【发布时间】:2014-11-18 09:41:16
【问题描述】:
平台:Windows 8.1 Emacs 24.3
git config --global -l 显示:
user.name=username
user.email=useremail
core.autocrlf=false
core.safecrlf=true
Git 仓库.gitattributes 文件:
# Auto detect text files and perform LF normalization
* text=auto
# Custom for Visual Studio
*.cs diff=csharp
*.sln merge=union
*.csproj merge=union
*.vbproj merge=union
*.fsproj merge=union
*.dbproj merge=union
# Standard to msysgit
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain
我确实认为我的 Git 和存储库设置是正确的。
但是每次我用 Emacs 创建一个新的文本文件时,我都无法运行git add <newfile>。该文件由utf-8-unix编码。
错误信息如下:
E:\workspace\repository [master +0 ~2 -0]> git add .
fatal: LF would be replaced by CRLF in newfile.txt
我不认为是由于 emacs 编辑器问题。因为我打开了新文件,并且很确定行尾是 LF 而不是 windows 默认的 CRLF。
哪个配置部分决定LF会被CRLF替换?
编辑 1
如果safecrlf 设置为warn,则输出为:
warning: LF will be replaced by CRLF in _posts/2014-11-19-test.md.
The file will have its original line endings in your working directory.
这意味着文件已成功添加到索引中。我的文件是由utf-8-unix 编码的。
编辑 2
有趣的是,如果我使用记事本而不是 Emacs 24.3 创建一个新文件,则可以毫无问题地添加该文件。区别在于记事本采用CRLF行尾,而Emacs 24.3采用LF行尾。
所以问题出在某个地方,Git 以某种方式将CRLF 转换为LF,然后返回到CRLF,这会为原始LF 行结束文件生成错误。
编辑 3
以前,GitHub Windows GUI 客户端警告我没有 .gitattributes 文件用于我的存储库,并建议使用上述默认的 .gitattributes 文件。
我认为问题出在* text=auto 行。所以我把这行注释掉了。
现在一切正常!
编辑 4
核心是:
禁用自动换行符 by GitHub。
行尾取决于平台文件编辑器。
编辑 5
-
text此属性启用和控制行尾标准化。当一个文本文件被规范化时,它的行尾被转换为LF在存储库中。要控制在工作目录中使用哪种行尾样式,请使用eol属性用于单个文件和core.eol配置变量用于所有文本文件。- 在路径上设置
text属性可启用行尾规范化并将路径标记为文本文件。 无需猜测内容类型即可进行行尾转换。 - 取消设置路径上的
text属性会告诉 Git在签入或签出时不要尝试任何行尾转换。 - 当
text设置为“auto”时,路径被标记为自动行尾标准化。如果 Git 确定内容是文本,则在签入时将其行尾标准化为LF。 - 未指定。如果未指定
text属性(由!text或根本没有设置条目),Git 使用core.autocrlf配置变量来确定是否应转换文件(回退兼容性,如 编辑 8)。
- 在路径上设置
-
eol此属性设置要在工作目录中使用的特定行尾样式。它无需任何内容检查即可启用行尾规范化,有效地设置text属性。-
也就是说
eol自动设置text属性。 - 设置为字符串值“crlf”
此设置强制 Git 在签入时规范化此文件的行尾,并在签出文件时将其转换为 CRLF。 - 设置为字符串值“lf”
此设置强制 Git 在签入时将行尾规范化为 LF,并在文件签出时阻止转换为 CRLF。
-
也就是说
如果eol 放在.gitattributes 文件中,它应该应用于特定的文件类型。同时在签入时自动将具体文件类型标记为text,以进行LF归一化。如果eol 设置为git config --global core.eol xxx,则为所有文本文件设置eol。
参考gitattributes - defining attributes per path
编辑 6
Git 属性在.gitattributes 文件中指定。行尾由text 和eol 属性控制。
text 属性告诉 Git 文件是binary(即在签出和签入时不应执行EOL 转换)或text(执行EOL 转换,始终转换为LF 而签到)。可能的值有 set(开启 EOLs 转换)、unset(关闭 EOLs 转换,默认值)和auto(如果文件被检测为二进制,则不进行转换,否则执行 EOLs 转换)。
eol 属性:如果设置隐式设置text 属性并定义在签出时文件应转换为的 EOL。
参考Line endings handling in SVN, Git and SubGit
编辑 7
可能的解决方案:
- 作为 EDIT 3,注释掉
* text=auto - 在
gitattributes中为.md文件添加一行:*.md eol=lf- 如果创建了另一种文本文件,例如
.txt,我还应该为其添加一行*.txt eol=lf
- 如果创建了另一种文本文件,例如
- 将
* text=auto更改为* !text - 彻底删除
.gitattributes文件
据我目前所知,我认为:
- 通过
filetype textingitattributes,在checkin 时对filetype进行EOL 规范化。 - 同时,此行暗示结帐时还应执行
default eol。default表示取决于全局配置git config --global core.eol xxx或默认操作系统样式core.eol = native。- 您可以运行
git config --global core.eol来查看该值在您的系统上的设置。如果没有返回,则表示您正在使用操作系统默认值native。
- 您可以运行
-
eol 暗示
text属性,而text暗示默认eol属性。 - 所以当
*.md text=auto被启用时。*.md文件被 Git 检测为text文件,并在签入时转换为 LF。结帐时,*.mdLF 将转换为 CRLF。此过程被safecrlf = false全局设置无效,拒绝将文件添加到索引/阶段区域。
编辑 8
我在 EDIT 7 中的三个假设得到验证Mind the End of Your Line
从Git 1.7.2及以上版本开始,EOL设置主要放在工作树根目录.gitattributes。全局配置 autocrlf 仅用于回退兼容性。
*.txt text 将匹配过滤器*.txt 的所有文件设置为text。这意味着每次将这些文件写入对象数据库时,Git 都会在这些文件上运行CRLF 到LFreplacement,并且在写出工作目录时将运行反向替换。。 p>
EDIT 9 Final Idea
-
text和core.autocrlf(in.gitattributes) 专注于从工作树写入存储库数据库的 EOL 转换。 -
eol和core.eol(inglobal config) 专注于从存储库数据库写入工作树的 EOL 转换。 -
在决定 EOL 转换时,
.gitattributes的优先级高于global config。后者实际上是后备参考。 - 如果指定了一种方式转换,另一种方式未指定或未定义,则使用默认的回退选项进行另一种方式转换。
- EOL 问题与您在编辑文件时选择的行尾密切相关。
逻辑解释参考我的博客znhoo
【问题讨论】:
-
啊!
man gitattributes说text=auto“确保 Git 认为是文本的所有文件都将在存储库中具有规范化 (LF) 行结尾”。 -
当你编辑时,请不要写像'EDIT'(或'UPDATE')这样的cmets - 每个帖子都有一个修订历史记录,显示每次编辑自动更改的内容,复制没有任何收获并使对于将来阅读它的人来说,这个问题看起来真的很奇怪(这是大多数观点的来源)
-
@Flexo 我应该放什么cmets?因为每次我只改变一点点。不容易描述。
-
老实说,这并不重要,比如“添加缺少的 Foo”,但如果你以一种假装你用所有信息编写它的风格来编写它,这个问题会更好从一开始。
标签: git emacs core.autocrlf