只需运行以下命令即可解决问题:
git config --global core.safecrlf=false
知道你很着急,但请稍安勿躁,现在去执行 commit 吧。
若仍然报错,请将上述命令中的 safecrlf=false 改为 autocrlf=true,再执行一次即可。
全文完
如果你心中还有疑惑,请继续往下阅读。
为什么会出这个问题?
可以很肯定地说,你正在使用 Windows 系统——这是 Windows 专属的 Bug。换用 macOS 也能彻底避免此问题。
为什么我同事也都是 Windows 却没问题?
因为某次不经意的操作,你把 Git 中的 safecrlf 配置改成了 true。可能是某个软件“好心”帮你调整的,也可能你之前看到某篇文章说 safecrlf=true 是最佳实践,就照着做了。而 Git 的默认配置就是 false,开头那条命令只是让你恢复到默认值罢了。
如果想彻底搞清楚背后的原因,请坐稳,接下来要深入讲解了。
什么是 LF 与 CRLF?
世界上有两种操作系统:Windows 是一类,Unix(macOS + Linux)是另一类。这两种系统在表示“空格”这类不可见字符时方式相同,但表示“此处需要换行”的方式却截然不同:Windows 使用 CRLF,Unix 使用 LF。
问题来了:如何确保代码或文本在任何系统上都能正常显示或运行?Git 给出的解决方案是:统一使用 LF。如果是 Windows 系统,在拉取代码时(其实是 checkout/switch 到某分支时)自动将 LF 转换为 CRLF,而在 add 时自动将 CRLF 转换为 LF。
这个行为由哪个配置项控制?autocrlf,注意单词是 auto。文章开头让你设置的是另一个配置项:safecrlf。
报错信息是什么意思?
fatal: LF will be replaced by CRLF — 警告:CRLF 将被转换为 LF,但 Git 却阻止了这次转换。
What?
commit 时本来就应该将 CRLF 转换为 LF,这是正常操作,为什么会出现警告?问题出在 safecrlf 这个配置项上,注意单词是 safe。它的作用是:检查 CRLF 与 LF 的转换是否安全。隐含意思就是:判断将来 checkout/switch 时能否再把 LF 转回 CRLF。恭喜,你中奖了——Git 认为将来无法转换回来,所以不让你 add 本次的变更。Fuck!
此时你需要告诉 Git:不要检查,即设置 safecrlf = false。
这样改可以吗?
当然可以。这就是 Git 的默认配置,你的同事能在 Windows 上愉快地开发,正是因为他们没有改动过默认配置。
其他文章可能会让你执行下面这个命令,查看是否设置了自动转换(注意单词是 auto):
git config --global core.autocrlf
执行后什么都显示不出来,这是因为只要没有配置过全局的 autocrlf,结果就是空。那么如何查看 auto 当前的默认值呢?你应该执行下面这个命令——把单词 global 换成 get:
git config --get core.autocrlf
显示 true,说明 Git 默认自动转换。你可以在自己电脑上试一下:如果显示是 false,请立即执行下方命令,改为 true:
git config --global core.autocrlf=true
接下来同理,查看 safe 的默认值:
git config --global core.safecrlf
git config --get core.safecrlf
你会发现这两条命令都没有结果。Why?傻瓜,还没明白吗——没有值就是 null,null 在程序中代表 false 呀。再看看这一节的标题,你心里已经有答案了吧?
有些包不管任何系统,它只用 LF
比如 pnpm,它无论什么系统,都会把 package.json 和 pnpm-lock.json 的换行符格式化成 LF。所以,请接受现实,胳膊拧不过大腿。老老实实按我说的修改即可,把节省下来的精力用在真正重要的技术上,不是更好吗?
