计算机目前有两个文本换行符的事实标准。涉及两个字符:
CR
Carriage Return 回车符。转义符\r
ASCII 码13 (0x0D)
LF
Line Feed 换行符。转义符\n
ASCII 码10 (0x0A)
顾名思义,这是古早打字机时期流传下来的控制指令。
用法上:
- Windows 采用
CRLF
两个字符做行尾,最大程度照顾兼容性。 - Linux/macOS 采用
LF
。其中 macOS 自 2001 年起从CR
改为LF
。
Git 默认使用 LF
,即:文本文件检入至仓库时(checkin)换行符使用 LF
,检出至工作目录时(checkout)换行符使用 LF
。
这跟 Windows 的默认值不同,需要处理。Git 提供了一些相关配置项。
首先,Git 只对文本文件做修改 。那么首先要标记或检测一个文件是否为文本文件。这是 .gitattributes
的用途(之一)。
这个片段简要说明其用法:
.gitattributes
# auto detect, not mark as text unconditionally
* text=auto
*.c text
*.cpp text
# binary = -text -diff
*.exe binary
*.lib binary
*.obj binary
.gitattributes
可以是仓库级配置,置于仓库根目录;也可以是用户级配置,位置和命名跟 .gitconfig
相同($HOME/.gitattributes
$HOME/.config/git/attributes
)。
.gitattributes
自上而下后者覆盖前者、仓库级覆盖用户级
其次,Git 会修改文本文件的换行符(End of Line,EOL)和文本编码(Text Encoding)。当然本文只关心换行符。
autocrlf 取值及效果如下所示:
- $autocrlf=false : checkout as-is, checkin as-is
- $autocrlf=input : checkout as-is, checkin eol=lf
- $autocrlf=true : checkout $eol, checkin eol=lf
EOL 取值如下所示:
- $eol=native : platform preference
- $eol=lf
- $eol=crlf
还挺清晰,对吗?考虑考虑下面两种情形:
- 检入了文件,文件
eol=crlf
- 文本文件的不同的行混用了
crlf
lf
#1 很常见,尤其是下载使用他人的代码仓库的时候。这时,如果将其作为文本文件,那么检出时就会遵循 autocrlf,如果配置是 input or true,那么 git diff
全文件每行都不匹配,因为再次检入就会改成 eol=lf 了。
针对这种情况,Git attribute text
的自动检测写法 text=auto
能处理好:
text
显式标记为文本文件,处理视同 autocrlf=truetext=auto
自动检测是否为文本文件。如果是文本,处理视同 autocrlf=true- 特殊情况:如果是文本、已检入过 eol=crlf,处理视同 autocrlf=false
因此 .gitattributes
最佳写法是:
.gitattributes
*.c text=auto eol=native
*.cpp text=auto eol=native
为何这么做好呢?因为你不是原仓库的唯一所有人,避免破坏原仓库文件 eol 可以避免合并冲突。
可以使用如下命令观察当前状态:
bash
> git ls-files --eol a-file-whose-eol-is-crlf
i/crlf w/crlf attr/text a-file-whose-eol-is-crlf
如果你只是仓库消费者,最简单做法是 .gitattributes
写成这样:
.gitattributes
*.c -text eol=input autocrlf=false
如果你是唯一所有人,那么你可以将全量扫描并统一 eol:
bash
git add --renormalize .
茴字的另一种写法:
bash
git filter-branch --tree-filter 'find . -type f -exec dos2unix {} \;' -- --all
autocrlf eol 不仅可以在 .gitattributes
中配置,还有 .gitconfig
内的一组配置项:
core.autocrlf
文本文件处理时的默认值core.eol
默认=native
所以一般无需配置core.safecrlf
如果要发生不可逆的转换,则=true
阻止;=warn
发出警告
临了,发现隔壁也有一篇参考文档 Git 优雅处理行结束符,也可看看。