[原文链接:通过阅读 git-config 文档理解 Git 如何使用autocrlf、safecrlf、eol和.gitattributes处理line-ending](https://xiaozhuanlan.com/topic/4053786912#sectionlfcrlf)
# 一、遇到的问题
在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》的相关内容](https://git-scm.com/book/en/v2/Customizing-Git-Git-Configuration#Formatting-and-Whitespace),可以得知:
```
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](https://git-scm.com/docs/git-config)上的文档上关于`git-config`的文档或者[mirrors.edge.kernel.org](https://mirrors.edge.kernel.org/pub/software/scm/git/docs/git-config.html)
```
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.autocrlf`为`true`或者`input`时,算激活了`eol`,此时如果`core.safecrlf`为`true`,Git检查`crlf`转换是否正常,比如Windows平台,`core.autocrlf`设置为`true`,如果工作区的文件中含有`LF`,Git就会拒绝,因为true的情况下,Git认为工作区应该都是`CRLF`才对啊。
给你一个致命大礼,`fatal:LF would be replaced by CRLF in app.wxss`.,阻止你继续操作。
---
^ _ ^ 使用dos2unix进行手动转换
这种情况不要慌,可以使用[dos2unix](https://waterlan.home.xs4all.nl/dos2unix.html)工具中的unix2dos将`LF`转换成`CRLF`,来满足`core.autocrlf`为`true`的要求。当然,解决的方法有很多,可以根据实际情况,使用不同的方法来解决。
以下命令可以将当前文件夹内的文件[批量的转换](https://stackoverflow.com/questions/11929461/how-can-i-run-dos2unix-on-an-entire-directory),也有其他方式,比如`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](http://macappstore.org/dos2unix/),同理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.safecrlf为warn,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.
```
这一段主要是说,同时有`LF`和`CRLF`的文件是被腐蚀的,这类文件是不被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](https://git-scm.com/docs/git-config)上的文档上关于git-config的文档或者[mirrors.edge.kernel.org](https://mirrors.edge.kernel.org/pub/software/scm/git/docs/git-config.html)
```
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 lf, crlf 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.autocrlf是false时,设置行结束符的类型,可以是
lf
crlf
native三种,其中native是指平台默认的行结束符。默认的类型是native
```
欲知详情,请翻阅[gitattributes[5]](https://git-scm.com/docs/gitattributes)或者[mirrors.edge.kernel.org](https://mirrors.edge.kernel.org/pub/software/scm/git/docs/gitattributes.html)。
# 六、总结一下吧
## 1. 不安全不保险的方式
虽然Google查询`LF will be replaced by CRLF`,几个答案会建议设置
```
git config --global core.autocrlf false
git config --global core.safecrlf false
```
比如[stackoverflow](https://stackoverflow.com/questions/5834014/lf-will-be-replaced-by-crlf-in-git-what-is-that-and-is-it-important),[知乎](https://www.zhihu.com/question/50862500/answer/123197258),[github上的bolg](https://github.com/cssmagic/blog/issues/22)中的某些答案(这几个链接里也是有一些干货的),
但是,通过上面我们看文档的过程,我们发现这种方式,是不保险的。很容易产生混合,git diff的时候,就会影响我们查看版本之间的修改。
## 2. 个人推荐的设置方式
### (1)添加.gitattributes
首先要在项目里添加.gitattributes文件,可以参考[Github help-Dealing with line endings和gitattributes[5]](https://help.github.com/articles/dealing-with-line-endings/),这是我自己的[.gitattributes](https://github.com/ThorWu/running_pomelo/blob/master/.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](https://camo.githubusercontent.com/c334a5644f69da294255a1de0a690239f8a83131/68747470733a2f2f662e636c6f75642e6769746875622e636f6d2f6173736574732f313233313335392f3937343134392f64396564313662652d303634622d313165332d393336382d3831373138616563653335322e706e67)
由上向下依次是`true input false`。
#### 第二点 TortoiseGit settings about AutoCrlf
另外,如果使用的是TortoiseGit,要注意其中的设置:
![TortoiseGit settings](https://camo.githubusercontent.com/8d6a7962aba0ce4e94ec32e4bf788360a84b301f/68747470733a2f2f662e636c6f75642e6769746875622e636f6d2f6173736574732f313233313335392f3937343136322f31363930353264342d303634632d313165332d393434352d3535656637303238623633632e706e67)