.gitattributes 中的`* text=auto` 和`* text eol=lf` 有什么区别?

What is the differrence between `* text=auto` and `* text eol=lf` in .gitattributes?

我一次又一次地查看 .gitattributes 的文档,但我找不到关于这两者之间区别的明确答案:

* text=auto

* text eol=lf

此外,text=auto 是仅用于 * 还是也可以与特定扩展一起使用?在这种情况下有什么区别?

*.txt text=auto

*.txt text eol=lf

TL;DR

eol=lf 设置会覆盖任何 text 设置,并且由于您已选择将此应用到每个路径,因此只有 eol=lf 设置才重要,如果您使用它的话。

完整解释

让我们从这里开始并向外工作:

Also is text=auto intended only for use with * or it can also be used with specific extensions?

模式可能包含扩展。 text=auto 部分是 属性设置 ,模式 select 哪些属性应用于哪个文件。

Git 如何读取 .gitattributes 文件

gitattributes 中的每一行匹配或不匹配某些路径名,例如 dir1/dir2/file.extREADME.md 或其他任何名称。正如 gitattributes documentation 所说:

Each line in gitattributes file is of form:

pattern attr1 attr2 ...

That is, a pattern followed by an attributes list, separated by whitespaces. Leading and trailing whitespaces are ignored. Lines that begin with # are ignored. Patterns that begin with a double quote are quoted in C style. When the pattern matches the path in question, the attributes listed on the line are given to the path.

因此,* 模式 。这些“模式”与 .gitignore 文件中的相同,只是不允许使用负模式。因此,您可以使用 *.txt*.jpg 等模式来匹配文件扩展名,或使用 dir1/* 等模式来匹配特定目录中的文件。 .gitignore.gitattributes 文件也可以是特定目录的本地文件,在这种情况下,它们适用于该目录及其子目录中的文件,但不适用于树中更高的路径。

现在,对于 texttext=auto,以及对于 eol=lf 与否,我们发现以下内容:

Each attribute can be in one of these states for a given path:

Set
The path has the attribute with special value "true"; this is specified by listing only the name of the attribute in the attribute list.

Unset [details snipped, but see below]

Set to a value
The path has the attribute with specified string value; this is specified by listing the name of the attribute followed by an equal sign = and its value in the attribute list.

Unspecified
No pattern matches the path, and nothing says if the path has or does not have the attribute, the attribute for the path is said to be Unspecified.

(在我看来,最后一个的措辞特别糟糕。它的真正意思是“在所有匹配路径的模式中”,none 说了关于这个属性的任何事情。)

所以对于text,属性是设置,对于text=auto,属性是设置一个值。本例中的 value 部分是 auto。由于模式是 *,它适用于所有文件。

同样的逻辑也适用于 eol=lf 项目。如果,首先,这个 eol=lf 出现在某个模式中,其次,该模式与有问题的文件匹配,那么 eol 属性被设置为一个值,该值为 lf。由于您建议的行是 * text eol=lf,这将使 eol 设置为一个值 ,并使 text 设置 ,但未设置值

如果您在单个 .gitattributes 文件中写入 两行序列 :

* text=auto
* text eol=lf

第二行的 text 覆盖第一行,因此 textset(但不是一个值)和 eol 设置为一个值,值为lf。两行匹配,第二行覆盖第一行。

如果你反转两行:

* text eol=lf
* text=auto

然后两行匹配但现在第二行只覆盖text设置,所以现在你有text设置将autoeol设为lf.

text 属性如何应用于文件

gitattributes documentation 的下一部分说:

This attribute [text] enables and controls end-of-line normalization... [If it is]

Set
... enables end-of-line normalization and marks the path as a text file ...

Unset
... tells Git not to attempt any end-of-line conversion upon checkin or checkout ...

Set to string value "auto"
... If Git decides that the content is text ...

Unspecified
... Git uses the core.autocrlf configuration variable ...

(这意味着如果您未指定 text,您必须追查 git config documentation 以找出 core.autocrlf 的作用)。

您已选择为每个文件设置它或为每个文件设置为 auto。前者的意思是“对每个文件进行转换”,后者(auto设置)的意思是:嘿,Git,请帮我决定文件是不是文本。如果您确定它是文本,请进行转换。

eol=lf 如何应用于文件

text 设置说明的正下方是 eol 设置的说明:

This attribute sets a specific line-ending style to be used in the working directory. It enables end-of-line conversion without any content checks, effectively setting the text attribute.

Set to string value "crlf"
... [snipped because you set lf]

Set to string value "lf"
This setting forces Git to normalize line endings to LF on checkin and prevents conversion to CRLF when the file is checked out.

因此,如果您为路径设置了 eol=lf(并且使用 * 作为模式,它将为 每个 路径设置), Git 会将每个文件都视为文本,并在“checkin”时将 CRLF 行尾转换为 LF 行尾(这又是一个糟糕的措辞:转换实际上发生在 git add 步骤中)。 Git 在结帐期间什么都不做(这也不是完美的措辞:转换,或者在这种情况下为非转换,发生在从索引提取到工作树的过程中)。

如果你使用不同的模式,你会得到不同的结果

请注意,如果您选择像 *.txt 这样的模式,那么这些属性 设置 仅适用于匹配该模式的路径。对于其他路径,这些属性保持未设置。因此,您应该回顾一下 the documentation,看看当这些属性被 unset.

时会发生什么

您当然可以这样做:

* -text
*.txt eol=lf

第一行将在所有文件上显式 取消设置 text,并在所有文件上保留 eol 未指定。然后第二行 *.txt 文件设置一个值 eol=lf,覆盖未指定的值。现在 Git 会将 eol=lf 规则应用到名称匹配 *.txt 的所有文件,并使用未指定的(eolunset)所有剩余文件的文本规则。

这个特殊的 -text 语法是我在上面剪掉的东西。使用 text=false 不会 取消设置 text,而是将 text 设置为字符串值 false。这与未指定 text 具有相同的效果(不是特别 unset)。使用 -text 给它特殊的 unset 设置。

unset textunspecified text 的区别在于 text 未指定,Git 可以尝试 猜测 (基于像 core.autocrlf 这样的 core.* 设置)是否进行转换。但是,当 text 明确地 unset 时,Git 将不会对该文件进行任何猜测或转换。