【问题标题】:Git CRLF LF EOL Conversion SettingGit CRLF LF EOL 转换设置
【发布时间】: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

  1. text 此属性启用和控制行尾标准化。当一个文本文件被规范化时,它的行尾被转换为LF在存储库中。要控制在工作目录中使用哪种行尾样式,请使用eol 属性用于单个文件core.eol 配置变量用于所有文本文件
    • 在路径上设置text 属性可启用行尾规范化并将路径标记为文本文件。 无需猜测内容类型即可进行行尾转换。
    • 取消设置路径上的 text 属性会告诉 Git在签入或签出时不要尝试任何行尾转换
    • text 设置为“auto”时,路径被标记为自动行尾标准化。如果 Git 确定内容是文本,则在签入时将其行尾标准化为 LF
    • 未指定。如果未指定 text 属性(由 !text 或根本没有设置条目),Git 使用 core.autocrlf 配置变量来确定是否应转换文件(回退兼容性,如 编辑 8)。
  2. 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 文件中指定。行尾由texteol 属性控制。

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

可能的解决方案:

  1. 作为 EDIT 3,注释掉 * text=auto
  2. gitattributes 中为.md 文件添加一行:*.md eol=lf
    • 如果创建了另一种文本文件,例如.txt,我还应该为其添加一行*.txt eol=lf
  3. * text=auto 更改为* !text
  4. 彻底删除.gitattributes文件

据我目前所知,我认为:

  1. 通过filetype text in gitattributes,在checkin 时对filetype 进行EOL 规范化。
  2. 同时,此行暗示结帐时还应执行default eoldefault 表示取决于全局配置git config --global core.eol xxx 或默认操作系统样式core.eol = native
    • 您可以运行git config --global core.eol 来查看该值在您的系统上的设置。如果没有返回,则表示您正在使用操作系统默认值 native
  3. eol 暗示text 属性,而text 暗示默认eol 属性
  4. 所以当*.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 都会在这些文件上运行CRLFLFreplacement,并且在写出工作目录时将运行反向替换。。 p>


EDIT 9 Final Idea

  1. textcore.autocrlf(in .gitattributes) 专注于从工作树写入存储库数据库的 EOL 转换。
  2. eolcore.eol(in global config) 专注于从存储库数据库写入工作树的 EOL 转换。
  3. 在决定 EOL 转换时,.gitattributes 的优先级高于 global config。后者实际上是后备参考。
  4. 如果指定了一种方式转换,另一种方式未指定或未定义,则使用默认的回退选项进行另一种方式转换。
  5. EOL 问题与您在编辑文件时选择的行尾密切相关。

逻辑解释参考我的博客znhoo

【问题讨论】:

  • 啊! man gitattributestext=auto “确保 Git 认为是文本的所有文件都将在存储库中具有规范化 (LF) 行结尾”。
  • 当你编辑时,请不要写像'EDIT'(或'UPDATE')这样的cmets - 每个帖子都有一个修订历史记录,显示每次编辑自动更改的内容,复制没有任何收获并使对于将来阅读它的人来说,这个问题看起来真的很奇怪(这是大多数观点的来源)
  • @Flexo 我应该放什么cmets?因为每次我只改变一点点。不容易描述。
  • 老实说,这并不重要,比如“添加缺少的 Foo”,但如果你以一种假装你用所有信息编写它的风格来编写它,这个问题会更好从一开始。

标签: git emacs core.autocrlf


【解决方案1】:

罪魁祸首是您的 Git 配置中的 core.safecrlf=true

来自the git-config manual page

core.safecrlf
    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. The variable can be set to "warn", in which case git will only
    warn about an irreversible conversion but continue the operation.

【讨论】:

  • '当行尾转换处于活动状态'是条件。我已将“autocrlf”设置为“假”。所以我不认为这是由于“safecrlf”
  • 哦,你是对的。好吧,只是为了笑,如果你将 safecrlf 更改为 false 或 warn 会发生什么?
  • 输出警告:LF 将被 _posts/new file.md 中的 CRLF 替换。该文件将在您的工作目录中以原始行结尾。
【解决方案2】:

可能的解决方案:

  1. 作为 EDIT 3,注释掉 * text=auto
  2. gitattributes 中为.md 文件添加一行:*.md eol=lf
    • 如果创建了另一种文本文件,例如.txt,我还应该为其添加一行*.txt eol=lf
  3. * text=auto 更改为* !text
  4. 彻底删除.gitattributes文件

【讨论】:

    猜你喜欢
    • 2017-03-21
    • 2016-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-30
    • 1970-01-01
    • 1970-01-01
    • 2010-12-08
    相关资源
    最近更新 更多