前些天有位小伙伴告诉我说 git 改了某个重要文件的换行符,导致文件的哈希变了,于是文件校验出现错误。之前一直没问题而最近才有问题是因为最近换了部署服务器,git 的换行符配置不一样。
其实,我们不应该让代码仓库如此容易受到外界环境的影响。所以本文会解释 git 的全局配置如何影响了 git 对换行符的处理,然后说说如何彻底解决这个问题。
关于换行符
- r = CR = Carriage-Return = 回车
- n = LF = Line-Feed = 换行
- rn = CRLF = Carriage-Return Line-Feed = 回车换行
Windows 下默认的文本换行符是 rn
,Linux 下默认的换行符是 n
,Mac 下默认的换行符是 r
。因为这些差异,如果某部分文本文件会跨操作系统处理,那么换行符的处理就必须考虑了。git 允许开发者设置如何处理换行符在跨平台上的处理方式,不过不合适的设置可能带来文件发生不期望的修改。
问题
问题本身在本文一开始已经说得比较清楚了,现在疏理一下:
- 有个文本文件,被 git 改了换行符,导致哈希变化,文件校验出现了错误;
- 部署服务器以前 git 全局配置和现在不同,所以以前没问题,现在出了问题。
解决
当时,林德熙 小伙伴是负责部署服务器配置的,看到出事了立刻想到去服务器把配置改“正确”。
然而我阻止了。因为现在因为换服务器出问题,将来也会因为换服务器出问题,更普遍的,换任何环境都可能出问题。所以这问题应该从仓库着手,避免此文件被修改换行符。
于是我和小伙伴结对打开了 .gitattribute 文件,在末尾加了一行:
1 2 3 | *.bmp binary *.jpg binary *.inf binary |
---|
这样,*.inf 文件会被 git 视为二进制文件,也就不会处理换行符了。
当然,因为项目很小,所以直接改了位于项目根目录的 .gitattribute 文件。如果项目比较大,那么建议考虑在那个 .inf 文件所在的文件夹新建一个 .gitignore 文件,避免全局的设置对可能不需要生效的文件也起了作用。
原因
git 有个全局配置,在 %USERPROFILE%.gitconfig
文件里面,可以指定如何处理文本文件的换行符:
1 2 | [core] autocrlf = true |
---|
有三个可选值:
- true
- false
- input
在 Windows 系统上:
true
表示在推送时转成n
,在拉取时转成rn
。这样的设置让 Windows 的开发者能兼容很多的开发工具(比如早期的记事本,新的已经支持rn
了),不至于遇到很多换行符问题。false
表示在推送时和拉取时都原样保留换行符。这样的设置在所有程序员都在同一个平台开发时很有用,git 完全不处理换行符,全部改由开发者自行解决。input
表示在推送时转成n
,在拉取时原样保留换行符。注意到,这样的设置会让仓库里所有的换行符都变成n
不再有什么时候有rn
了,所以对 Windows 平台的开发者并不友好。
以前的服务器全局配置没有问题,是因为服务器配置为 true
,于是拉下来时一定都是 rn
哈希正确。而现在全局配置是 false
,于是会原样把 git 仓库里的拉下来,哈希错误。
是的,你没看错!远程 git 仓库里的是错的!这是因为有小伙伴使用了 true
或者 input
的配置,导致推送时统一把换行符改成了 rn
。
本文会经常更新,请阅读原文: https://blog.walterlv.com/post/fix-git-unexpected-line-end-changing.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 吕毅 (包含链接: https://blog.walterlv.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 ([email protected]) 。