为什么在git diff或git status之后git diff-index HEAD结果会改变被触摸的文件?

Jan*_*ani 14 git

如果我touch在git repo中跟踪文件并运行git diff-index HEAD,它将打印输出并M指示文件已被修改.例如,

$ touch foo
$ git diff-index HEAD
:100644 100644 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 0000000000000000000000000000000000000000 M  foo
Run Code Online (Sandbox Code Playgroud)

我不确定这是否有意义,但这不是问题.问题是,如果我运行git diff HEAD或为什么输出会改变(没有差异)git status

$ touch foo
$ git diff-index HEAD
:100644 100644 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 0000000000000000000000000000000000000000 M  foo
$ git diff                  # no output
$ git diff-index HEAD       # no output
Run Code Online (Sandbox Code Playgroud)

我希望结果,无论它是什么,在不应该改变任何东西的命令之间保持不变.

pok*_*oke 12

我们先来看一下输出的含义:

:100644 100644 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 0000000000000000000000000000000000000000 M  foo
Run Code Online (Sandbox Code Playgroud)

手册从左到右说明如下:

  1. 一个冒号.
  2. "src"模式; 如果创建或未合并,则为000000.
  3. 空间.
  4. "dst"模式; 如果删除或未合并,则为000000.
  5. 空间.
  6. sha1为"src"; 0 {40}如果创建或未合并.
  7. 空间.
  8. sha1为"dst"; 0 {40}如果创建,未合并或"查看工作树".
  9. 空间.
  10. 状态,后跟可选的"分数"编号.
  11. 使用-z选项时的制表符或NUL.
  12. "src"的路径
  13. 使用-z选项时的制表符或NUL; 仅适用于C或R.
  14. "dst"的路径; 仅适用于C或R.
  15. 使用-z选项时的LF或NUL,以终止记录.

有趣的是第8点:

sha1为"dst"; 0 {40}如果创建,未合并或"查看工作树".

因此,在您的情况下,您将获得40个零,因此这意味着"创建","未合并"或"查看工作树".由于您只触摸了文件,并且已经跟踪过,因此您可以删除前两个选项.这让我们"看工作树".

如果你这样做,使用git diff(将尝试为所有更改生成实际内容差异,并因此实际查看文件内容),然后Git显然发现没有任何更改,所以后续调用不再说什么关于它.

这个观察结果让我相信默认情况下git diff-index只会快速查看文件,而不会实际比较任何内容.由于您已经修改了文件日期,因此Git认为它"可能已更改",并且需要更详细的外观才能正确识别它.

如果你运行git diff-index一个选项,要求它更彻底地查看文件,那么它也不会发现任何变化,例如当使用-p选项生成补丁时(这就是那种git diff情况).

因此,如果文件修改日期发生更改,则可能只是进行性能优化以假设文件可以更改,而不会对其进行实际声明; 相反,它只是留下了"稍后看"这个标记.

  • `git update-index --refresh`将更新索引信息,以便随后的`git diff-index`按预期工作. (7认同)
  • 我确实建议使用“git update-index -q --really-refresh”而不是“git update-index --refresh”,因为最后一个可能不会刷新索引。有关详细信息,请参阅[文档](https://git-scm.com/docs/git-update-index#Documentation/git-update-index.txt---really-refresh)。 (3认同)
  • 有趣的是,“git diff-index -p HEAD”不会更改后续“git diff-index HEAD”的输出。 (2认同)