{"thread":{"id":"44944","subject":"interaction between git-diff-index and git-apply","startedAt":"2017-01-22T20:09:59Z","lastAt":"2017-01-22T22:06:56Z","messageCount":2,"participants":["Ariel Davis","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"309945","messageId":"C45218A3-8A81-4307-AADB-FBA4F51EAC51@icloud.com","threadId":"44944","inReplyTo":null,"subject":"interaction between git-diff-index and git-apply","fromName":"Ariel Davis","fromEmail":"ariel.z.davis@icloud.com","sentAt":"2017-01-22T19:09:51Z","receivedAt":"2017-01-22T20:09:59Z","isPatch":false,"sender":{"key":"ariel.z.davis@icloud.com","avatar":null},"body":"Hello,\n\nI have noticed an interesting interaction between git-diff-index and git-apply.\nEssentially, it seems that if we start with a clean working tree, then\ngit-apply a patch, then git-apply the reverse of that patch, git-diff-index\nstill thinks files are modified. But then, if we git-status, git-diff-index\nseems to \"realize\" the files are actually not modified.\n\nBelow are steps to reproduce, as well as information about my machine, which I\ndiscovered this behavior on.\n\nReproduction instructions:\n\n$ mkdir -p test/repo\n$ cd test/repo\n$ git init -q\n$ echo 1 > file\n$ git add file\n$ git commit -qm 1\n$ echo 2 >> file\n$ git add file\n$ git commit -qm 2\n$ git diff @~ > ../patch\n$ git apply --reverse ../patch\n$ git diff-index --name-only @\nfile\n$ git apply ../patch\n$ git diff-index --name-only @\nfile\n$ git status\nOn branch master\nnothing to commit, working tree clean\n$ git diff-index --name-only @\n$ echo hmm\nhmm\n\nSystem information:\n\n$ uname -a\nDarwin azdavis-mbp 16.3.0 Darwin Kernel Version 16.3.0: Thu Nov 17 20:23:58 PST\n2016; root:xnu-3789.31.2~1/RELEASE_X86_64 x86_64 i386 MacBookPro12,1 Darwin\n$ sw_vers\nProductName:    Mac OS X\nProductVersion: 10.12.2\nBuildVersion:   16C67\n$ git --version\ngit version 2.11.0\n\nThank you for your time.\n\nAriel Davis\n\n"},{"id":"309948","messageId":"xmqqinp6vjey.fsf@gitster.mtv.corp.google.com","threadId":"44944","inReplyTo":"C45218A3-8A81-4307-AADB-FBA4F51EAC51@icloud.com","subject":"Re: interaction between git-diff-index and git-apply","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-01-22T22:06:45Z","receivedAt":"2017-01-22T22:06:56Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ariel Davis <ariel.z.davis@icloud.com> writes:\n\n> I have noticed an interesting interaction between git-diff-index and git-apply.\n> Essentially, it seems that if we start with a clean working tree, then\n> git-apply a patch, then git-apply the reverse of that patch, git-diff-index\n> still thinks files are modified. But then, if we git-status, git-diff-index\n> seems to \"realize\" the files are actually not modified.\n\nThat is perfectly normal and you are making it too complex.  You do\nnot need to involve \"git apply\" at all.\n\n    $ git init\n    $ echo hello >file && git add file && git commit -m initial\n    $ git diff-index HEAD\n    $ echo hello >file\n    $ git diff-index HEAD\n    :100644 100644 ce013625030ba8dba906f756967f9e9ca394464a 0000000000000000000000000000000000000000 M\tfile\n\n    $ git update-index --refresh\n    $ git diff-index HEAD\n    $ exit\n\nA few things about Git that are involved in the above are:\n\n * There are plumbing commands that are geared more towards\n   scripting Git efficiently and there are end-user facing Porcelain\n   commands.\n\n * Git uses cached \"(l)stat\" information to avoid having to inspect\n   the contents of the file all the time.  The idea is that Git\n   remembers certain attributes (like size and last modified time)\n   of a file when the contents of the file and the blob object in\n   the index are the same (e.g. when you did \"git add file\" in the\n   above sequence), and it can tell a file was edited/modified if\n   these attributes are different from those recorded in the index\n   without comparing the contents of the file with the blob.\n\n * The plumbing commands trust the cached \"(l)stat\" information for\n   efficiency and whoever uses the plumbing commands are responsible\n   for culling the false positives when cached \"(l)stat\" information\n   is used to see which paths are modified.  They (typically these\n   are scripted commands) do so with \"update-index --refresh\".\n\n * The Porcelain commands sacrifice the efficiency and internally do\n   an equivalent of \"update-index --refresh\" at the beginning to\n   hide the false positive.\n\nAfter your reverse application of the patch with \"git apply\" (or the\nsecond \"echo hello\" into the file in the above example), the\ncontents of the file is equivalent to what is in the index, but the\nlast modified timestamp (among others) is different because you\nwrote into the file.  If you do not do \"update-index --refresh\"\nbefore running \"diff-index\" again, \"diff-index\" will notice and\nreport the fact that you touched that file.  If you run \"git status\",\n\"git diff\", etc., they internally do \"update-index --refresh\" and\nthen after that until you touch the file on the filesystem, the\ncached \"(l)stat\" information will match and you will stop seeing the\nfalse positive.\n"}]}