为什么Git认为未修改的文件的每一行都已更改

6

我认为这不是行结束差异问题 - 即使设置为识别行结束和空格差异,p4merge 也认为文件没有任何更改。

我的问题是有时会出现以下情况:

  • 起初,git status 没有显示未提交的更改。
  • 然后我切换到另一个分支
  • 现在,git status 列出一些文件已更改。
  • 对于任何其中的“更改文件”,git diff 显示该文件的每一行都已更改。更改版本与原始版本相同。

为什么会发生这种情况?为什么 git 认为文件已经更改了,当它们看起来没有做出那样的更改?为什么仅仅检出另一个分支就会导致这种情况发生?

我的第一个想法是行结束符,但我不知道为什么 p4merge 不会检测到这些。第二个想法是文件模式更改。我不知道如何找出是否是这种情况。git config --list 显示 core.filemode 设置为 false。git config --global --listgit config --system --list 没有显示任何关于 core.filemode 的设置(我在这里说明,因为我不确定不同的配置级别是如何覆盖彼此的)。core.autocrlf 设置为 true。

多个开发人员提交到同一个仓库,我从中拉取更改,他们都在使用 Windows 计算机。我猜测某个人在某个位置上有一些设置导致了这种情况,但我不知道是我本地还是其他人,或者它可能是哪个设置。

列出的更改文件似乎不是随机的 - 如果我删除我的本地仓库,再次从远程克隆(默认为检出主分支),然后再次检出相同的分支,git status 每次都会列出完全相同的更改文件。这些文件有时是最近编辑的内容,有时是多年未被触及的文件。它们不仅是二进制文件(已知 core.autocrlf=true 有时会损坏它们),而且也是文本文件。

执行命令 git rm --cached -r .,然后是 git reset --hard 可以摆脱这些更改,但它发生得太频繁,让人感到烦恼。我也很好奇是什么原因导致了这种情况。

同一个仓库还引起了行结束问题。我认为这是一个单独的问题,所以我可能最终会为它提出另一个问题,但我在这里简要提到它,以防它们有关联。检出另一个分支或从远程仓库拉取更改有时会导致文件看起来已更改,并且对这些文件的 git diff 仅输出: warning: LF will be replaced by CRLF in [file]. The file will have its original line endings in your working directory.

编辑:该仓库的 .gitattributes 文件中只有一行 * text=auto,没有其他内容。

git config --list的输出结果(省略了与颜色、编辑器文件路径、远程、差异工具、用户名和电子邮件等相关的设置):
core.symlinks=false
core.autocrlf=true3
pack.packsizelimit=2g
rebase.autosquash=true
merge.summary=true
core.repositoryformatversion=0
core.filemode=false
core.bare=false
core.logallrefupdates=true
core.symlinks=false (yes this is there twice, just noticed)
core.ignorecase=true
core.hidedotfiles=dotgitOnly

在你的克隆仓库中,git config core.autocrlf 返回什么?是否有任何带有 core.eol 指令的 .gitattributes 文件? - VonC
1
你和其他开发者一样在使用Windows吗?听起来好像^M或其他Windows特有的字符进入了文件中。 - Jeff Panici
可能是空格(制表符/空格)吗?尝试使用Git历史记录查看器,在显示差异视图时关闭空格。 - nwinkler
@VonC 我下次问题出现时可以尝试这样做。现在还没有发生,可能需要等待其他人再次推送引起问题。即使它可以解决问题,我仍然不认为我能将 core.autocrlf 设置为 false。我想了解为什么会发生这种情况。 - riksteri
1
这是因为 core.autocrlf 被设置为 true。我已经多年来一直主张将其设置为 false。https://dev59.com/unE95IYBdhLWcg3wY85l#2354278。 - VonC
显示剩余4条评论
1个回答

10

要显示这种细微的“看不见”的更改,请使用:

git diff --word-diff-regex=.

这将标记所有更改的字符,包括空格。

很可能会显示换行符的更改。如果您在Windows上工作并打开了core.autocrlf,Git可能会期望另一种换行符,并显示“错误”的换行符差异。

关闭core.autocrlf来告诉Git不关心换行符应该可以解决您的问题。


这表明每行中的^M字符已被删除。谢谢!尚未解决导致此问题的原因,但现在似乎更接近解决方案了。 - riksteri
你告诉 Git 始终使用本机(即 Windows)换行符存储文件。但是该文件包含 Unix 换行符。因此,Git 假定你已删除了"^M"字符,这正是两种换行符之间的区别。 - michas
这是由于一些开发人员设置了 core.autocrlf,而其他人则没有设置,导致意外的行结尾被提交到数据库吗?如果每个人始终将其设置为相同的设置,无论选定的设置是打开还是关闭,这仍然会成为问题吗?此外,我了解可以通过添加适当的设置到 .gitattributes 来解决此问题,以避免我们必须为每个开发人员设置适当的 core.autocrlf 设置。这是否正确? - riksteri
作为一条注释,我期望这个答案是正确的,并且在我看到修复程序正常运行后会立即标记它。我预计需要到下周才有机会应用和测试这个修复程序。 - riksteri
1
我遇到了类似的问题,我的结论是最好的方法是在.gitattributes中关闭git的任何“魔法”行尾标准化(以便它由存储库控制,而不依赖于各个开发人员可能在其.gitconfig中设置的任何设置)。请看我的回答:https://dev59.com/w4Hba4cB1Zd3GeqPOjw7 - Philip Daniels
显示剩余2条评论

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