6

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

(这个改变很不方便,因为它把Unison文件同步器弄乱了。)

4

6 回答 6

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 diff并且git status,另一方面,使用索引。

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

回到您的问题,如果您自己没有执行任何涉及索引的命令,那么也许您有另一个工具可以为您执行此操作:IDE 插件或了解 git 存储库并检查状态的文件浏览器扩展的 git 存储库。或者,还有另一个过程可以改变文件在磁盘上的存储方式,例如磁盘碎片整理实用程序。

于 2012-08-26T07:15:52.413 回答
3

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

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

就 .git/index 是一个缓存而言,它应该从同步中省略。但我相信 .git/index 也用于暂存文件,并且可能在一台机器上启动该过程并在另一台机器上完成它,这需要 .git/index 同步。

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

于 2014-02-13T16:04:57.153 回答
0

对于这个问题的作者来说,这可能不是解决方案,但就我而言,etckeeper 的每日自动提交功能是罪魁祸首。

于 2014-04-26T19:48:36.600 回答
0

我在设置中看到了同样的问题,我让 Unison 在两台机器之间同步我的主目录(包含 3 个 git repos),以及一个 cd 到每个 repo 目录并每天运行“git status”的 cron 作业(并通过电子邮件发送给我如果未签入更改)。我的测试表明这是由于 .git/index 存储了特定于机器的数据,例如文件的 inode 数量[1]。

要对此进行测试,请使用已经在两台机器上同步且相同的存储库。将 .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

现在再次比较这两个文件,你会发现它们已经改变了: 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

于 2017-02-01T10:39:00.890 回答
0

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

为了使这篇文章成为答案,而不是评论,我不得不说更多。所以这里转载了正确的答案:

Emacs VC 使用计时器来定期刷新一些信息并调用git命令来这样做,其中一些会触及索引。

如果 VC 是导致此问题的原因,则删除Gitfrom vc-handled-backends可能会解决此问题。

于 2018-03-25T14:58:39.573 回答
0

在 Emacs 中禁用 VC 并不能真正解决这个问题。它只会阻止 Emacs 自己运行git status,但手动运行它仍然会修改文件.git/index并导致与 Unison 的虚假修改/冲突。

git 邮件列表建议了一个适合我的解决方法 [1]:

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

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

通过这些设置,git 现在在检查文件是否被修改时只查看 mtime 的组成部分和文件大小,并且两者都由 Unison 同步。

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

于 2020-01-18T22:15:42.720 回答