Git中LF will be replaced by CRLF问题原因及解决方法

在Git或者Github上进行跨平台项目合作开发时,会遇到换行符转换的问题。

编辑文档的过程中,在按下回车键的时候实际上是向文档插入了一个不可见的换行符。在Windows系统中是CRLF (Carriage-Return Line-Feed,即回车换行)就是回车符CR (ASCII 13, \r)加上换行符LF (ASCII 10, \n)。在Linux/UNIX、OS X系统中只用换行符LF来标识一行的结束。

问题就来了,结尾换行符不一致在版本更新的时候就会导致不必要的麻烦,版本管理系统可能将换行符不一致视为对文件的修改。这当然不是我们所希望的,所幸,Git和Github有专门针对这个问题的解决方法。

Global settings for line endings

git config core.autocrlf命令可以管理换行符的识别,详细说明可以参考Git的帮助文档。在Windows系统上,只要将该项设置为true就可以了。

$ git config --global core.autocrlf true
# Configure Git on Windows to properly handle line endings

在Linux/UNIX、OS X系统上将该项设置为input

$ git config --global core.autocrlf input
# Configure Git on OS X or Linux to properly handle line endings

此时,Git会在Windows系统提交代码时将换行符转换成LF,checkout时转换为CRLF;在Linux/UNIX、OS X系统以及库中保留LF作为换行符。

如果你是Windows程序员,且正在开发仅运行在Windows上的项目,可以设置false取消此功能,把回车符记录在库中:

$ git config --global core.autocrlf false

Per-repository settings

当然,并非所有现实情况都那么完美,我就遇到了Stack Overflow这个帖子上面的问题。我使用的操作系统是Windows,但是开发的项目需要在不能连接外网的CentOS虚拟机中运行,多是Python、Shell脚本。在Linux/UNIX系统中,Windows的换行符会被当作特殊字符处理,可能会影响程序运行并报错。

附上处理该类问题的一点经验:

对于逻辑没有问题但运行一直报错的程序可用vi -b查看源文件,看每行末尾是否有粗体^M字符。如果有就说明是换行符在作怪,可用1, $ s/^M//g命令进行替换。其中,^M字符需按ctrl+v+m组合键输入。

此时问题就来了,如果直接设置core.autocrlftrue的话,在签出时会将其自动转换成CRLF换行符,在提交代码时会报warning: LF will be replaced by CRLF。该警告一般是项目中出现了CRLFLF换行符混用的情况,LF在提交时会被自动转换成CRLF。对于Windows和UNIX混用的情况显然全局的设置就不太合适了,需要针对该项目设置具体换行符。

建立一个.gitattributes文件,每一行开始是文件名的pattern,即具体的文件类型,空格后是指定具体使用的换行符。下面是我在官方例子中加入了.sh脚本文件的换行符指定,这样就会更明确每个设置项的意义。

# Set the default behavior, in case people don't have core.autocrlf set.
* text=auto

# Explicitly declare text files you want to always be normalized and converted
# to native line endings on checkout.
*.c text
*.h text

# Declare files that will always have CRLF line endings on checkout.
*.sln text eol=crlf

# Declare files that will always have LF line endings on checkout.
*.sh text eol=lf

# Denote all files that are truly binary and should not be modified.
*.png binary
*.jpg binary

在处理这类Windows和UNIX混用的项目时要更加小心,建议使用专门的文本编辑器来打开此类文件,并且在IDE或者文本编辑器统一设置换行符为LF以及编辑环境为UNIX。

Refreshing a repository after changing line endings

当设置了core.autocrlf选项或者添加了.gitattributes以后,可以提交编辑后的源文件。此时,Git会帮助你转换每个文件中的换行符。

最好按照Github帮助文档配置并备份文件。首先要删除.git文件夹外的所有文件,然后重建文件。

  1. 保存当文件,保证所发生的修改不丢失。

    $ git add . -u
    $ git commit -m "Saving files before refreshing line endings"
    
  2. 删除Git本地库的索引

    $ git rm --cached -r .
    
  3. 重写Git本地库索引确认新的换行符

    $ git reset --hard
    
  4. 将所有文件重新添加,准备提交。这时也是一个机会检查哪些文件的换行符还有问题,屏幕会输出提示。

    $ git add .
    # It is perfectly safe to see a lot of messages here that read
    # "warning: CRLF will be replaced by LF in file."
    
  5. 提交代码。

    $ git commit -m "Normalize all the line endings"
    

Conclusion

网上有一些方法很暴力,直接将.git文件夹删除后重新建库,把core.autocrlf设置为false也没有说明为什么。所以还是需要搞清楚原理根据项目的情况来设置:

  1. 一般情况下建议Windows用户将core.autocrlf设置为true,UNIX用户将core.autocrlf设置为input

  2. 如果有Windows和UNIX系统混用的项目时,针对该项目确认IDE以及文本编辑器的换行符设置和每种文件类型的换行符,并添加.gitattributes文件。

  3. 不太建议把core.autocrlf设置为false即使你的项目是纯Windows项目。我是小心谨慎的性格,人生总有太多难免嘛

参考

  1. newline - Trying to fix line-endings with git filter-branch, but having no luck - Stack Overflow

  2. git replacing LF with CRLF - Stack Overflow

  3. Dealing with line endings - GitHub Help

  4. Formatting and Whitespace - Git - Git Configuration

文章目录
  1. 1. Global settings for line endings
  2. 2. Per-repository settings
  3. 3. Refreshing a repository after changing line endings
  4. 4. Conclusion
  5. 5. 参考
,