为什么 Git 想要将我的行结尾更正为 CRLF,即使我希望它们是 LF?

Mär*_*Mär 6 git line-endings core.autocrlf

在一个相对较大的项目中,使用签出CRLF和提交LF的策略。为此,我的系统使用:

git config --global core.autocrlf true
Run Code Online (Sandbox Code Playgroud)

但是,当提交文件(在本例中为.gitattributes文件)时,会返回警告:

LF would be replaced by CRLF in .gitattributes
Run Code Online (Sandbox Code Playgroud)

文件.gitattributes本身包含该行* text=auto !eol,并且文件本身使用 LF 行结尾。

为什么会发生这种情况?为什么 Git 告诉我要小心,因为它会将 LF 转换为 CRLF,即使我希望此文件在存储库中以 LF 结尾进行规范化?

我一定错过了一些完全明显的东西,因为我已经经历过:

还有更多,但这仍然没有像我想象的那样工作。

tor*_*rek 4

让我们分几个部分来看看:

\n\n
    \n
  • !eol这里没有任何功能。这设置eolunspecified,但这已经是默认值,并且未指定的值eol不会禁用 LF 到 CRLF 转换。

  • \n
  • 由于您确实指定了text=auto,Git 将检查 的内容是否.gitattributes显示为文本或二进制,当然它们应该显示为文本。

  • \n
\n\n

因此,这个特定条目告诉 Git 它应该.gitattributes.

\n\n

同时,认识到行结束变换是一般清理和涂抹过滤器概念的特例是有用的。 VonC 在您的第三个链接中接受的答案有一个很好的图画,说明了污迹过滤器的工作方式,但缺少说明清洁过滤器如何工作的图,所以让我们深入探讨这一点,并了解一些背景知识。

\n\n

Git 化(“冻干”)与工作树(“再水化”)文件以及索引

\n\n

Git 的正常1 个原子存储单元是提交。提交保存源树的完整快照(加上我不会在此处介绍的提交元数据)。出于许多充分的原因,提交中的文件以压缩、冻结、只读和仅限 Git 的存储格式保存。我最近开始将这些文件称为“冻干”。这有助于将它们与您实际使用的文件区分开来。

\n\n

与 Git 内部键值对象数据库中的所有内容一样,这些提交及其文件都是只读的。这意味着它们将永远保留(或者只要提交本身继续存在),这对于存档很有用,但对于完成任何工作完全没有用。因此 Git 必须提供一种方法来“重新水化”文件,将它们变成可以使用的普通文件。

\n\n

你的工作树是 Git 放置重新水化文件的地方。它们有普通的形式,在普通的文件中,用普通的名字。计算机上的每个程序都可以处理它们,并且您可以随心所欲地操纵它们。

\n\n

Git可以停在这里:你将拥有冻结的提交文件和可延展的工作树文件,Git 将从工作树构建新的提交。Mercurial 在很多方面与 Git 非常相似,但仅限于此。但 Git 并不止于此。相反,它继续在当前冻结的提交和工作树之间添加一个中介。这个中介就是 Git 的索引。Git 有时将其称为暂存区缓存,具体取决于谁/Git 文档的哪一部分正在执行调用。不过,这三个都是同一实体的名称。

\n\n

索引/暂存区域仅保存每个文件的额外副本。这个额外副本的格式是冻干的、内部的、仅限 Git 的存储格式这种格式的文件会在具有相同文件的所有提交之间自动共享,因此这意味着当索引中的副本与任何提交中的副本相同时,它实际上提交共享。

\n\n

这也意味着git commit,必须冻干每个文件才能永久存储它,实际上几乎是零工作:文件已经冻干了! 当您运行 时,冷冻干燥过程发生得较早git add。这就是 Git 速度提升的主要原因。这也是Git 一直要求您这样做的原因git add2 请注意,这意味着当您运行时git commitGit 甚至不需要查看您的工作树。 (不过,默认情况下它仍然会快速运行一半git status,为您的提交消息创建注释文本。)

\n\n
\n\n

1我在这里说正常是因为 Git 还通过所谓的blob对象提供对简单键值存储的低级访问。但是,要使用它,您必须诉诸于使用一些所谓的管道命令,而不是至少在理论上用户友好的命令。:-)

\n\n

2 Mercurial 使用工作树作为建议的下一次提交,不需要您保留hg add文件。完成初始操作后hg add,系统会hg commit扫描您的工作树并提交您所做的任何更改。这对于新人来说就友好多了,但是这也意味着在一个大项目中,当你跑的时候hg commit,要做好等待的准备。

\n\n
\n\n

索引/暂存区在行结束转换中的作用

\n\n

请记住,索引存储每个文件的冻干、Git 化副本。这意味着索引到工作树的“补充”步骤是进行任何您想要完成的转换的好地方。这就是链接答案中的污迹过滤器的用武之地:污迹过滤器可以修改提交的文本,以便工作树文本更有用。

\n\n

同样,工作树到索引的“冷冻干燥”步骤\xe2\x80\x94(运行git add\xe2\x80\x94时发生的步骤)是进行任何你想要完成的转换的好地方。这就是干净过滤器的用武之地:干净过滤器可以删除不应该进入存储库中实际提交的内容。

\n\n

Git 中的行结束转换只是 clean 和 smudge 过滤器的特例。冻干的存储库内文件可以具有您喜欢的任何行结尾。3例如 ,当我们让 Git 将文件索引/暂存区域复制工作树时git checkout,我们可以让 Git 将这些行结尾从仅 LF更改为 CRLF。当我们让 Git 将该文件工作树复制索引/暂存区域时,我们可以让 Git 将这些行结尾从 CRLF更改为仅 LF。

\n\n

这是文本文件的默认 CRLF 转换。这些转换会将仅 LF 冻干文件更改为 CRLF 再水化文件,并将 CRLF 再水化文件更改为仅 LF 冻干文件。

\n\n

只要 Git 检测到这可能会执行与已经执行的操作不同的操作,您就应该收到警告。.gitattributes因此,假设您的工作树中的文件现在只有 LF 行结尾。进一步假设提交和/或索引/暂存区域中的冻干副本也具有仅 LF 行结尾。假设指令说索引 -> 工作树应该将 LF-only 更改为 CRLF:那么,为什么有些东西很奇怪,Git 应该发出警告。

\n\n

我发现这些警告有时有点令人兴奋。我无法将其归咎于特定 Git 版本中的特定情况,因为我自己尽最大努力永远不会让 Git 摆弄我的数据。我希望工作树副本每次都与冻干副本相匹配,因为我避免使用需要愚蠢的行结束特殊性的操作系统。但上面是一般规则,你现在收到的警告是有道理的:实际的冻干文件工作树文件现在只有 LF 行结尾,但你的设置告诉 Git 的文本应该有已转换为在工作树中具有 CRLF 行结尾。.gitattributes

\n\n
\n\n

3 Linus Torvalds 要求您应该喜欢仅 LF 的行结尾。:-) 开玩笑吧,Git 有点喜欢这个。如果您通过根本不启用 CRLF 或将所有文件标记为 来禁用所有转换\xe2\x80\x94 -text,Git 将永久存储\xe2\x80\x94!\xe2\x80\x94 无论您说什么行结尾。如果您随后改变主意,您将陷入已经冻结的行结尾,因为任何提交中的任何内容都无法更改。 如果这些提交是错误的,您唯一能做的就是停止使用它们。您可以创建新的、改进的、更正的并使用它们。

\n\n

我认为正是这些“冻结提交的副本是错误的,因为它有 CRLF 结尾”的情况通常会触发虚假的 CRLF 行结尾警告问题。由于我自己实际上并没有使用行结束转换代码,因此很难确定这一点。

\n