与一个相对较大的项目一起使用时,将使用签出CRLF和提交LF的策略。为此,我的系统使用:
git config --global core.autocrlf true
但是,在提交文件(在这种情况下为.gitattributes
文件)时,会返回警告:
LF would be replaced by CRLF in .gitattributes
.gitattributes
文件本身包含* text=auto !eol
行,并且文件本身使用LF行尾。
为什么会这样?为什么Git告诉我要小心,因为它会将LF转换为CRLF,即使我希望将此文件在存储库中以LF结尾进行规范化?
自从我经历过之后,我肯定会错过一些显而易见的东西
还有更多,但这仍然无法达到我的预期。
答案 0 :(得分:4)
让我们从几个方面来看这个问题:
!eol
在这里没有功能。这会将eol
设置为unspecified
,但这已经是默认设置,并且未指定的值eol
不会禁用LF到CRLF的转换。
由于您确实指定了text=auto
,因此Git将检查.gitattributes
的内容是文本还是二进制,当然它们应该是文本。
因此,此特定条目告诉Git它应该在.gitattributes
上执行翻译。
同时,认识到行尾转换是常规清理和污迹过滤器概念的特例是很有用的。 VonC's accepted answer at your third link很好地描绘了 smudge过滤器的工作方式,但是缺少 clean 过滤器的工作方式,因此让我们深入了解一下背景。
Git的常规 1 原子存储单元是提交。提交包含源树的完整快照(加上我不会在此处提交的提交元数据)。由于许多充分的原因,提交中的文件以压缩,冻结,只读和仅Git的存储格式保存。我最近开始将这些文件称为 freeze-dried 。这有助于将它们与您实际在/上使用的文件区分开。
就像Git内部键值对象数据库中的所有内容一样,这些提交及其文件都是只读的。这意味着它们将被永久保存(或者只要提交本身继续存在就保留),这对于存档非常有用,但是对于完成任何 new 工作完全没有用。因此,Git必须提供一种“补水”文件的方法,将其转换为可以使用的普通文件。
您的工作树是Git存放重新水化文件的地方。它们具有普通格式,以普通文件名存在于普通文件中。您计算机上的每个程序都可以处理它们,您可以根据需要对其进行操作。
Git 可以在这里停止:您将拥有冻结的已提交文件和可延展的工作树文件,而Git将从工作树中构建 new 提交。 Mercurial在许多方面与Git非常相似,确实就在这里停止。但是,Git并不止于此。取而代之的是,它继续将一个中介放入当前冻结的提交和工作树之间的中间。该中介是Git的 index 。 Git有时将其称为暂存区域或缓存,具体取决于Git文档的谁/哪个部分进行调用。不过,这三个都是相同实体的名称。
索引/暂存区仅保存每个文件的额外副本。此额外副本的 format 是冻结干燥的内部仅Git的存储格式。这种格式的文件会在所有具有相同文件的提交中自动共享,因此这意味着当 in 中的副本与任何提交中的副本相同时,索引,它实际上是与共享提交。
这也意味着git commit
(必须永久冻结每个文件才能永久存储)实际上要执行的工作几乎为零:文件已经被冻干了!冷冻干燥过程早于您运行git add
时进行。这就是让Git发挥最大速度的原因。这也是为什么 Git一直要求您git add
。 2 注意,这意味着当您运行git commit
时, Git甚至不需要查看您的工作树。(尽管默认情况下,它仍会运行git status
的一半,以创建提交消息的注释文本。)>
1 我在这里说 normal 是因为Git还通过其称为 blob 对象提供了对简单键值存储的低级访问。但是,要使用此命令,您必须求助于使用某些所谓的 plumbing 命令,而不是至少在理论上讲是用户友好的命令。 :-)
2 Mercurial使用工作树作为建议的下一次提交,不需要要求您保持hg add
-处理文件。完成初始hg add
后,hg commit
将扫描您的工作树并提交您所做的更改。这对新来者来说是友好的,但这也意味着在大型项目中,当您运行hg commit
时,请准备好等待。
请记住,索引存储了每个文件的冻干,Git格式的副本。这意味着索引到工作树的“补水”步骤是绝佳的地方,可以进行您想要进行的任何转换。这是链接答案中的污迹过滤器出现的地方:污迹过滤器可以修改提交的文本,以便工作树文本更有用。
同样,工作树到索引的“冻结-干燥”步骤(运行git add
时发生的步骤)是执行任何所需转换的好位置完成。这是干净过滤器的来源:干净过滤器可以删除不应放入存储库中实际提交的内容。
在Git中,行尾转换只是清洁过滤器和污迹过滤器的特例。冻结干燥的存储库文件可以具有您喜欢的任何行结尾。 3 当我们使用Git将文件从的索引/临时区域复制到时, 工作树,例如,在git checkout
期间,我们可以让Git change 那些行尾从仅LF到CRLF。当我们让Git从工作树 复制文件到索引/临时区域时,我们可以让Git change 这些行结尾从从CRLF到仅限LF。
这是文本文件的CRLF转换的默认设置。这些转换将把仅LF冻干的文件更改为CRLF复水文件,并将CRLF复水文件更改为仅LF的冻干文件。
您应该应该在Git检测到可能会执行与已完成的操作不同的警告时得到警告。因此,假设当前工作树 中.gitattributes
中的文件具有仅LF行尾。进一步假设,提交和/或索引/分段区域中的冻干副本也具有仅LF的行结尾。并假设指令说index-> work-tree应该将仅LF更改为CRLF:那么,为什么有些杂乱无章,而Git应该发出警告。
我发现这些警告有时会让人有些高兴。我无法将其固定到特定Git版本中的特定情况,因为我本人会尽力永远不要让Git弄弄我的数据。我希望工作树副本每次都与冻干副本匹配,因为我避免使用那些需要愚蠢的行尾特殊性的操作系统。但是以上是一般规则,您现在得到的警告是有道理的:实际的冻干文件 和工作树文件 all 仅具有LF行结束符现在,但是您的设置告诉Git,.gitattributes
中的文本应该已经转换为在工作树中具有CRLF行结束符。
3 ,Linus Torvalds要求您喜欢纯LF行尾。 :-)开个玩笑,Git更喜欢这个。如果禁用所有转换(通过根本不启用CRLF或将所有文件标记为-text
),则Git将永久存储!无论您说什么结尾的行。如果您随后改变主意,您将被已经冻结的行尾卡住,因为任何提交中的任何内容都无法更改。提交是错误的,您唯一可以做的就是停止使用它们。您可以制作新的,改进的,更正的,然后改用它们。
我认为正是这些“冻结的提交的副本是错误的,因为它具有CRLF结尾”的情况通常会触发伪造的CRLF行结尾警告问题。由于我自己实际上并没有使用行尾转换代码,因此很难确定。