规范化后的Git行结尾

规范化后的Git行结尾,git,Git,这个行尾问题快把我逼疯了 背景:从历史上看,我使用core.autocrlf设置,但我发现不同的回购行为存在问题(我在Windows上工作,有些回购需要LF结尾,有些回购需要CRLF结尾)。因此,我正试图摆脱这种情况,在每个存储库中使用.gittributes(我希望Git闭嘴,让我来管理行尾!)。因此,我现在有了core.autocrlf=false和一个.gittributes,对于我正在处理的Visual Studio项目,它看起来像这样: # Don't do any end of li

这个行尾问题快把我逼疯了

背景:从历史上看,我使用core.autocrlf设置,但我发现不同的回购行为存在问题(我在Windows上工作,有些回购需要LF结尾,有些回购需要CRLF结尾)。因此,我正试图摆脱这种情况,在每个存储库中使用.gittributes(我希望Git闭嘴,让我来管理行尾!)。因此,我现在有了
core.autocrlf=false
和一个
.gittributes
,对于我正在处理的Visual Studio项目,它看起来像这样:

# Don't do any end of line normalization.
* -text

# Always treat these files as binary. Not strictly necessary, but can't hurt.
*.png binary
*.gif binary
*.jpg binary
*.jpeg binary
*.dll binary
*.doc binary
*.docx binary
*.xls binary
*.xlsx binary
*.pdf binary
我已使用unix2dos将repo中的所有文件强制转换为CRLF结尾,并确认它们在工作目录中具有正确的行结尾,并将它们全部签入。是的,我听从了这里的建议

这几乎是完美的

问题在于,每当我更改文件时,git都会报告更改的行上有行尾差异,例如,如果原始行是

string s;
改变的路线是

string sucks;
git diff将更改显示为

string sucks;^M
看起来Git认为回购协议中的文件仍然有LF结尾(因为它们在过去是标准化的?)。^M会引起大量的视觉噪音,我不确定这是否是其他症状。我不明白为什么Git报告了一个差异,因为我在上一次提交中签入了所有以CRLF结尾的文件,事实上,在这次提交之前


那么,为什么我会有这些“虚假”的差异,我如何才能消除它们呢?

呜呼!我想我找到了答案。本网站建议您这样做

git config [--global] core.whitespace cr-at-eol
这确实让“git diff”闭嘴了。当然,最好的解决方案是在.gittributes文件中执行等效操作,使其与repo保持一致,并且不依赖于用户的设置

.gittributes的最终设置

我花了一些时间在Linux和Windows上试验repo,并用Unix和Windows行结尾的文件进行试验,我相信如果您只给git repo一个带有两行的.gittributes文件,那么整个行尾问题都可以解决:

* -text
* whitespace=cr-at-eol
第一行停止git执行任何行尾规范化,第二行停止git diff在行尾突出显示CR字符。我能找到的唯一缺点是,如果将文件从DOS转换到Unix,或者从Unix转换到DOS,则会有一点奇怪:git diff会将文件显示为已更改,但它不会突出显示更改的原因,而只是将每一行显示为已删除,然后添加。我可以接受,因为这是一个非常罕见的手术(或者应该是)

以上将行结束管理的负担放在提交者身上。这是应该的,我不相信我的风投工具会变魔术,成千上万的网页和关于git处理行尾的问题证明他们在这里做出了错误的决定

变体

如果将第一行替换为

* eol=lf
然后,文件在工作目录中将始终具有LF结尾。这对于必须跨Unix和Windows工作的存储库(如“.dotfiles”)来说非常方便。同样地,
eol=crlf
将强制使用Windows样式的行尾警告这也将转换二进制文件中的CRLF!请参阅我的评论,以便您还需要使用文件路径或告诉git哪些文件是二进制文件

方便的别名

以下两个git别名提供了一种快速的方法,可以将repo中的所有文本文件从DOS转换到Unix,或者从DOS转换到Unix。它们明确排除了对.git文件夹的任何处理。我无法从命令行中找到定义它们的方法,因此请编辑您的.gitconfig并在
[alias]
部分中添加以下两行:

godos = !find . -path ./.git -prune -o -type f -exec unix2dos {} "\\;"
gounix = !find . -path ./.git -prune -o -type f -exec dos2unix {} "\\;"  
然后,您可以在repo的根目录中执行
git godos
git gounix
,以将所有文本文件的结尾设置为一个或另一个n.b.以上仅适用于当前分支中的文件。我还没有找到转换每个分支中每个文件的方法

参考资料

gitattributes手册页:

gitconfig手册页(在下线讨论cr):


查找的Git别名:

您使用的编辑器是什么?您确定它没有插入不同的行尾吗?