一文搞懂换行符(CRLF & LF)以及规范使用说明

3,236 阅读5分钟

背景

换行符的问题很容易被人忽视,但是如果你要在项目中对代码格式进行规范化的时候就不得不重视它了。换行符的问题主要影响window系统用户。例如以下场景

  1. git add时会有一个警告(windows环境下当本地修改的文件换行符是LF时)
git add .
warning: in the working copy of '.eslintrc.cjs', LF will be replaced by CRLF the next time Git touches it

原因:这次提交的文件是LF格式,但是在windows环境下,git在拉取代码时默认会把文件转成CRLF格式。所以在提交LF格式文件时,git会有此提示。

  1. 当项目中有使用EsLint校验并指定了换行符时,无法同时兼容Mac和Window系统。
  • 如果设置为CRLF,Mac系统中默认是LF,EsLint则会有警告。
  • 如果设置为LF,Window系统中默认是CRLF,EsLint同样会有警告。

CRLF 和 LF说明

要想理解LF和CRLF,需要先理解CR和LF

  • CR(CarriageReturn)代表回车,对应\r :回到一行的开头,ASCII代码是13
  • LF(LineFeed)代表换行,对应字符\n:另起一行,ASCII代码是10

在不同的操作系统和环境中,CR和LF的组合用于实现换行

  • Windows 和 Dos系统: 使用回车(CR)和换行(LF)两个字符来结束一行,回车+换行(CR+LF),即“\r\n”;所以我们平时编写文件的回车符应该确切来说叫做回车换行符。
  • Mac 和 Linux系统:只使用换行(LF)一个字符来结束一行,即“\n”;现代的版本控制系统(如:git)中也使用LF表示换行。

CR 和 LF 的历史(来自ChatGPT)

  1. CR(Carriage Return) : CR是一个控制字符,通常用来将光标移动到行的起始位置,而不换行。它最初来自于打字机时代,打字机中的"回车"操作会将打印头移动到左侧并保持在同一行上。在计算机中,CR通常用来表示光标回到当前行的起始位置,但不会移动到下一行。
  2. LF(Line Feed) : LF是另一个控制字符,用于将光标移动到下一行的起始位置,实现真正的换行。在计算机中,LF会使光标移到下一行,并定位在左侧,从而开始新的一行。

Git的换行符处理

core.autocrlf

通过core.autocrlf可以更改git处理换行符的方式。

core.autocrlf有三个值:

  1. 当设置为true时,git提交代码时会自动将CRLF转换为LF,在检出代码时会将LF转换成CRLF。一般在windows上使用该功能。
git config --global core.autocrlf true
  1. 在Linux或MacOS上时,使用LF作为换行符,检出代码时不需要转换。但是当代码中已有一个CRLF换行符时,在提交时就需要将其转换成LF。因此input的功能是在提交代码时,将CRLF转换成LF;检出代码时不转换
git config --global core.autocrlf input
  1. 当设置成false时,表示不做任何转换。因此可以把CRLF提交到版本库中。
git config --global core.autocrlf false

综上,如果是跨平台开发和运行,core.autocrlf应在windows上设置为true(windows中默认为true),在Linux和MacOS上设置为input;如果仅在windows上开发和运行的项目,可以设置为false

core.safecrlf

当值为true时,如果你的代码中同时包含两种不同的换行格式会被禁止提交。默认为false。

# 不允许提交包含混合换行符的文件
git config --global core.safecrlf true

# 允许提交包含混合换行符的文件
git config --global core.safecrlf false

# 提交包含混合换行符的文件时给出警告
git config --global core.safecrlf warn

core.eol

eol 表示 "end of line",即"行尾"的意思。当core.autocrlffalse时可以设置文本文件的换行符类型。有三个值crlflfnative,默认是native,表示平台默认的换行符。

网上找到的看似可行的方案

以上方式虽然能解决问题,但是必须要所有项目参与者都在本地设置git,可操作性不大,容易有遗漏。最好是能在项目中进行设置,这样子才能保证所有参与者是一致的。通过.gitattribute文件配置就能很好地解决这个问题。 将此文件提交到存储库时,它将覆盖所有开发者本地的设置(如:core.autocrlf)。 这可确保所有用户的行为一致,而不管其 Git 设置和环境如何。

.gitattribute

在项目根目录添加文件.gitattribute

常用的配置内容如下:

* text=auto eol=lf

*匹配所有文件,text=auto表示由git自己识别是否是文本文件(因为二进制文件,如图片,不需要转换换行符),eol=lf将换行符设置为LF。

使用了.gitattribute则不需要设置core.autocrlfcore.eol,因为.gitattribute中的配置优化级更高。

添加以上文件和配置内容后,当前分支的文件并不会更新成配置的方式。只有重新git clone代码时文件换行符格式才会以配置的方式展示。

若要以.gitattribute文件中配置的换行符更新当前分支上的所有文件,请运行以下命令。

git rm -rf --cached .
git reset --hard HEAD

如果不小心将CRLF换行符提交到仓库,则可以通过以下命令修复,然后重新提交。

git add --renormalize .

实际尝试以上方案并未成功,不知是否是操作不对。如有知道的朋友请留言补充。


EsLint 和 Prettier 指定换行符的方式

设置EsLint规则

module.exports = {
    // ...
    rules: {
        // ...
        'linebreak-style': ['error', 'unix'] // unix表示LF,windows表示CRLF。
    }
}

设置Prettier规则

module.exports = {
    // ...
    endOfLine: 'auto' // lf:"\n"; crlf:"\r\n"; auto: 兼容两者;
}

最佳方案

使用EsLint+Prettier的方式,规则统一使用如上设置的Prettier规则。

如此就能解决文章开头所说的两个问题:

  1. 因未修改git的core.autocrlf值,在不同环境遵从不同的格式(在windows上git提交代码时会自动将CRLF转换为LF,在检出代码时会将LF转换成CRLF;在Mac上始终是LF)。所以提交代码时不会有警告。
  2. Prettier规则中设置endOfLineautoEsLint规则复用该规则。即:EsLint支持两种换行符,也不会告警或报错。

参考文献