原因
这个问题是由于在 .gitattributes
中的 * text=auto
设置导致的。你可以将其删除并快乐地生活下去,但是你的存储库中可能有具有非默认行编码的文件,甚至有多种不同的行结尾编码(即LF和CRLF,甚至CR!)。
为什么会发生这种情况(详细信息)
当 git 按原样检出文件时,在添加/提交时它将修改行结尾。实际上,文件还没有被修改,但是由于存储库的设置,git 已经将其视为已修改。
有些时候 git 的工作方式有点奇怪。例如,git reset --hard
有时可以正常工作,有时不能,可能取决于你的设置。或者,如果你进入你的 .gitattributes
并将扩展名标记为二进制,那么这个修改过的文件就会神奇地消失:
*.ext binary
该效果甚至在您删除二进制标记后仍然存在,甚至在您再次执行
git reset --hard
之后也是如此,因此这可能是一个git bug或git缓存问题。对该文件执行
git -rm
,然后执行
git reset --hard
,可以恢复已修改的标记。
如何修复:
我们假设您想保留
* text=auto
设置,以便现在和将来git警告您各种文本文件中的不一致行结束符。如果是这样,请选择以下方法:
选项0:暂时欺骗git标记文件为已修改
1. 编辑
.gitattributes
,注释掉
* text=auto
,保存
2.
git status
(需要执行此步骤才能使git记录.gitattributes中的更改)
3.
git reset --hard
(这将恢复
* text=auto
并清除您的工作目录中的任何更改,如果有的话)。
这通常有效(除了可能最顽固的情况)。它也会推迟问题,因为行尾仍未被规范化,最有可能在以后某个时刻出现。
当您必须回滚一个尚未规范化的先前提交(例如在 rebase 或其他 git 工作期间),或者您知道现有的后续提交将规范化行尾但 git 抱怨修改的文件现在阻止您继续进行时,此选项非常有用。因此,当您需要 Git 保持安静并忽略真正未针对特定上下文修改的修改文件时,请使用此方法。
选项1:易于“最终用户”解决方案。
如果你只有几个文件,确保你的
.gitattributes
和
core.autocrlf
设置为你喜欢的方式,然后只需进行
git add/commit
即可,你就不会再看到这个问题了。这些文件将被转换为你想要的行结尾并存储在你的仓库中,正如你的配置所述。这个提交将被存储在你的仓库中,因为每一行都会改变它的行结尾,所以会被记录为“整个文件已更改”。对于一个较大或开源的仓库中的几个文件来说,这是可以接受的。确保将该提交合并或 cherry-pick 到你的所有分支中,因为在拥有这些文件的所有分支中,这个问题都会存在,直到你解决它。顺便说一下,在这里你可以使用选项 0。也就是说,如果你切换到一个未修复的分支,并且它抱怨,运行选项 0,然后进行修复(合并或 cherry-pick)。
重要提示:如果您选择选项1,请确保正确转换已修改的文件。 Git 可能无法像您期望的那样为您执行此操作,因此在提交之前自己进行转换,即使用此方法:
将 Mac 格式的换行符转换为 Windows 格式。Git 可能会混淆的原因是我见过一些文件中同时包含 CR、LF 和 CRLF 行结束格式。在提交之前请自己将其转换为所需的格式。
选项2:高级机制“git 历史重写”修复:
如果您拥有更私密的存储库并且不怕重写历史,请参考以下内容:
由于 Mac 换行符,Git 将整个文件视为一行。这将重写整个存储库,并消除所有树、分支上的任何行结束问题!请确保包括所有可能引起问题的文本文件扩展名,否则它们可能会在以后出现。
在我的情况下,我选择了方案2,因为我需要处理许多分支中的很多文件结尾问题。但是后来我发现了一些意外的扩展名没有被规范化,所以我只好使用了方案1,因为我只错过了5-6个文件。
.gitattribute
。它做了一些奇怪的事情。它可能已经在以后的版本中修复了,但是1.7.11.msysgit.0是当时最新的可用版本。 - pepr