取消

git 乱改你的换行符?一句话设置让 git 不再碰你某个文件的换行符

前些天有位小伙伴告诉我说 git 改了某个重要文件的换行符,导致文件的哈希变了,于是文件校验出现错误。之前一直没问题而最近才有问题是因为最近换了部署服务器,git 的换行符配置不一样。

其实,我们不应该让代码仓库如此容易受到外界环境的影响。所以本文会解释 git 的全局配置如何影响了 git 对换行符的处理,然后说说如何彻底解决这个问题。


关于换行符

  • \r = CR = Carriage-Return = 回车
  • \n = LF = Line-Feed = 换行
  • \r\n = CRLF = Carriage-Return Line-Feed = 回车换行

Windows 下默认的文本换行符是 \r\n,Linux 下默认的换行符是 \n,Mac 下默认的换行符是 \r。因为这些差异,如果某部分文本文件会跨操作系统处理,那么换行符的处理就必须考虑了。git 允许开发者设置如何处理换行符在跨平台上的处理方式,不过不合适的设置可能带来文件发生不期望的修改。

问题

问题本身在本文一开始已经说得比较清楚了,现在疏理一下:

  1. 有个文本文件,被 git 改了换行符,导致哈希变化,文件校验出现了错误;
  2. 部署服务器以前 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,在拉取时转成 \r\n。这样的设置让 Windows 的开发者能兼容很多的开发工具(比如早期的记事本,新的已经支持 \r\n 了),不至于遇到很多换行符问题。
  • false 表示在推送时和拉取时都原样保留换行符。这样的设置在所有程序员都在同一个平台开发时很有用,git 完全不处理换行符,全部改由开发者自行解决。
  • input 表示在推送时转成 \n,在拉取时原样保留换行符。注意到,这样的设置会让仓库里所有的换行符都变成 \n 不再有什么时候有 \r\n 了,所以对 Windows 平台的开发者并不友好。

以前的服务器全局配置没有问题,是因为服务器配置为 true,于是拉下来时一定都是 \r\n 哈希正确。而现在全局配置是 false,于是会原样把 git 仓库里的拉下来,哈希错误。

是的,你没看错!远程 git 仓库里的是错的!这是因为有小伙伴使用了 true 或者 input 的配置,导致推送时统一把换行符改成了 \r\n

本文会经常更新,请阅读原文: https://blog.walterlv.com/post/fix-git-unexpected-line-end-changing.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

知识共享许可协议

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 吕毅 (包含链接: https://blog.walterlv.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 ([email protected])

登录 GitHub 账号进行评论