Git不同系统换行符问题


近期公司由于业务原因开始使用 mac 开发,但当上班摸鱼开发朋友的项目时却遇到了诡异的问题。

只改了两行代码

只改了两行代码,提交时却整个文件都发生了改动。

那还了得,刷代码提交量也没有这么刷的。于是着手寻找原因。

问题查找

不同操作系统的换行符是不同的,针对三个主流操作系统有如下三种换行符:

1
2
3
windows: CRLF                # \r\n (回车换行)
mac os && linux && Unix: LF # \n (换行)
早期 mac 系统: CR # \r (回车)

而 git 因为最早在 linux 上出现的,因此也推荐使用 LF 换行符。

而此先朋友的项目为 windows 上开发,且在 .editconfig 配置文件中设置了这么一行

1
end_of_line = crlf

这行代码将强制使用 crlf 换行符,这在 windows 上是没问题的,但在 mac os 上就出现了问题:

LF 被 批量更换成了 CRLF 导致提交时整个文件均发生替换

但这样就引出了另一个问题:为什么 windows 不会出现问题?

问题发现

经过一番 git 文档翻看,找到了这么一个配置项:autocrlf

该配置项用于在 git clone / git pull 以及 git push 时的换行符自动转换方式,文档中提供了如下三个值:

1
2
3
true   # 在提交时将CRLF转换为LF 当签出代码时,LF会被转换成CRLF
input # 在提交是将CRLF转换为LF ,签出时不转换
false # 取消此功能

而该属性的默认值为自动,什么是自动?

经测试,macos 和 linux 中默认为 false,而 windows 上默认为 true。在 windows 系统拉取代码时,git 上的代码在拉取时自动从 LF 转换为了 CRLF,并在提交时自动从 CRLF
转换回了 LF。因此在默认情况下,此处 .editorconfig 中的配置 CRLF 并不会对其产生什么影响。

而我们的 macos 这边就不一样了,由于其并没有默认开启 autocrlf,代码使用 LF 换行符被完整不变的拉取了下来,但由于 .editorconfig 的干扰,编写代码时被 webstorm 强制转换为了 CRLF
,全部文件发生替换。

问题解决

既然问题已经找到了,那解决也就很容易,把 macos 的 autocrlf 也设置成 true 不就好了。

1
2
# 全局设置开启换行符自动转换
git config --global core.autocrlf true

但这样也不好,这次问题之所以出现根本还是因为项目中的 .editorconfig 中配置了 CRLF,仅仅是单个项目的问题就设置为全局配置,那势必会影响其他项目。因此个人认为应该将其配置在项目内部更为合适。

那该怎么处理,你可能想到了像下面这样在项目下设置本地配置?

1
2
# 设置仅仓库范围的 git 配置项
git config core.autocrlf true

你会发现并没有什么用,因为在项目被 clone 下来这个过程中,就已经以 LF 的形态下凡了,依然会被 .editorconfig 强制转换,已经为时已晚了。因此只能在 clone 命令上动手,像下面这样

1
2
# -c 在 clone 时指定 git 配置项
git clone git@github.com:xxx/xxx.git -c core.autocrlf=true

这样项目在下来的时候就已经是 CRLF 的形状了,可以安心敲代码提交拉取了,也不会影响到其他项目。

新的问题

很多项目都存在 .editorconfig 配置文件,该配置文件默认为限制换行符为 LF,按上面的理论,似乎默认情况下会导致 windows 出现此文中 macos 的问题:

代码拉取时被默认转换为了 CRLF,但因为 .editorconfig 的限制,编写代码时被转换成了 LF,导致项目被全部替换

但似乎开发中并没有遇到这种情况?

新问题探讨

在 windows 上测试后,可以发现和理论所想的类似,代码 clone 后换行符格式显示为 CRLF,一经修改后就变味了 LF

但却并没有发生全文替换,而仅仅是在 git add 时给与了警告提示:

且在我强制将全文替换为 LF,文件显示发生变化需要提交后,执行 git add ,变化竟然诡异的消失了,提示不存在需要 commit 的内容。

由于网上并没有找到相关说法,因此我个人推断:在 windows 上, git 的 commit 对比规则不会对不同换行符做出处理

后记

从没想过这么一个小换行符能折腾掉我这么多精力,为了搞懂这东西花了大半上午,不过既然是带薪摸鱼,也就算了罢。

什么?你管周末上班连上 12 天算带薪摸鱼?