【发布时间】:2019-01-26 20:59:35
【问题描述】:
这怎么可能? 我有一个包含以下内容的 .gitattributes
* text=auto
更新: 嗯。事实证明,导致这种行为的是 .gitattributes 文件。有人可以解释一下或指向相关文档吗?
【问题讨论】:
标签: git
这怎么可能? 我有一个包含以下内容的 .gitattributes
* text=auto
更新: 嗯。事实证明,导致这种行为的是 .gitattributes 文件。有人可以解释一下或指向相关文档吗?
【问题讨论】:
标签: git
设置.gitattributes 后,使用git add --renormalize .(来自包含这些*.sh 和*.bash 文件的目录)或git add --renormalize *.sh *.bash 在提交前更新文件。或者,使用 touch *.sh *.bash; git checkout -f *.sh *.bash 更新工作树副本。
您无疑已经知道,Git 存储库包含提交。每个提交都有一个已提交文件的冻结副本,与您(或任何人)提交时的状态完全相同。 这个冻结的副本永远无法更改, 因此,如果它有 CRLF 行结尾,它就会永远拥有它们,如果它只有 LF 行结尾,它就会永远拥有它们。该文件的任何 other 副本,在任何 other 未来的提交中,可以是不同的,但 this 副本在 this提交被冻结。 (任何其他现有提交中的任何副本当然也会被冻结,但可能会有所不同。)
在内部,每个提交的文件都是一种特殊的、仅限 Git 的格式,只能由 Git 压缩和使用——一旦提交,就会在该特定提交中永久冻结。但当然,您可以查看已提交的文件,方法是提取它们;并且您可以制作 new 已提交的文件,使用您可以修改的提取文件。因此,Git 需要两个操作:
这两个操作实际上只执行任何 CRLF-to-LF-only 或反之亦然。
保存您使用和处理的文件版本的地方也许毫不奇怪,称为 work-tree(或它的一些变体,例如 working tree em> 或 工作目录)。您使用并处理您的工作树 中的文件。你告诉 Git 复制文件 from 一个提交,to 工作树,或者复制文件 from 工作树,到(准备好)提交。
这里有一个额外的问题,那就是 Git 根本不会根据您的工作树中的内容进行提交。相反,Git 在提交和工作树之间插入了第三个保存区域。 Git 将其称为 index、staging area,有时也称为 cache,具体取决于 Git 的谁/哪个部分在执行调用。
索引中的文件总是准备好提交。也就是说,它们具有与提交相同的特殊、压缩、仅 Git 格式。这就是使git commit 如此快速的诀窍(无论如何与其他版本控制系统相比):一切都在任何时候——或者几乎所有时候——准备就绪。当您运行git commit 时,Git 甚至不会查看 工作树。它只是打包索引中的文件,以它们现在的形式,所有压缩和 Git 化并准备就绪。
git add 命令复制文件从工作树,到索引,使它们准备就绪。相比之下,git checkout 命令将文件从一个提交(您要签出的那个)首先复制到索引中,以便它们为下一个做好准备提交,然后进入工作树。
git add --renormalize
假设某个文件以某种方式(带有或不带有 CRLF 结尾)存储在提交中。您运行git checkout <em>name</em> 来选择一个分支及其提示提交。该提交中的文件进入索引,然后从那里进入工作树。复制出步骤(工作树的索引)将文件更改为有人告诉 Git 使用的行结尾,可能是通过您刚刚签出的提交中的 .gitattributes 文件。
如果这些错误,您现在更改.gitattributes 文件。1这也许会改变文件应该的方式在下一次提交中。它可能会改变文件应该在工作树中的方式。但是——这就是问题所在——Git 已经以它认为正确的方式在索引和工作树中保存了文件。
此外,更糟糕的问题是:Git 不仅以它认为正确的方式拥有文件,它还认为它不需要对它们做任何新的工作。 如果你现在对它们运行git checkout 或git add,Git 会巧妙地注意到工作树副本没有被触及并且什么都不做,即使重新结帐或重新添加会做一些不同的事情!
结果是,实际上,您必须欺骗 Git 重做工作。如果您需要根据“从索引到工作树”顺序更新部分或全部工作树文件,您可以针对每个此类文件:
git checkout,或者touch 工作树副本(以便 Git 认为您已修改它)并运行 git checkout -f 以强制覆盖它们。如果您需要根据“从工作树到索引”的顺序更新部分或全部工作树文件,您可以:
touch 工作树副本(以便 Git 认为您已修改它)并运行 git add,或者git add --renormalize 强制 Git 重新添加文件,即使它可以看到您没有触摸它们。如果您的 Git 太旧而无法使用 git add --renormalize,您可以使用 touch 方法。
1这对core.autocrlf 和core.eol 也适用,但最好使用.gitattributes 文件在此处进行更精细的控制。例如,Git 维护人员为 Git 本身执行此操作。
【讨论】:
git add --renormalize。 (注意:我自己没有 Windows,我最多只能在 MacOS / Linux 等上模拟它。)如果您将您的六个步骤编辑成某人可以运行的脚本,并将其放入您的问题中,这将有助于某人-否则重现您的问题。
git add --renormalize . git status 是nothing to commit, working tree clean
eol=lf。我假设您最初想要并且拥有 CRLF 行尾,因为设置 core.autocrlf = input 告诉 Git 只执行工作树到索引复制行尾更改。 (其他系统最初会希望并具有仅 LF 结尾。)在 .gitattributes 中设置 eol=lf 还会设置工作树到索引的转换,git add --renormalize 应该遵守该转换。同时* text=auto 应该有no 效果,因为text=auto 是默认值。所以这似乎令人费解。
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,它们使用平台的本机行尾。默认值为原生。有关行尾转换的更多信息,请参阅 gitattributes[5]。
此声明表明我看到的是预期行为,因为默认情况下core.eol 是native,而我有core.autocrlf=false。
更新:
这确实是一种预期行为,core.eol 仅适用于设置了text git 属性的文件以及当autocrlf=false 时。可以说,使用autocrlf=false * text=auto 触发器 自动换行符(在默认为core.eol 的Windows 上,结果与autocrlf=true 相同)。
文档含糊不清,但可能很快会得到改进。
【讨论】:
*text=auto 是添加 git 属性的特定选项,应该将您的行尾转换为 lf。据我所知,您会看到 crlf 的唯一情况是,如果您在更改配置(更改为 auto.crlf=false、*text=auto)之前已经使用 crlf 提交了文件,然后您之后没有提交任何更改(仅签出)。
autocrlf=false * text=auto 触发自动换行"。实际上,可以说* text=auto 会触发自动换行符,而不管core.autocrlf。它明确地在那里覆盖core.autocrlf。
auto 启用输入和输出转换。但是对于输出,它是 core.eol 或 core.autocrlf(如果不是 false)决定使用的分隔符。
.gitattributes检查你的配置。如果要设置特定的行尾,请设置eol 属性。