Git 索引和工作树 EOL 值与 .gitattributes 中设置的值不匹配
Posted
技术标签:
【中文标题】Git 索引和工作树 EOL 值与 .gitattributes 中设置的值不匹配【英文标题】:Git index and working-tree EOL values do not match those set in .gitattributes 【发布时间】:2022-01-19 16:34:23 【问题描述】:我在 Windows 上,通过 git bash
CLI 使用 git
。我有一个使用UTF-8
编码的.java
文件,我从旧的svn
服务器导入到git
。我的同事也在 Windows 上,但使用 Eclipse IDE 中的 git
客户端,经常抱怨这个特定文件在结帐时有空格更改(即没有任何手动修改)。我相信问题与git
将文件视为二进制文件有关,但我不确定。 ls-files --eol
的输出为:
$ git ls-files --eol -- src/Props.java
i/-text w/-text attr/text=auto eol=crlf src/Props.java
以上似乎表明git
认为文件的存储版本是二进制的(i/-text w/-text
位),但也识别存储库中的属性设置(attr/text=auto eol=crlf
位)。这怎么可能?有没有办法修复它,以便存储在索引/工作树中的是crlf
?我是否正在寻找正确的地方来解决这个问题?
【问题讨论】:
text=auto
告诉 Git 猜测。您看到的输出表明 Git 确实猜到了,它的猜测是“这些是二进制文件”。猜测是不可配置的,但您可以强制 Git 相信文件是文本(或不是文本),text
或 -text
在 .gitattributes
中。但是,如果 Git 猜测该文件是二进制文件,则它可能不是文本(例如,它可能存储为 UTF16,对于 Git 来说不是文本,如果将其视为文本并进行 EOL 转换,它可能会损坏 Git )。
很难判断文件是否已被某些错误的 Windows 软件从 UTF-8 转换为 UTF-16-LE,因为检查文件的其他软件会发现它是 UTF-16 -LE,将其转换为 UTF-8,然后检查它并自豪地宣布该文件现在是 UTF-8。当你的工具对你撒谎时——许多现代工具都会撒谎——事情就会变得困难。
好的,假设我真的想告诉git
将此文件视为text
并以crlf
行结尾。我需要某种方法来确定编码是什么,然后用某种方法替换那些欺骗git
相信它是二进制的字符,对吧?关于如何做这两件事的想法?我完全控制了这个文件,它不需要是 UTF-16(或任何其他特殊编码),所以手动修改文件不是问题。 (FWIW,Notepad++
认为它是 UTF-8 而file -i Props.java
给出了text/x-java; charset=us-ascii
)
如果文件真的是文本,奇怪的是 Git 会猜错,但只需将 .gitattributes
中的 text=auto
更改为 text
就会告诉 Git 文件是文本。 (更改或添加的内容取决于.gitattributes
文件中已有的内容:如果您有* text=auto
,您可以在其下方添加*.java text
以覆盖.java
文件,例如。添加eol=crlf
以制作Git 在从存储库到工作树的途中将 \n 转为 \r\n,并且仅在从工作树到存储库的途中将 \r\n 转为 \n,如果这是你想要的。)
请注意,不同的eol=
设置指导Git在退出时是否做\n => \r\n,以及是否做\r\n => \n方式。设置是:两者都做,或者只做输入到存储库端(\r\n => \n)的转换。这些是唯一可用的转换选项:例如,在进入存储库选项的过程中没有 \n 到 \r\n。 -text
(或binary
)表示放手,text
表示放手,eol=
设置转换。
【参考方案1】:
当你使用text=auto
时,它要求 Git 查看文件,如果它在文件开头的一定字节数内找到任何 NUL 字节,它认为文件是二进制的,否则它认为文件为文本。通常这种方法效果很好,但有时效果不佳。
如果您使用的是 UTF-16,则不是这样的地方之一。这在 Windows 上非常流行,并且仍在某些编程语言中使用,但通常被认为在其他任何地方都已过时,转而支持 UTF-8。带有 ASCII 范围字符(即大多数英文文本和编程语言)的 UTF-16 将包含 NUL 字节,这将使 Git 认为文本是二进制的。请注意,对于 Git,任何 LF 和 CR 字符由它们在 US-ASCII 中的值以外的值(如 UTF-16 中的两字节序列)表示的任何东西都是二进制的,并且强制在那里进行文本转换会破坏事情。
如果这些文件确实是某种与 ASCII 兼容的编码(例如,UTF-8)并且您想强制 Git 将这些文件检测为文本,您可以修改您的 .gitattributes
文件:
*.java text
如果您还希望 EOL 为 CRLF,请执行以下操作:
*.java text eol=crlf
任何时候你将 Git 设置为执行文本转换,它都会将 LF 结尾存储在存储库中。无论工作树的结尾如何,这都是您想要的,因为它可以使git diff
之类的工具更好地工作,而无需担心您的尾随空格(CR)。设置 eol=crlf
只是强制它成为工作树中的 CRLF,这将是大多数程序工作所需要的。
请注意,一般来说,建议只是让人们使用他们喜欢的行尾,并且仅在需要功能时设置行尾,例如用于 shell 脚本的 LF 和用于批处理脚本的 CRLF,其中的替代方法是它只是行不通。但是,在某些环境中工具会导致问题,因此您可能希望在这些环境中也设置配置。
【讨论】:
以上是关于Git 索引和工作树 EOL 值与 .gitattributes 中设置的值不匹配的主要内容,如果未能解决你的问题,请参考以下文章