git status之后,git diff-files的输出会发生变化。

10
我有一个脚本update.py,用于下载我在git存储库中跟踪的文件的新版本:
$ python update.py
Doing work...
Done
$ git status
On branch my-branch
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   foo.txt
    modified:   bar.txt
    modified:   baz.txt

no changes added to commit (use "git add" and/or "git commit -a")

有时,下载的文件与HEAD中已有的文件完全相同,因此下载后工作目录将变得干净:
$ python update.py
Doing work...
Done
$ git status
On branch my-branch
nothing to commit, working directory clean

然而,我发现当文件被替换时,即使它们的内容相同,git diff-files 似乎会变得混乱:
$ python update.py
Doing work...
Done
$ git diff-files
:100644 100644 ffa91f655007c56f209cf15fee13c55991a76e18 0000000000000000000000000000000000000000 M  foo.txt
:100644 100644 dc05558729c3c94a088aa63da3bbd8f1213b8cf3 0000000000000000000000000000000000000000 M  bar.txt
:100644 100644 002cc3f53dc64b89b1b91adbb6fe61035ba9e832 0000000000000000000000000000000000000000 M  baz.txt
$ git status
On branch my-branch
nothing to commit, working directory clean
$ git diff-files
$

在上面的代码片段中:
  1. 我运行 update.py,用从其他地方下载的相同副本替换了 foo.txt、bar.txt 和 baz.txt 文件。
  2. git diff-files 根据 git diff man page 上描述的原始输出格式错误地报告这三个文件已在工作树中原地编辑。
  3. git status 正确地报告没有任何更改。
  4. 在运行 git status 后运行 git diff-files,现在也报告没有任何更改。
在运行 update.py 后,git diff-files 将继续错误地报告更改,直到我运行 git status,此后它再次正常工作。
这是怎么回事?为什么 git diff-files 在没有更改时报告更改?
如果你好奇为什么这让我感到困扰,下面是更多背景信息:
我有另一个脚本update_and_commit_if_needed.py,它执行以下操作:
1. 运行update.py。 2. 如果git diff-files返回零,则工作树干净,update.py未更改任何内容。退出。 3. 否则,工作树是脏的。提交更改。
我在update_and_commit_if_needed.py中看到了奇怪的错误:我会到达第三步,但然后git commit会抱怨没有要提交的内容,工作目录干净。在追踪此错误时,我发现了git diff-files的这种奇怪行为。
我正在使用OS X 10.11.4(15E65)上的git版本2.5.0。

编辑 1:我找到了一个简单的方法来重现这种行为:

$ git diff-files
$ git status
On branch my-branch
nothing to commit, working directory clean
$ cp foo.txt ~
$ mv ~/foo.txt .
$ git diff-files
:100755 100755 20084b5d6da359748f62c259c24f2b9cc2359780 0000000000000000000000000000000000000000 M  foo.txt
$ git status
On branch my-branch
nothing to commit, working directory clean
$ git diff-files
$

编辑2: 根据评论的建议,我尝试了反转core.trustctimecore.ignoreStat的默认设置。在这种情况下,这似乎并没有改变git的行为。


显然这是某种错误。具体是什么类型的错误...嗯,那部分清楚。 :-) 由于索引存储了stat结果以供缓存使用,您的操作系统可能是相关的。还请参考git config中的core.trustctimecore.ignoreStat设置。 - torek
哇,伙计!你刚刚调查了 gitk 的一个长期存在的问题,这个问题实际上是一个 bug:有时它会显示有更改但无法展示,而在按下 F5(重新加载)后,更改标志就消失了。我相信快速检查涉及某种不带实际内容比较的 stat,但这些只是猜测,不是真正的调查。 - user3159253
1个回答

13

git diff-index实际上并不检查工作树中文件的内容,而是使用文件的状态信息与索引进行比较。事实上,diff-index手册指出:

像其他此类命令一样,git diff-index实际上根本不查看文件的内容。所以也许kernel/sched.c实际上没有改变,只是你碰到了它。无论哪种情况,这都是一个需要注意的问题,并且需要运行git update-index使索引与之同步。

正如提示所示,可以在运行diff-files之前通过运行git update-index --refresh来更新索引的状态条目。update-index手册进一步解释了此操作:

--refresh不会计算新的sha1文件或将索引更新为模式/内容更改。但它确实可以“重新匹配”文件的状态信息与索引,因此您可以刷新未更改但状态条目已过期的文件的索引。

例如,在进行git read-tree之后,您希望执行此操作,以将状态索引详细信息与正确的文件链接起来。

在运行diff-files之前运行update-index --refresh可以消除我所描述的症状,从而解决问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接