If I touch
a file tracked in a git repo, and run git diff-index HEAD
, it will print output with M
indicating the file has been modified. For example,
$ touch foo
$ git diff-index HEAD
:100644 100644 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 0000000000000000000000000000000000000000 M foo
I am unsure if this makes sense or not, but that is not the question. The question is, why does the output change (to no diff) if I run git diff HEAD
or git status
?
$ touch foo
$ git diff-index HEAD
:100644 100644 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 0000000000000000000000000000000000000000 M foo
$ git diff # no output
$ git diff-index HEAD # no output
I would expect the result, whatever it is, to stay the same across commands that are not supposed to change anything.
Let’s first take a look at what the output means:
:100644 100644 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 0000000000000000000000000000000000000000 M foo
The manual says the following, from left to right:
- a colon.
- mode for "src"; 000000 if creation or unmerged.
- a space.
- mode for "dst"; 000000 if deletion or unmerged.
- a space.
- sha1 for "src"; 0{40} if creation or unmerged.
- a space.
- sha1 for "dst"; 0{40} if creation, unmerged or "look at work tree".
- a space.
- status, followed by optional "score" number.
- a tab or a NUL when -z option is used.
- path for "src"
- a tab or a NUL when -z option is used; only exists for C or R.
- path for "dst"; only exists for C or R.
- an LF or a NUL when -z option is used, to terminate the record.
Interesting is the 8th point:
sha1 for "dst"; 0{40} if creation, unmerged or "look at work tree".
So in your case, you get 40 zeros, so that either means “creation”, “unmerged” or “look at work tree”. Since you only touched the file, and it was already tracked, you can eliminate the first two options. That leaves us with “look at work tree”.
And if you do that, using git diff
(which will try to generate actual content diffs for all changes and as such actually look at the file contents), then Git apparently finds out that there was no change after all, so subsequent calls no longer say anything about it.
This observation makes me believe that by default git diff-index
will only take a quick look at the files, without actually comparing any content. Since you have modified the file date, Git considers it as “possibly changed” and requires a more detailed look to figure it out properly.
If you run git diff-index
with an option that requires it to take a more thorough look at the files, then it will also not find any changes, e.g. when using the -p
option to generate a patch (which is kind of what git diff
does).
So it’s likely just a performance optimization to assume a file could be changed if the file modification date was changed, without making actual claims about it; instead it just leaves a “look at this later” marker.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With