行结束转换如何与git核心工作。不同操作系统之间的自专制

我已经在Stack Overflow上阅读了很多不同的问题和答案,以及关于core.autocrlf设置如何工作的git文档。

以下是我读到的内容:

Unix和Mac OSX (pre-OSX使用CR)客户端使用LF行结束符。< br / > Windows客户端使用CRLF行结束符

当核心。在客户端被设置为true, git存储库总是以LF行结束格式存储文件,客户端文件中的行结束符在签出/提交时来回转换,对于使用非LF行结束符的客户端(即Windows),无论客户端上的行结束符文件是什么格式(这与Tim Clem的定义不一致-参见下面的更新)。

下面是一个矩阵,它试图为core的'input'和'false'设置记录相同的内容。带问号的自专制,我不确定行结束转换行为。

我的问题是:

  1. 问号应该是什么?
  2. 这个矩阵对“非问题marks"正确吗?

当达成共识时,我将更新答案中的问号。

core.autocrlf value
true            input              false
----------------------------------------------------------
commit   |  convert           ?                  ?
new      |  to LF      (convert to LF?)   (no conversion?)


commit   |  convert to        ?                 no
existing |  LF         (convert to LF?)     conversion


checkout |  convert to        ?                 no
existing |  CRLF       (no conversion?)     conversion


我并不是真的在寻找各种设置的利弊。我只是寻找数据,使它清楚地期望git如何操作这三个设置中的每一个。

--

更新04/17/2012:在阅读评论中JJD链接的蒂姆·克莱姆的文章后,我修改了“未知”中的一些值;值,以及更改“checkout existing | true to convert to CRLF而不是convert to client”;以下是他给出的定义,比我在其他地方看到的任何定义都更清楚:

核心。独裁者= false

这是默认值,但是大多数人都被鼓励去改变它 立即。使用false的结果是Git永远不会出错 在你的文件上加上行尾。您可以用LF或CRLF签入文件 或CR或这三者的任意组合,Git并不关心。这 可以使差分更难读取和合并更困难。大多数人 在Unix/Linux世界中工作的人使用这个值,因为他们没有 CRLF问题,他们不需要Git做额外的工作 文件被写入对象数据库或写入 工作目录。< / p >

核心。独裁者= true

这意味着Git将处理所有文本文件,并确保 在将该文件写入对象数据库时,CRLF将被LF替换 并在写入工作时将所有LF转回CRLF 目录中。这是Windows上的推荐设置,因为它 确保您的存储库可以在其他平台上使用

.在你的工作目录中保留CRLF

核心。selflf =输入

这意味着Git将处理所有文本文件,并确保 当将该文件写入对象时,CRLF将被LF替换 数据库。然而,它不会起到相反的作用。当你读取文件时 从对象数据库中退出,并将它们写入工作数据库 目录下,它们仍然会有lf来表示行结束。这 设置通常用于Unix/Linux/OS X,以防止crlf 写入存储库。这个想法是,如果你粘贴 代码,并意外地将crlf带入您的一个 当你写文件时,Git会确保它们被lf替换

Tim的文章非常棒,我能想到的唯一缺失的是他假设存储库是LF格式的,这并不一定是正确的,特别是对于仅用于Windows的项目。

将Tim的文章与jmlane迄今为止投票最多的回答进行比较,可以看出在true和输入设置上完全一致,而在false设置上不一致。

130625 次浏览

在“eol转换”方面,事情即将发生变化,即将发布的Git 1.7.2:

一个新的配置设置core.eol正在被添加/进化:

这是对当前在pu(我的系列中的最后一个)中的'Add "core.eol"配置变量'提交的替换 并没有暗示"core.autocrlf=true"是"* text=auto"的替代品,它明确表明了autocrlf仅适用于想要使用的用户 在没有文本的存储库的工作目录中的crlf 文件标准化> < /强劲。< br > 当它被启用时,“core。

. Eol "被忽略 引入一个新的配置变量"core.eol",允许用户设置工作目录中行结束规范化文件的行结束符 它默认为“native”,这意味着Windows上的CRLF和其他地方的LF。 注意"core.autocrlf"覆盖core.eol.
这意味着:

[core]
autocrlf = true

即使core.eol设置为"lf",也会将CRLFs放在工作目录中。

core.eol:

设置行结束类型,用于设置了text属性的文件的工作目录 可选选项有'lf', 'crlf'和'native',它们使用平台的本机行结尾 默认值为native


其他演化正在被考虑:

对于1.8,我会考虑让core.autocrlf只打开归一化,把工作目录行结束决定留给core。eol,但那打破人们的设置。


git 2.8(2016年3月)改进了core.autocrlf影响eol的方式:

参见提交817年a0c75的提交817年a0c7(2016年2月23日),提交6 e336a5提交df747b8提交df747b8(2016年2月10日),提交df747b8提交df747b8(2016年2月10日),以及提交4 b4024f提交bb211b4提交92年cce13提交817年a0c70, 提交4 b4024f提交bb211b4提交92年cce13提交92年cce13提交817年a0c70(2016年2月5日) (由Junio C Hamano—gitster提交c6b94eb中合并,26 Feb 2016)

convert.c:重构crlf_action

重构crlf_action的确定和使用 今天,当一个文件上没有设置“crlf”属性时,crlf_action被设置为 CRLF_GUESS。改为使用CRLF_UNDEFINED,并像以前一样搜索“text”或“eol”。< / p >

替换旧的CRLF_GUESS用法:

CRLF_GUESS && core.autocrlf=true -> CRLF_AUTO_CRLF
CRLF_GUESS && core.autocrlf=false -> CRLF_BINARY
CRLF_GUESS && core.autocrlf=input -> CRLF_AUTO_INPUT

通过定义,更清楚地说明什么是什么:

- CRLF_UNDEFINED : No attributes set. Temparally used, until core.autocrlf
and core.eol is evaluated and one of CRLF_BINARY,
CRLF_AUTO_INPUT or CRLF_AUTO_CRLF is selected
- CRLF_BINARY    : No processing of line endings.
- CRLF_TEXT      : attribute "text" is set, line endings are processed.
- CRLF_TEXT_INPUT: attribute "input" or "eol=lf" is set. This implies text.
- CRLF_TEXT_CRLF : attribute "eol=crlf" is set. This implies text.
- CRLF_AUTO      : attribute "auto" is set.
- CRLF_AUTO_INPUT: core.autocrlf=input (no attributes)
- CRLF_AUTO_CRLF : core.autocrlf=true  (no attributes)

torek添加在评论中时:

所有这些转换(从eol=autocrlf设置的任何EOL转换,以及"clean"过滤器)当文件从工作树移动到索引时运行,即在git add期间而不是在git commit时间 (注意,git commit -a--only--include确实在当时将文件添加到索引中。

有关更多信息,请参见“selflf和eol有什么区别”。

core.autocrlf如何工作的最好解释可以在gitattributes手册页中找到,在text属性节

这就是core.autocrlf目前的工作方式(或者至少从我所知道的v1.7.2开始):

  • core.autocrlf = true
  1. 从存储库签出的只有LF字符的文本文件在你的工作树中被规范化为CRLF;在存储库中包含CRLF的文件将不会被触及
  2. 在存储库中只有LF字符的文本文件,在提交回存储库时,将从CRLF规范化为LF。在存储库中包含CRLF的文件将被提交。
  • core.autocrlf = input
  1. 从存储库签出的文本文件将在您的工作树中保留原始EOL字符。
  2. 工作树中带有CRLF字符的文本文件在提交回存储库时被规范化为LF
  • core.autocrlf = false
  1. core.eol指定工作树的文本文件中的EOL字符。
  2. 默认为core.eol = native,这意味着工作树eol将取决于git运行的位置:Windows机器上的CRLF,或*nix中的LF
  3. 存储库gitattributes设置决定提交到存储库的EOL字符规范化(默认是规范化为LF字符)。

我最近才研究了这个问题,我也发现情况非常复杂。core.eol设置确实有助于澄清git如何处理EOL字符。

长期以来,混合平台项目中的eol问题一直让我的生活很痛苦。当repo中已经有不同的和混合eol 已经的文件时,通常会出现问题。这意味着:

  1. 回购可能具有不同eol的不同文件
  2. repo中的一些文件可能有混合的EOL,例如,同一文件中CRLFLF的组合。

这是如何发生的不是这里的问题,但它确实发生了。

我在Windows上对各种模式及其组合进行了一些转换测试 下面是我得到的,在一个稍微修改过的表中:

| Resulting conversion when       | Resulting conversion when
| committing files with various   | checking out FROM repo -
| EOLs INTO repo and              | with mixed files in it and
|  core.autocrlf value:           | core.autocrlf value:
--------------------------------------------------------------------------------
File             | true       | input      | false | true       | input | false
--------------------------------------------------------------------------------
Windows-CRLF     | CRLF -> LF | CRLF -> LF | as-is | as-is      | as-is | as-is
Unix -LF         | as-is      | as-is      | as-is | LF -> CRLF | as-is | as-is
Mac  -CR         | as-is      | as-is      | as-is | as-is      | as-is | as-is
Mixed-CRLF+LF    | as-is      | as-is      | as-is | as-is      | as-is | as-is
Mixed-CRLF+LF+CR | as-is      | as-is      | as-is | as-is      | as-is | as-is


如您所见,在提交时发生转换的情况有两种(左边的3列)。在其余情况下,文件按原样提交。

签出时(右3列),只有1种情况下转换发生:

  1. core.autocrlftrue 而且
  2. 回购中的文件具有LF EOL。

最令我惊讶的是,我怀疑许多EOL问题的原因是,没有一个配置可以将CRLF+LF这样的混合EOL标准化。

还要注意,CR的“旧”Mac eol也永远不会被转换 这意味着,如果一个编写得很糟糕的EOL转换脚本试图将一个包含CRLF + __abc1的混合结尾文件转换为__abc1,只需将__abc1转换为CRLF,那么它将使该文件处于“孤独的”__abc4的混合模式,其中CRLF被转换为CRCRLF Git将不会转换任何东西,即使是在true模式下,EOL破坏仍将继续。这实际上发生在我身上,我的文件非常糟糕,因为一些编辑器和编译器(例如VS2010)不喜欢Mac eol

我想真正处理这些问题的唯一方法是偶尔通过检出所有inputfalse模式下的文件来规范化整个回购,运行适当的规范化并重新提交更改的文件(如果有的话)。在Windows上,假定继续使用core.autocrlf true

以下是我到目前为止对它的理解,以防它能帮助到别人。

core.autocrlf=truecore.safecrlf = true

你有一个存储库中所有的行结束都是相同的,但是你在不同的平台上工作。Git将确保您的行结束符转换为您平台的默认值。为什么这很重要?假设您创建了一个新文件。平台上的文本编辑器将使用默认的行结束符。当你登记的时候,如果你没有核心。如果将selflf设置为true,则为平台上默认使用不同的行结束符的某人引入了不一致的行结束符。我总是设置safecrlf,因为我想知道crlf操作是可逆的。通过这两个设置,Git正在修改您的文件,但它会验证修改是否可逆

core.autocrlf=false

你有一个已经有混合行结束符的存储库检入和修复不正确的行结束可能破坏其他东西。在这种情况下,最好不要告诉git转换行尾,因为这样会加剧它本来要解决的问题——使差异更容易阅读,合并不那么痛苦。在此设置中,Git不会修改你的文件

core.autocrlf=input

我不使用它的原因是为了介绍一个用例,在这个用例中,您在默认为LF行结束符的平台上创建了一个具有CRLF行结束符的文件。相反,我更喜欢让我的文本编辑器总是用平台的默认行结束符保存新文件。

core.autocrlf的值不依赖于操作系统,
但Windows上的默认值是true。在Linux上是input
我探索了检出和提交用例的三个可能值

下面是结果表:

╔═══════════════╦══════════════╦══════════════╦══════════════╗
║ core.autocrlf ║     false    ║     input    ║     true     ║
╠═══════════════╬══════════════╬══════════════╬══════════════╣
║               ║ LF   => LF   ║ LF   => LF   ║ LF   => CRLF ║
║ git checkout  ║ CR   => CR   ║ CR   => CR   ║ CR   => CR   ║
║               ║ CRLF => CRLF ║ CRLF => CRLF ║ CRLF => CRLF ║
╠═══════════════╬══════════════╬══════════════╬══════════════╣
║               ║ LF   => LF   ║ LF   => LF   ║ LF   => LF   ║
║ git commit    ║ CR   => CR   ║ CR   => CR   ║ CR   => CR   ║
║               ║ CRLF => CRLF ║ CRLF => LF   ║ CRLF => LF   ║
╚═══════════════╩══════════════╩══════════════╩══════════════╝
在linux和windows上都做了一些测试。我使用了一个包含以LF结尾的行和以CRLF结尾的行的测试文件 文件被提交,删除,然后签出。 核心的价值。在提交之前和签出之前设置专制语句。 结果如下:

commit core.autocrlf false, remove, checkout core.autocrlf false: LF=>LF   CRLF=>CRLF
commit core.autocrlf false, remove, checkout core.autocrlf input: LF=>LF   CRLF=>CRLF
commit core.autocrlf false, remove, checkout core.autocrlf true : LF=>LF   CRLF=>CRLF
commit core.autocrlf input, remove, checkout core.autocrlf false: LF=>LF   CRLF=>LF
commit core.autocrlf input, remove, checkout core.autocrlf input: LF=>LF   CRLF=>LF
commit core.autocrlf input, remove, checkout core.autocrlf true : LF=>CRLF CRLF=>CRLF
commit core.autocrlf true, remove, checkout core.autocrlf false: LF=>LF   CRLF=>LF
commit core.autocrlf true, remove, checkout core.autocrlf input: LF=>LF   CRLF=>LF
commit core.autocrlf true,  remove, checkout core.autocrlf true : LF=>CRLF CRLF=>CRLF

不,@jmlane的答案是错误的。

Checkin (git add, git commit):

  1. 如果text属性为Set, Set value to 'auto',则转换发生在文件已使用'CRLF'提交时。
  2. 如果text属性为Unset:什么都不发生,则enen为Checkout
  3. 如果text属性为Unspecified,转换依赖于core.autocrlf
    1. 如果autocrlf = input or autocrlf = true,转换只发生在存储库中的文件是'LF'时,如果它已经是'CRLF',什么都不会发生。
    2. 如果autocrlf = false,什么都不会发生
    3. 李< / ol > < / >

    Checkout:

    1. 如果text属性为Unset:什么都不会发生。
    2. if text属性为Set, Set value to 'auto:它取决于core.autocrlfcore.eol
      1. 核心。专制lf =输入:什么都没有发生
      2. 核心。selflf = true:转换只发生在存储库中的文件是'LF', 'LF' -> 'CRLF'时
      3. 核心。selflf = false:仅当存储库中的文件为'LF', 'LF' -> core.eol时才会发生转换
      4. 李< / ol > < / >
      5. 如果text属性为Unspecified,则它取决于core.autocrlf
        1. 2.1相同
        2. 2.2相同
        3. 没有,什么都不会发生,核心。当text属性为Unspecified时,eol无效
        4. 李< / ol > < / >

        默认的行为

        所以默认行为是text属性是Unspecifiedcore.autocrlf = false:

        1. 对于签入,什么都不会发生
        2. 对于结帐,什么都没有发生

        结论

        1. 如果设置了text属性,则签入行为依赖于自身,而不是自selff
        2. 专制或核心。Eol是签出行为,自定义> core.eol

语句core.autocrlf=true在提交时导致CRLF -> LF是完全错误的!事情并没有那么简单,正如你将看到的……

文档表示设置对应于…" text=auto.gitattributescore.eol被设置为crlf在git配置"…这到底意味着什么?

这意味着,如果一个文件没有.gitattributes 文本属性集,并且如果core.autocrlftrue,那么现在取决于你提交的文件是否为新文件(在这种情况下,是的,它将在git回购数据库中被归一化为LF),或者它是否是你编辑过并且正在提交的现有文件(在这种情况下,什么都不会发生……除非你运行git add --renormalize .,在这种情况下,它将在git回购数据库中得到规范化)。

你看到…整个机制只发生在.gitattributes放置文本属性变体的文件上:text-texttext=auto

所以你真正应该关注的是在你的所有文件上使用.gitattributes和默认设置,是:

* -text
# followed by specialization

它将默认所有(特殊化除外)为按原样<强> < / >强,并完全覆盖core.autocrlf,或使用默认值为:

*  text=auto
# followed by specialization

意味着git自动检测为非二进制(文本)的所有文件(除了特化),并且在git数据库__abc2中有LF,将在任何时候获得CRLFcore.autocrlftrue,或
core.eolcrlf,或
core.eolnative(默认),并且你在Windows平台上。
在所有其他情况下,你得到LF.

.< br>

我指的是什么专门化?例如,将.bat文件设置为CRLF,将.sh文件设置为LF:

*.sh           text eol=lf


# *.bat
*.[bB][aA][tT] text eol=crlf

# *.sh are committed correctly as-is (LF)
*.sh           -text


# *.bat are committed correctly as-is (CRLF)
*.[bB][aA][tT] -text

是的……事情没那么简单。


[注1]:
这将是所有匹配text=auto属性的文件的情况(即没有一些其他专门化),因为我假设你的repo在创建.gitattribute时是正确规范化的