【问题标题】:Git diff thinks line endings are LF when EOL is set to CRLF in .gitattributes当 EOL 在 .gitattributes 中设置为 CRLF 时,Git diff 认为行尾是 LF
【发布时间】:2017-03-21 14:08:13
【问题描述】:

当我恢复对具有 Windows 行结尾的文件的更改并且 .gitattributes 将 EOL 定义为 CRLF 时,git 认为行结尾已更改为 LR,即使十六进制编辑器显示 CRLF。

这仅在 .gitattributes 定义 EOL 字符时发生。

没有 .gitattributes:

这可以正常工作。

这是我的文件 Web.config 的原始版本。最后两个字符是0d 0a (CR LF)

00000000: efbb bf3c 3f78 6d6c 2076 6572 7369 6f6e  ...<?xml version
00000010: 3d22 312e 3022 2065 6e63 6f64 696e 673d  ="1.0" encoding=
00000020: 2275 7466 2d38 223f 3e0d 0a              "utf-8"?>..     

我在第一行的末尾添加了一个空格字符,20 0d 0a

00000000: efbb bf3c 3f78 6d6c 2076 6572 7369 6f6e  ...<?xml version
00000010: 3d22 312e 3022 2065 6e63 6f64 696e 673d  ="1.0" encoding=
00000020: 2275 7466 2d38 223f 3e20 0d0a            "utf-8"?> ..    

Git diff 显示空格字符:

diff --git a/Web.config b/Web.config
index bc3c3c3..6215f5e 100644
--- a/Web.config
+++ b/Web.config
@@ -1,4 +1,4 @@
<U+FEFF><?xml version="1.0" encoding="utf-8"?>{+ +}

还原文件,所有更改都消失了:

$ git checkout Web.config

$ git status Web.config
On branch develop
Your branch is up-to-date with 'origin/develop'.

nothing to commit, working directory clean

带有 .gitattributes

这不能正常工作。

将 CRLF 定义为 .gitattributes:

*.config eol=crlf

将空格字符添加到第一行的末尾:

00000000: efbb bf3c 3f78 6d6c 2076 6572 7369 6f6e  ...<?xml version
00000010: 3d22 312e 3022 2065 6e63 6f64 696e 673d  ="1.0" encoding=
00000020: 2275 7466 2d38 223f 3e20 0d0a            "utf-8"?> ..    

Git diff 显示空间,但缺少 CR (^M):

diff --git a/Web.config b/Web.config
index bc3c3c3..9d3bc53 100644
--- a/Web.config
+++ b/Web.config
@@ -1,248 +1,248 @@
<U+FEFF><?xml version="1.0" encoding="utf-8"?>[-^M-]{+ +}

还原文件:

$ git checkout Web.config

$ git status Web.config
On branch develop
Your branch is up-to-date with 'origin/develop'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   Web.config

no changes added to commit (use "git add" and/or "git commit -a")

Git 认为 CR 已从所有行中删除:

$ git diff --word-diff-regex=. Web.config
diff --git a/Web.config b/Web.config
index bc3c3c3..094d1d5 100644
--- a/Web.config
+++ b/Web.config
@@ -1,248 +1,248 @@
<U+FEFF><?xml version="1.0" encoding="utf-8"?>[-^M-]
<!--[-^M-]
  For more information on how to configure your ASP.NET application, please visit[-^M-]
  http://go.microsoft.com/fwlink/?LinkId=152368[-^M-]
  -->[-^M-]
<configuration>[-^M-]

但在十六进制编辑器中并非如此:

00000000: efbb bf3c 3f78 6d6c 2076 6572 7369 6f6e  ...<?xml version
00000010: 3d22 312e 3022 2065 6e63 6f64 696e 673d  ="1.0" encoding=
00000020: 2275 7466 2d38 223f 3e0d 0a3c 212d 2d0d  "utf-8"?>..<!--.
00000030: 0a20 2046 6f72 206d 6f72 6520 696e 666f  .  For more info
00000040: 726d 6174 696f 6e20 6f6e 2068 6f77 2074  rmation on how t
00000050: 6f20 636f 6e66 6967 7572 6520 796f 7572  o configure your
00000060: 2041 5350 2e4e 4554 2061 7070 6c69 6361   ASP.NET applica
00000070: 7469 6f6e 2c20 706c 6561 7365 2076 6973  tion, please vis
00000080: 6974 0d0a 2020 6874 7470 3a2f 2f67 6f2e  it..  http://go.
00000090: 6d69 6372 6f73 6f66 742e 636f 6d2f 6677  microsoft.com/fw
000000a0: 6c69 6e6b 2f3f 4c69 6e6b 4964 3d31 3532  link/?LinkId=152
000000b0: 3336 380d 0a20 202d 2d3e 0d0a 3c63 6f6e  368..  -->..<con
000000c0: 6669 6775 7261 7469 6f6e 3e0d 0a20 203c  figuration>..  <

这里发生了什么,如何让它正常工作?

【问题讨论】:

    标签: git


    【解决方案1】:

    这里的关键是,无论你使用text=autotext eol=crlf还是text eol=lf,git都会:

    1. 在存储库中将行尾转换为 LF(即在 git commit 上)
    2. 从 存储库到您的工作树(即在 git checkoutgit merge 上)

    这可能是违反直觉的,但请记住 git 起源于 Linux 世界,并不是一个错误。来自git documentation:“当一个文本文件被规范化时,它的行尾在存储库中被转换为LF”。

    因此,我发现当我加入现有项目并且需要引入 .gitattributes 来规范化行尾时,我发现最好编写一个 Powershell 脚本(或您喜欢的任何方法)来规范化行尾一次在存储库中的所有文件中。这是为了避免持续的混淆差异,其中唯一的变化是 .gitattributes 引入的行尾。

    最后,以防万一,我之前在我的 GitHub 上发布了一个沙盒来使用行尾设置:https://github.com/teamtam/git-line-endings

    【讨论】:

    • 我不确定行尾是否在提交时转换为 LR。我的 repo 中有一个文件有混合行结尾,大多数是 LR,但有几行是 CRLF。如果我没有设置 .gitattributes 并且我删除并重新签出文件,我可以在十六进制编辑器中看到混合行结尾; git diff 显示没有变化。如果我在 .gitattributes 中将行尾设置为 CRLF,删除文件并再次签出,所有行都将转换为 CRLF,但 git diff 显示原来 CRLF 的行已更改(CR 已删除)。它不会显示 LF 和已更改为 CRLF 的行的任何更改。
    • 当我提到“存储库”时,我指的是你通常不会触及的内部 git 工作 - 即(隐藏的).git 文件夹。因此,当您使用 .gitattributes 文本集进行提交时,我的理解是它会删除存储库中的 CR,但您的工作树副本(即您实际使用的文件)保持不变。这意味着您在结帐时会注意到,当时存储库中的任何内容都将转换为您指定的格式,无论是 auto、crlf 还是 lf。
    • 这其实是最准确的答案。简而言之,如果您在.gitattributes 中制作了一些CRLF 文件text,则应将其转换为blob 中的LF。
    【解决方案2】:

    这是我遇到过的 git 上的一个错误。您可以向git 团队举报:

    可以使用电子邮件地址 git@vger.kernel.org 将 Git 社区的问题或 cmets 发送到邮件列表。 git 的错误报告应该发送到这个邮件列表。

    https://git-scm.com/community

    如果您使用的是Windows,您还可以尝试打开以下错误报告:

    1. https://github.com/git-for-windows/git/issues

    可能这个错误已在最新版本的 git 2.10.2 上修复,如果还没有,您可以将您的更新到最新版本:

    1. https://en.wikipedia.org/wiki/Git

    【讨论】:

    【解决方案3】:

    首先检查您的git config core.autocrlf 值。

    为确保您的 .gitattributes 指令是唯一要应用的指令,请确保键入:

    git config --global core.autocrlf false
    

    然后再次克隆您的 Git 存储库并查看问题是否仍然存在。

    【讨论】:

    • core.autocrlf 未在系统、全局或本地配置中设置。我在全局中将其设置为 false,然后完全删除存储库并再次克隆。我在第一行的末尾添加了空格字符并保存了,但是 git diff 显示每一行都删除了它的 CR,即使我可以在十六进制编辑器中看到它,所以与原始问题没有任何变化。
    • .gitattributes 优先于本地或全局配置
    【解决方案4】:

    要在我正在使用的 Windows 上使用 unix 行尾:

    git config --global core.autocrlf input
    git config --global core.eol lf
    

    所以在你的情况下你应该设置:

    git config --global core.autocrlf input
    git config --global core.eol crlf
    

    您显然可以针对特定文件夹执行此操作,而不是像我上面显示的那样全局执行此操作

    【讨论】:

    • 是的,问题是当我将行结尾设置为 CRLF 时,git diff 认为任何最初具有 CRLF 行结尾的文件都已被修改并删除了 CR,即使我可以在其中看到它十六进制编辑器,我告诉它应该是 CRLF。
    • .gitattributes 优先于本地或全局配置
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-16
    • 1970-01-01
    • 2017-10-25
    • 2021-09-06
    • 2020-10-03
    相关资源
    最近更新 更多