Git text=auto-core.autocrlf=false在Windows上给出CRLF



这怎么可能?我有一个.gitattributes与以下内容

* text=auto

更新:嗯。原来是.gitattributes文件导致了这种行为。有人能解释这一点或指出相关文件吗?

设置.gitattributes后,使用git add --renormalize .(来自包含这些*.sh*.bash文件的目录)或git add --renormalize *.sh *.bash在提交之前更新文件。或者,使用touch *.sh *.bash; git checkout -f *.sh *.bash更新工作树副本。

这是怎么回事

毫无疑问,您已经知道,Git存储库包含提交。每个提交都有一个已提交的每个文件的冻结副本,其状态与您(或任何人)提交时的状态完全相同。此冻结副本永远无法更改,因此,如果它有CRLF行结尾,它将永远拥有这些行结尾,如果它只有LF行末尾,它将永久拥有它们。该文件的任何其他副本,在任何其他future提交中,都可能不同,但this提交中的复制被冻结。(任何其他现有提交中的任何副本当然也会被冻结,但可能会有所不同。)

在内部,每个提交的文件都是一种特殊的、仅限Git的格式,压缩后只能由Git使用——一旦提交,就会在特定的提交中永久冻结。当然,您可以通过提取提交的文件来查看这些文件;您可以制作新的提交文件,使用您可以修改的提取文件。因此,Git需要两个操作:

  • 将文件提交,复制到,在那里您可以进行操作;以及
  • 将文件从您处理过的复制到(准备好)提交

正是这两个操作实际上只执行任何CRLF到LF,反之亦然。

存放您使用和处理的文件版本的地方被称为工作树(或其变体,如的工作树>的工作目录),这也许并不奇怪。您使用并处理工作树中的文件。您告诉Git将文件复制到提交,或者将文件复制到(准备好)提交。

索引

这里还有一个额外的问题,那就是Git根本不会从你的工作树中进行提交。相反,Git在提交和工作树之间插入第三个保存区域。Git将其称为索引暂存区,有时也称为缓存(取决于Git的谁/哪个部分在进行调用)。

索引中的文件总是准备提交。也就是说,它们具有与提交中相同的特殊、压缩、仅Git格式。这就是git commit如此快速的诀窍(与其他版本控制系统相比):一切都在任何时候——或者几乎所有时候——准备就绪。当您运行git commit时,Git甚至不会查看工作树。它只是将索引中的文件以现在的形式打包,所有文件都经过压缩和Git化,可以使用了。

git add命令将文件从工作树复制到索引中,使其可以使用。相比之下,git checkout命令会将文件中复制到索引中,以便为下一次提交做好准备,然后再复制到工作树中。

这就是为什么您需要git add --renormalize

假设某个文件以某种方式(有或没有CRLF结尾)存储在提交中。您可以运行git checkoutname来选择一个分支及其提示提交。提交中的文件进入索引,然后从那里进入工作树。复制出步骤——索引到工作树——将文件更改为有人告诉Git使用的行结尾,可能是通过您刚刚签出的提交中的.gitattributes文件。

如果错误,则现在更改.gitattributes文件1这可能会改变文件在下一次提交中的方式。它可能会改变文件在工作树中的方式。但是——问题是——Git已经以它认为正确的方式在索引和工作树中拥有了文件

此外,还有更糟糕的问题:Git不仅以其认为正确的方式拥有文件,而且认为不需要对它们进行任何新的工作如果你现在在它们上运行git checkoutgit add,Git会聪明地注意到工作树副本没有被触摸,什么也不做,即使重新签出或重新添加会有不同的效果!

结果是,实际上,你必须欺骗Git重做工作。如果你需要根据"从索引到工作树"的顺序更新一些或所有工作树文件,你可以为每个这样的文件:

  • 删除工作树副本并再次运行git checkout,或者
  • touch复制工作树(这样Git就会认为你已经修改了它),并运行git checkout -f强制覆盖它们

如果您需要根据"从工作树到索引"的顺序更新部分或全部工作树文件,您可以:

  • touch复制工作树(以便Git认为您已经修改了它)并运行git add,或者
  • 使用新的ishgit add --renormalize来强制Git重新添加文件,即使它可以看到你没有接触过它们

如果您的Git太旧,无法使用git add --renormalize,则可以使用touch方法。


1这对core.autocrlfcore.eol都适用,但在这里,使用.gitattributes文件进行更精细的控制几乎总是最好的。例如,Git维护者为Git本身做这件事。

git文档对core.autocrlf和.gitattributes如何一起发挥作用含糊其辞:

文本

此属性启用并控制行尾规范化。当一个文本文件被规范化时,它的行尾在存储库中被转换为LF。要控制工作目录中使用的行尾样式,请对单个文件使用eol属性,对所有文本文件使用core.eol配置变量。请注意,core.autocrlf会覆盖core.eol

如果我们有以下,Note that core.autocrlf overrides core.eol是什么意思

core.eol

当core.autocrlf为false时,为设置了text属性的文件设置要在工作目录中使用的换行类型。备选方案是lf、crlf和native,后者使用平台的native行结尾。默认值为本机值。有关行尾转换的更多信息,请参见gitattributes[5]。

这句话说我看到的是一个预期行为,因为默认情况下core.eolnative,而我有core.autocrlf=false

UPDATE:这确实是一种预期行为,core.eol仅适用于设置了text位属性的文件,并且当autocrlf=false时。可以说,使用autocrlf=false* text=auto触发自动换行转换(在默认core.eol的Windows上,结果与autocrlf=true相同)。

文件很模糊,但可能很快就会得到改进。

最新更新