Why does `.git/index` change when I haven't done anything to my repository?
The index file shouldn't just randomly change. That is the staging tree, a buffer between the repository of commits and the working tree. For efficiency, it also stores some metadata about the working tree (the checked out files which you can modify), which would allow faster status
or diff
results. To see what kind of such information is stored, try to execute git ls-files --debug
. This should print, for each file and directory, something like:
path/to/file
ctime: 1332898839:873326227
mtime: 1332898839:873326227
dev: 2052 ino: 4356685
uid: 1000 gid: 100
size: 3065 flags: 6c
So, if a file changes in any way on the disk, not as its content, but internal stuff like which inode it's using, it will trigger an update to the index
file next time the index is used.
git branch
doesn't update the index, since it only checks the .git/HEAD
file and the .git/refs/heads
and .git/packed-refs
files, it doesn't care about the index or the working tree. git diff
and git status
, on the other hand, do work with the index.
I did an experiment: I copied the current index
file, I created a new version of a file making sure that a new inode will be assigned to it (copy, remove original, rename the copy back to the original name), executed git status
, and then compared the new index file with the original copy. Two things changed: a line that contained the affected file in it, and the changes were in the bytes right before the filename, and a few bytes right at the end of the index file, probably a timestamp for the last index computation. The overall size of the file remained the same.
Back to your problem, if you're not executing any command that touches the index yourself, then maybe you have another tool that does that for you: an IDE plugin or a file browser extension that knows about git repositories, and which checks the status of git repositories. Or, there's another process that changes the way files are stored on disk, like a disk-defrag utility.
I've come across this issue as well, and I believe it's the interaction between unison and git that is causing the problem. When unison synchronizes the two directories, it doesn't synchronize the ctimes. That means that in one copy of the git repository, say copy 2, the file ctimes don't match the times stored in .git/index. That means that .git/index in copy 2 will get updated the next time you run a git command that stats files. When unison runs, .git/index is copied to copy 1, but then its contents don't match the ctimes there. So the next time a git command is run there, the index is updated. Then unison copies it to copy 2, etc.
I haven't found a reasonable workaround for this. Setting core.trustctime=false doesn't help.
To the extent that .git/index is a cache, it should be omitted from synchronization by unison. But I believe that .git/index is also used to stage files, and one might start that process on one machine and finish it on another, which would require .git/index to be synchronized.
(I know some people think it's odd to synchronize git repos with unison, but the point of unison is that you can switch between working on two different machines and continue exactly where you left off. It's an amazing tool!)