通过阅读 git-config 文档理解 Git 如何使用autocrlf、safecrlf、eol和.gitattributes处理line-ending

[toc]

一、遇到的问题

在Windows平台上,会出现如下的warning:

$ git add app.wxss
warning: LF will be replaced by CRLF in app.wxss.
The file will have its original line endings in your working directory.

为什么会出现这个warning呢?

二、为什么会出现这个问题

通过查阅《ProGit》的相关内容,可以得知:

If you’re programming on Windows and working with people who are not (or vice-versa), you’ll probably run into line-ending issues at some point. This is because Windows uses both a carriage-return character and a linefeed character for newlines in its files, whereas Mac and Linux systems use only the linefeed character. This is a subtle but incredibly annoying fact of cross-platform work; many editors on Windows silently replace existing LF-style line endings with CRLF, or insert both line-ending characters when the user hits the enter key.
简单翻译一下,Windows在换行的时候,同时使用了回车符(carriage-return character)和换行符(linefeed character);而Mac和Linux系统(很老的mac系统才是CR,可以参见wiki),此时,仅仅使用了换行符(linefeed character)。同时呢,Windows的许多编辑器还悄悄滴将LF修改成了CRLF格式的行结束符,或者在你敲回车的时候,CRLF格式的行结束符就产生了。当然,这一切都发生在同时存在Windows和非Windows的跨平台工作中,如果大家都是同一种操作系统,那么,就天下太平了。

warning中所说的LF和CRLF分别是linefeed和carriage-return&linefeed。
那么现在,再仔细看warning的内容,为什么在git add的时候,“警告:app.wxss中的LF将来会被替换成CRLF”?

三、为什么LF->CRLF

Git can handle this by auto-converting CRLF line endings into LF when you add a file to the index, and vice versa when it checks out code onto your filesystem.
Git有一个针对性的功能:当添加到暂存区时,自动将CRLF转换成LF;反之,当检出时,自动将LF转换成CRLF。
You can turn on this functionality with the core.autocrlf setting.
可以通过设置core.autocrlf来开启这个功能。

看到这里,就更加不懂了,添加到暂存区时,为什么警告LF将被转换成CRLF?这不是和功能相反了吗?

四、原因

这个问题与git-config里面的相关设置有关,主要涉及到三个参数:

  • core.autocrlf
  • core.safecrlf
  • core.eol

这三个参数用来配置Git处理line-ending的方式。

五、接下来,来看如何配置

1. core.autocrlf

(1) true

If you’re on a Windows machine, set it to true — this converts LF endings into CRLF when you check out code:
$ git config --global core.autocrlf true
如果是在 Windows 系统上,把它设置成 true,这样在检出代码时,换行(LF)会被转换成回车和换行(CRLF)

(2) input

If you’re on a Linux or Mac system that uses LF line endings, then you don’t want Git to automatically convert them when you check out files; however, if a file with CRLF endings accidentally gets introduced, then you may want Git to fix it. You can tell Git to convert CRLF to LF on commit but not the other way around by setting core.autocrlf to input:
$ git config --global core.autocrlf input
如果使用以换行作为行结束符的 Linux 或 Mac,你不需要 Git 在检出文件时进行自动的转换;然而当一个以回车加换行作为行结束符的文件不小心被引入时,你肯定想让 Git 修正。 你可以把 core.autocrlf 设置成 input 来告诉 Git 在提交时把回车和换行转(CRLF)换成换行(LF),检出时不转换

(3) false

If you’re a Windows programmer doing a Windows-only project, then you can turn off this functionality, recording the carriage returns in the repository by setting the config value to false:
$ git config --global core.autocrlf false
如果你是 Windows 程序员,且正在开发仅运行在 Windows 上的项目,可以设置 false 取消此功能,把回车(CR)保留在版本库中

以上,是core.autocrlf的设置规则与建议。

2. core.safecrlf

通过查阅git-scm上的文档上关于git-config的文档或者mirrors.edge.kernel.org

If true, makes Git check if converting CRLF is reversible when end-of-line conversion is active. Git will verify if a command modifies a file in the work tree either directly or indirectly.For example, committing a file followed by checking out the same file should yield the original file in the work tree. If this is not the case for the current setting of core.autocrlf, Git will reject the file.

简单翻译一下:当core.autocrlftrue或者input时,算激活了eol,此时如果core.safecrlftrue,Git检查crlf转换是否正常,比如Windows平台,core.autocrlf设置为true,如果工作区的文件中含有LF,Git就会拒绝,因为true的情况下,Git认为工作区应该都是CRLF才对啊

给你一个致命大礼,fatal:LF would be replaced by CRLF in app.wxss.,阻止你继续操作。


^ _ ^ 使用dos2unix进行手动转换

这种情况不要慌,可以使用dos2unix工具中的unix2dos将LF转换成CRLF,来满足core.autocrlftrue的要求。当然,解决的方法有很多,可以根据实际情况,使用不同的方法来解决。
以下命令可以将当前文件夹内的文件批量的转换,也有其他方式,比如find . -type f -exec dos2unix {} +,可以自行Google

find . -type f -print0 | xargs -0 dos2unix

dos2unix工具在Windows的MINGW64 Git Bash客户端上自带,在mac平台可以Google how to install dos2unix on mac,同理linux(sudo apt-get install dos2unix),哈哈哈。


The variable can be set to "warn", in which case Git will only warn about an irreversible conversion but continue the operation.
也可以设置core.safecrlfwarn,Git就只会警告一下,不会阻止你。

继续看文档的内容。写着写着成了《带你看文档系列》了,所以很多问题,仔细看文档就能解决,但是文档太多,也很难看懂,只能花时间多看了。

CRLF conversion bears a slight chance of corrupting data. When it is enabled, Git will convert CRLF to LF during commit and LF to CRLF during checkout. A file that contains a mixture of LF and CRLF before the commit cannot be recreated by Git. For text files this is the right thing to do: it corrects line endings such that we have only LF line endings in the repository. But for binary files that are accidentally classified as text the conversion can corrupt data.
If you recognize such corruption early you can easily fix it by setting the conversion type explicitly in .gitattributes. Right after committing you still have the original file in your work tree and this file is not yet corrupted. You can explicitly tell Git that this file is binary and Git will handle the file appropriately.

这一段主要是说,同时有LFCRLF的文件是被腐蚀的,这类文件是不被Git认可的,而CRLF的转换过程很可能会产生腐蚀的文件,比如二进制的文件被当作文本的话,就会被腐蚀。

所以提出了重要的文件.gitattributes来明确转换配置,而且越早设置越好。你可以明确地指出某些文件是二进制的,比如*.jpg,Git知道了以后,会妥善处理。

Note, this safety check does not mean that a checkout will generate a file identical to the original file for a different setting of core.eol and core.autocrlf, but only for the current one. For example, a text file with LF would be accepted with core.eol=lf and could later be checked out with core.eol=crlf, in which case the resulting file would contain CRLF, although the original file contained LF. However, in both work trees the line endings would be consistent, that is either all LF or all CRLF, but never mixed. A file with mixed line endings would be reported by the core.safecrlf mechanism.

我的理解是,A和B协同开发,A设置的是core.eol=lf core.autocrlf=true,B设置的是core.eol=crlf core.autocrlf=true,那么A checkout的时候,生成lf结尾的文件,而B checkout的时候,生成crlf结尾的文件。要么都是lf,要么都是crlf安全检查不可能允许混合出现,如果发现了混合的行结束符,就会报警

3. core.eol

通过查阅git-scm上的文档上关于git-config的文档或者mirrors.edge.kernel.org

Sets the line ending type to use in the working directory for files that have the text property set when core.autocrlf is false. Alternatives are lfcrlf and native, which uses the platform’s native line ending. The default value is native. See gitattributes[5] for more information on end-of-line conversion.
core.autocrlffalse,设置行结束符的类型,可以是

  • lf
  • crlf
  • native三种,其中native是指平台默认的行结束符。默认的类型是native

欲知详情,请翻阅gitattributes[5]或者mirrors.edge.kernel.org

六、总结一下吧

1. 不安全不保险的方式

虽然Google查询LF will be replaced by CRLF,几个答案会建议设置

git config --global core.autocrlf false
git config --global core.safecrlf false

比如stackoverflow知乎github上的bolg中的某些答案(这几个链接里也是有一些干货的),
但是,通过上面我们看文档的过程,我们发现这种方式,是不保险的。很容易产生混合,git diff的时候,就会影响我们查看版本之间的修改。

2. 个人推荐的设置方式

(1)添加.gitattributes

首先要在项目里添加.gitattributes文件,可以参考Github help-Dealing with line endingsgitattributes[5],这是我自己的.gitattributes

(2)safecrlf设置为true

git config --global core.safecrlf true

(3)autocrlf在不同平台不同设置

  • Windows
git config --global core.autocrlf true
  • Mac Or Linux
git config --global core.autocrlf input

(4)eol默认native,因为autocrlf不是false,也不起作用啊

补充

第一点 Git Setup Treat Line Endings In Text Files

Git默认的core.autocrlf其实在安装Git For Windows的时候,让我们选择了,只是安装的时候并不会注意,就是下面这张图:
Git treat line endings in text files
由上向下依次是true input false

第二点 TortoiseGit settings about AutoCrlf

另外,如果使用的是TortoiseGit,要注意其中的设置:
TortoiseGit settings

© 著作权归作者所有
这个作品真棒,我要支持一下!
专注Android知识网络的造轮子工程,与大家一同学习Android的新技术,完善知识体系
0条评论
top Created with Sketch.