CRLF和LF--团队开发难以排查的编码错误

911 阅读4分钟

LF(Line Feed)代表“换行”,转义序列 \n,这个字符代表一行文本的结束,在 Linux 和 Mac 上相当于新文本行的开始。

CR(Carriage Return)代表“回车”,转义序列 \r,将光标移动到当前行的开头。

简言之,LF 换下一行,CR 回到行首,CRLF 代表换下一行并且回到行首

MS-DOS 使用 CRLF 的两个字符组合来表示文件中的行尾,现代 Windows 计算机一直使用 CRLF 作为行尾。同时,从一开始 Unix 就使用 LF 来表示行尾,为了一致性和简单性而放弃了 CRLF。Apple 最初仅在 Mac Classic 上使用 CR,但最终在 OS X 上改用了 LF,与 Unix 一致。

在 bash中,你可以使用 cat -A 查看特定文件的行尾,如果文件使用 CRLF,您将在每行末尾看到字符串 ^M,其M表示回车,,其中 ^M 表示回车, 表示换行。下面是一个示例:

line one^M$
line two^M$
line three^M$

如果文件使用 LF,那么您只会看到美元符号:

line one$
line two$
line three$

由于Windows默认使用 CRLF,而Linux和macOS默认使用 LF,而这是两种不同的字符,因此在书写代码时,很容易不同文件使用了不同的行尾符,甚至一个文件中混用两种行尾符,而git这样的版本控制软件比较的是精准字符,行尾符的变化会被视作代码有了变化,而这些不同,肉眼不可见,因此就会导致一些不必要的麻烦。

git 对于行尾的处理有一套规则。 可以使用 core.autocrlf 配置告诉git如何处理系统上的行尾。可以通过以下命令完成:

git config --global core.autocrlf [true|false|input]

false ,git会关闭行尾转换,通常不这么用,除非团队中的每个人都使用相同的操作系统。 true ,文件检出会转换为为 CRLF,但是当提交文件时,CRLF 会被替换为 LF。基本上,此设置可确保你的代码库在所有文件的最终版本中始终使用 LF,但在获取文件时在本地使用 CRLF。这是 Windows 下的推荐设置,因为 CRLF 是 Windows 的本机行结尾。 input,文件在提交时转换为 LF,但在检出时不会转换为任何内容,这是 Mac/Linux 开发人员的推荐设置,因为这些操作系统默认使用 LF。这个配置下,文件最初被创建时是什么行尾,在本地就会一直保持住,除非手动修改。 input 和 true 之间的唯一区别是在检出代码时会不会处理行尾。

一般来说,false很少用,Windows下默认使用true,Linux和macOS默认使用input,这就会带来一种情况:同一个代码库,代码库里行尾都是 LF,在Windows下检出后,行尾都是 CRLF,而在Linux和macOS下检出后,行尾都是 LF。

VSCode中的 CRLF和LF

VSCode中打开一个文本文件后,状态栏的右边,有一项显示着 CRLF或者LF,这个状态项有两个含义,一个是当前这个文件使用的是哪种行尾符,另一个是点击这个状态项,可以更改当前文件的行尾符,更改之后,文件会被变为已修改状态,观察更改行尾符后的文件大小,会大一些或小一些。

一般来说,行尾符不影响代码的编译,加上Windows和Linux/macOS的默认配置,代码的行尾变化在本地会被自动处理,也不会冲突。

但有一种情况,当把代码从Linux机器上拷贝到Windows机器上,或者反过来拷贝时,比如本地开发机是Windows,服务器是Linux,将代码从服务器上下载下来后,行尾符会被修改,此时git 会认为代码有变更,但是在代码编辑器里看不到变化是什么,sourceTree这样的工具里会显示: 未检测到此文件的变化,或者这是一个二进制文件,这时就需要去看一下行尾符是否有变化了。

还有一种情况,在程序中需要对代码进行编辑修改,比如kitex、hertz之类框架的代码生成器会对待生成文件行尾符有要求必须是 LF,如果文件的行尾不是 LF,代码生成会失败。