当我没有对我的存储库做任何事情时,为什么`.git / index`会改变?

时间:2012-08-25 22:46:01

标签: git unison

使用最新的Debian版本的git(我使用1.7.2.5),我注意到.git/index文件可能会神秘地改变,而我没有执行任何我认为应该执行的操作更改存储库。 (我的shell偶尔会运行git branch,因此它可以显示已检出的分支,但不应该更改任何内容。)更改会生成.git/index文件,其长度与原始文件相同,但包含不同的位。 导致此更改的原因是什么?如何阻止它?

(这种变化很不方便,因为它会使Unison文件同步器变得混乱。)

6 个答案:

答案 0 :(得分:3)

索引文件不应随意更改。这是临时树,提交存储库和工作树之间的缓冲区。为了提高效率,它还会存储有关工作树的一些元数据(您可以修改的已签出文件),这样可以获得更快的statusdiff结果。要查看存储了哪种此类信息,请尝试执行git ls-files --debug。这应该为每个文件和目录打印如下内容:

path/to/file
  ctime: 1332898839:873326227
  mtime: 1332898839:873326227
  dev: 2052     ino: 4356685
  uid: 1000     gid: 100
  size: 3065    flags: 6c

因此,如果文件在磁盘上以任何方式发生变化,而不是其内容,而是内部的东西,如它正在使用的inode,它将在下次使用索引时触发对index文件的更新。

git branch不更新索引,因为它只检查.git/HEAD文件以及.git/refs/heads.git/packed-refs文件,它不关心索引或工作树。另一方面,git diffgit status可以使用索引。

我做了一个实验:我复制了当前的index文件,我创建了一个新版本的文件,确保将新的inode分配给它(复制,删除原始文件,将副本重命名为原始名称),执行git status,然后将新索引文件与原始副本进行比较。改变了两件事:一行包含受影响的文件,更改在文件名之前的字节中,以及索引文件末尾的几个字节,可能是最后一次索引计算的时间戳。文件的整体大小保持不变。

回到你的问题,如果你没有自己执行任何触及索引的命令,那么也许你有另一个工具为你做这个:IDE插件或知道git存储库的文件浏览器扩展,以及检查git存储库的状态。或者,还有另一个进程可以更改文件存储在磁盘上的方式,例如磁盘碎片整理实用程序。

答案 1 :(得分:3)

我也遇到过这个问题,我相信这是引起问题的unison和git之间的相互作用。当unison同步两个目录时,它不会同步ctimes。这意味着在git存储库的一个副本中,比如副本2,文件ctimes与存储在.git / index中的时间不匹配。这意味着下次运行stats文件的git命令时,副本2中的.git / index将会更新。当unison运行时,.git / index被复制到副本1,但是其内容与那里的ctimes不匹配。因此,下次在那里运行git命令时,索引会更新。然后unison将它复制到副本2等。

我还没有找到合理的解决方法。设置core.trustctime = false没有帮助。

如果.git / index是一个缓存,则应该通过unison同步省略它。但我相信.git / index也用于暂存文件,有人可能在一台机器上启动该进程并在另一台机器上完成,这需要同步.git / index。

(我知道有些人认为将git repos与unison同步是很奇怪的,但是一致的意思是你可以在两台不同的机器上切换并继续你离开的地方。这是一个了不起的工具!)

答案 2 :(得分:0)

这可能不是这个问题的作者的解决方案,但在我的情况下,etckeeper的每日自动提交功能是罪魁祸首。

答案 3 :(得分:0)

我在一台设备上看到同样的问题,我在两台机器之间使用Unison同步我的主目录(包含3 git repos),以及一个cd进入每个repo目录并每天运行'git status'的cron作业(如果没有签入更改,则给我发电子邮件)。我的测试表明它是由事实引起的.git / index存储机器特定的数据,如文件的inode数量[1]。

要对此进行测试,请在2台计算机上使用已同步且相同的存储库。将.git / index从一台机器复制到另一台机器,例如 scp -p machineB:/home/me/myrepo/.git/index /home/me/myrepo/.git/index

现在比较两个文件,您应该看到它们是相同的: sha1sum /home/me/myrepo/.git/index ssh machineB "sha1sum /home/me/myrepo/.git/index"

现在运行:git status

现在再次比较2个文件,你会发现它们已经改变了: sha1sum /home/me/myrepo/.git/index ssh machineB "sha1sum /home/me/myrepo/.git/index"

我没有看到这方面的解决方案,因为如果没有运行更新索引的git status等命令就无法使用git。

[1] https://github.com/git/git/blob/867b1c1bf68363bcfd17667d6d4b9031fa6a1300/Documentation/technical/index-format.txt#L38

答案 4 :(得分:0)

罪魁祸首证明是Emacs VC模式: https://emacs.stackexchange.com/questions/38418/could-magit-be-writing-git-index-without-my-intervention

为了使这个文本成为答案,而不是评论,我必须说更多。所以正确的答案在这里重现:

  

Emacs VC使用计时器定期刷新一些   信息和调用git命令执行此操作以及其中一些命令   触摸索引。

     

提供VC是导致此问题的原因,然后从中删除Git   vc-handled-backends可能会修复它。

答案 5 :(得分:0)

在Emacs中禁用VC并不能真正解决此问题。它只会阻止E​​macs单独运行git status,但是手动运行它仍会修改文件.git/index并导致与Unison的虚假修改/冲突。

git邮件列表建议一种对我有效的解决方法[1]:

  • 在Unison(times = true)中启用mtime同步
  • git config core.trustctime false
  • git config core.checkstat minimal

(当然,git-config选项可以全局设置。)

使用这些设置,git现在仅在检查文件是否已被修改并且仅由Unison同步时才查看mtime的整数部分和文件大小。

[1] https://marc.info/?l=git&m=157937653401027