行尾转换如何在不同操作系统之间使用 git core.autocrlf

Posted

技术标签:

【中文标题】行尾转换如何在不同操作系统之间使用 git core.autocrlf【英文标题】:How line ending conversions work with git core.autocrlf between different operating systems 【发布时间】:2011-03-13 12:28:27 【问题描述】:

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

这是我读到的理解:

Unix 和 Mac OSX(OSX 之前使用 CR)客户端使用 LF 行尾。 Windows 客户端使用 CRLF 换行符。

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

这是一个矩阵,它试图用问号记录 core.autocrlf 的“输入”和“假”设置,我不确定行结束转换行为。

我的问题是:

    问号应该是什么? 这个矩阵对于“非问号”是否正确?

随着似乎形成共识,我将更新答案中的问号。

core.autocrlf 值 真输入假 -------------------------------------------------- -------- 提交 |转变 ? ? 新 |到 LF(转换为 LF?)(没有转换?) 提交 |转换成 ?不 现有 | LF(转换为 LF?)转换 结帐 |转换成 ?不 现有 | CRLF(没有转换?)转换

我并不是真的在寻找关于各种设置的优缺点的意见。我只是在寻找能够清楚地说明如何期望 git 使用这三个设置中的每一个进行操作的数据。

--

更新 04/17/2012:在阅读了 cmets 中 JJD 链接的the article by Tim Clem 之后,我修改了上表中“未知”值中的一些值,以及更改“checkout existing | true 以转换为 CRLF 而不是转换为客户端”。以下是他给出的定义,比我在其他地方看到的任何东西都更清楚:

core.autocrlf = false

这是默认设置,但鼓励大多数人更改此设置 立即地。使用 false 的结果是 Git 永远不会搞砸 在您的文件上以行结尾。您可以使用 LF 或 CRLF 签入文件 或 CR 或这三者的一些随机组合,Git 不在乎。这 可以使 diff 更难阅读和合并更困难。大多数人 在 Unix/Linux 世界中工作使用这个值,因为它们没有 CRLF 问题,他们不需要 Git 做额外的工作 文件被写入对象数据库或写出到 工作目录。

core.autocrlf = true

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

core.autocrlf = 输入

这意味着 Git 将处理所有文本文件并确保 将该文件写入对象时,CRLF 被替换为 LF 数据库。但是,它不会反过来。当你阅读文件时 退出对象数据库并将它们写入工作 目录,它们仍然有 LF 来表示行尾。这 设置通常用于 Unix/Linux/OS X 以防止 CRLF 被写入存储库。这个想法是,如果你粘贴 来自 Web 浏览器的代码并意外地将 CRLF 放入您的一个 文件,Git 会确保在您编写时将它们替换为 LF 到对象数据库。

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

将 Tim 的文章与 jmlane 迄今为止投票率最高的 answer 进行比较,表明在 true 和 input 设置上完全一致,在 false 设置上存在分歧。

【问题讨论】:

保持autocrlf 为假似乎容易多了;)***.com/questions/2333424/… @VonC:我读过,我想我明白了,但我不一定要做出选择。我使用 git 存储库,我无法控制谁要求我以某种方式设置值。 如果 Windows 也标准化为 LF 不是很好吗? Mac 曾经是 CR(v10 之前的版本),但现在已标准化为 LF。 我需要添加一个链接到 Timothy Clem 的精彩文章 - 请阅读所有 Mind the End of Your Line。 场景:我是一个分离的 Linux/Windows 开发人员。我只使用可以识别这两种类型的行尾的文本编辑器(IE.vim、eclipse)。我只需要(想要)处理以 LF 结尾的文件。我目前在我的全局 git 配置中设置了 core.autocrlf=input。我可以走了吗?我会有冲突吗? 【参考方案1】:

在gitattributes 手册页的text attribute section 中可以找到关于core.autocrlf 工作原理的最佳解释。

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

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

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

【讨论】:

for autocrlf=true 不应该是以下?存储库中只有 CRLF EOL 字符的文本文件在提交回存储库时会从 CRLF 规范化为 LF。存储库中包含 LF 的文件将被原封不动地提交。 对我来说,即使 autocrlf=false git 正在将 EOL 转换为 CRLF。阅读此答案后,我意识到我的 .gitattribute 文件设置了 text=auto ,这导致了问题。 对于core.autocrlf = false,如果我没有gitattributes 文件是否意味着不会进行规范化?还是意味着它将使用默认的规范化? 不应该.gitattributes 文件优先于core.autocrlf 设置吗? 需要注意的是,更改此设置后,git rm --cached -r .git reset --hard 有助于重写工作树中的所有文件。这样做会丢失未提交的更改!【参考方案2】:

混合平台项目中的 EOL 问题让我的生活痛苦了很长时间。当 repo 中已经存在具有不同和混合 EOL 的文件已经时,通常会出现问题。这意味着:

    repo 可能包含具有不同 EOL 的不同文件 repo 中的某些文件可能混合了 EOL,例如CRLFLF 在同一文件中的组合。

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

我在 Windows 上针对各种模式及其组合运行了一些转换测试。 这是我在稍微修改的表格中得到的:

|产生的转换时 |结果转换时 |提交各种文件 |从回购中签出- | EOLs INTO 回购和 |里面有混合文件和 | core.autocrlf 值:| core.autocrlf 值: -------------------------------------------------- ------------------------------ 文件 |真实 |输入 |假 |真实 |输入 |错误的 -------------------------------------------------- ------------------------------ Windows-CRLF | CRLF -> LF | CRLF -> LF |原样 |原样 |原样 |原样 Unix-LF |原样 |原样 |原样 | LF -> CRLF |原样 |原样 Mac-CR |原样 |原样 |原样 |原样 |原样 |原样 混合-CRLF+LF |原样 |原样 |原样 |原样 |原样 |原样 混合-CRLF+LF+CR |原样 |原样 |原样 |原样 |原样 |原样

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

结帐时(右 3 列),只有 1 种情况发生转换:

    core.autocrlftrue repo 中的文件具有 LF EOL。

对我来说最令人惊讶的是,我怀疑许多 EOL 问题的原因是没有像 CRLF+LF 这样的混合 EOL 得到规范化的配置。

另请注意,CR 的“旧”Mac EOL 也永远不会被转换。 这意味着如果一个写得不好的 EOL 转换脚本试图通过将LFs 转换为CRLFs 来转换带有CRLFs+LFs 的混合结尾文件,那么它将使文件处于混合模式在 CRLF 被转换为 CRCRLF 的任何地方都带有“孤独”CRs。 然后,即使在 true 模式下,Git 也不会转换任何内容,并且 EOL 的破坏仍在继续。这实际上发生在我身上,并且把我的文件弄得一团糟,因为一些编辑器和编译器(例如 VS2010)不喜欢 Mac EOL。

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

【讨论】:

很好的答案,但我不能同意的一句话是在 Windows 上,大概继续使用core.autocrlf true。我个人认为应该始终使用input【参考方案3】:

core.autocrlf 值不依赖于操作系统类型,但在 Windows 上,默认值为 true,对于 Linux - input。我探索了提交和签出案例的 3 个可能值,这是结果表:

╔═══════════════╦══════════════╦══════════════╦══════════════╗
║ core.autocrlf ║     false    ║     input    ║     true     ║
╠═══════════════╬══════════════╬══════════════╬══════════════╣
║               ║ LF   => LF   ║ LF   => LF   ║ LF   => LF   ║
║ git commit    ║ CR   => CR   ║ CR   => CR   ║ CR   => CR   ║
║               ║ CRLF => CRLF ║ CRLF => LF   ║ CRLF => LF   ║
╠═══════════════╬══════════════╬══════════════╬══════════════╣
║               ║ LF   => LF   ║ LF   => LF   ║ LF   => CRLF ║
║ git checkout  ║ CR   => CR   ║ CR   => CR   ║ CR   => CR   ║
║               ║ CRLF => CRLF ║ CRLF => CRLF ║ CRLF => CRLF ║
╚═══════════════╩══════════════╩══════════════╩══════════════╝

【讨论】:

简短的文字总结:只有CR 的文件永远不会被触及。 false 从不触及行尾。 true 始终以LF 提交并以CRLF 签出。 input 始终以 LF 提交并按原样签出。【参考方案4】:

“eol 转换”方面的情况即将发生变化,upcoming Git 1.7.2:

一个新的配置设置core.eol is being added/evolved:

这是当前pu(我的系列中的最后一个)中的“添加“core.eol”配置变量”提交的替代品。并没有暗示“core.autocrlf=true”是“* text=auto”的替代品,而是明确表明autocrlf 仅适用于想要使用的用户 在没有文本的存储库上的工作目录中的 CRLF 文件规范化。 启用后,“core.eol”将被忽略。

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

[core]
  autocrlf = true

即使core.eol 设置为“lf”,也将 CRLF 放在工作目录中。

core.eol:

为设置了text 属性的文件设置要在工作目录中使用的行结束类型。 替代方案是 'lf'、'crlf' 和 'native',它们使用平台的本地行尾。 默认值为native


其他演变are being considered:

对于 1.8,我会考虑让 core.autocrlf 只打开规范化并将工作目录行结束决定留给 core.eol,但这破坏人们的设置。


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

请参阅commit 817a0c7(2016 年 2 月 23 日)、commit 6e336a5、commit df747b8、commit df747b8(2016 年 2 月 10 日)、commit df747b8、commit df747b8(2016 年 2 月 10 日)和 commit 4b4024f、@987654333 @,commit 92cce13,commit 320d39c,commit 4b4024f,commit bb211b4,commit 92cce13,commit 320d39c(2016 年 2 月 5 日)Torsten Bögershausen (tboegi)。(由 @9876543439@ 合并到 @987654 @,2016 年 2 月 26 日)

convert.c:重构crlf_action

重构crlf_action的判断和使用。 今天,当没有在文件上设置“crlf”属性时,crlf_action 设置为 CRLF_GUESS。请改用CRLF_UNDEFINED,并像以前一样搜索“text”或“eol”。

替换旧的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 添加in the comments:

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

有关详细信息,请参阅“What is difference between autocrlf and eol”。

【讨论】:

不幸的是,这并没有增加我的清晰度。似乎他们在说当前的实现存在问题(尚不清楚这些问题是什么),并且他们正在增加复杂性以解决那些未指定的问题。在我看来,core.autocrlf 设置已经过于复杂且文档不足,而且这种情况似乎越来越糟。再次感谢您的提醒。 这似乎不是一个令人满意的解决方案,并且似乎与 core.autocrlf 存在相同的问题。我的偏好是 git 永远不会自动修改任何内容,但它会警告想要添加或提交错误行尾的用户。所以你需要一个命令行选项来允许“git add”添加“错误”的行尾。 (可能 git add 是检查这个比 git commit 更好的地方) 这将迫使相应的用户更改他们的编辑器设置并真正解决问题。虽然它允许为来自第 3 方的文件或已签入存储库的文件留下“错误”的行尾。 @donquixote 再次,我同意。但是core.eol 仅是关于“自动修改”您在.gitattributes 文件中明确声明 的内容。这与 core.autocrlf 不同,后者适用于 repo 中的 any 文件。这是一个声明过程。 @donquixote:我知道这已经很老了,但我现在才看到你的评论。事实上,所有这些转换(从 eol= 或 autocrlf 设置,“干净”过滤器的任何 EOL 转换)都在文件从工作树移动到索引时运行,即在 git add 期间而不是在git commit 时间。 (请注意,git commit -a--only--include 在那个时候确实会将文件添加到索引中。)对于它的价值,你、我和 Linus Torvalds 都讨厌 VCS ever 修改正在提交的内容。但是有所有这些 Windows 用户...... :-)【参考方案5】:

这是我到目前为止的理解,以防它对某人有所帮助。

core.autocrlf=truecore.safecrlf = true

您有一个存储库,其中所有行尾都相同,但您在不同的平台上工作。 Git 将确保您的行尾转换为您平台的默认值。为什么这很重要?假设您创建了一个新文件。您平台上的文本编辑器将使用其默认的行尾。当您签入时,如果您没有将 core.autocrlf 设置为 true,那么您已经为平台上的某个人引入了行尾不一致,该平台上默认为不同的行尾。我也总是设置 safecrlf,因为我想知道 crlf 操作是可逆的。通过这两个设置,git 正在修改您的文件,但它会验证修改是否可逆

core.autocrlf=false

您有一个已包含混合行结尾的存储库签入,修复不正确的行结尾可能会破坏其他内容。在这种情况下,最好不要告诉 git 转换行尾,因为那样会加剧它旨在解决的问题 - 使差异更易于阅读和合并不那么痛苦。使用此设置,git 不会修改您的文件

core.autocrlf=input

我不使用它,因为这样做的原因是为了涵盖一个用例,您在默认为 LF 行结尾的平台上创建了一个具有 CRLF 行结尾的文件。我更喜欢让我的文本编辑器始终使用平台的行尾默认值保存新文件。

【讨论】:

【参考方案6】:

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

对于Checkin (git add, git commit)

    如果text 属性为Set, Set value to 'auto',则转换发生在文件已使用“CRLF”提交时 如果text 属性是Unset: 什么都没有发生,enen for Checkout 如果text 属性为Unspecified,则转换取决于core.autocrlf
      如果是autocrlf = input or autocrlf = true,则仅当存储库中的文件为“LF”时才会发生转换,如果已为“CRLF”,则不会发生任何事情。 如果autocrlf = false,什么都不会发生

对于Checkout

    如果text 属性是Unset:什么都不会发生。 如果text 属性是Set, Set value to 'auto:它取决于core.autocrlfcore.eol
      core.autocrlf = 输入:没有任何反应 core.autocrlf = true : 仅当存储库中的文件为 'LF', 'LF' -> 'CRLF' 时才会发生转换 core.autocrlf = false : 只有当存储库中的文件是 'LF', 'LF' -> core.eol 时才会发生转换
    如果text 属性是Unspecified,它依赖于core.autocrlf
      2.12.2 None,什么都没有发生,当text属性为Unspecified时core.eol无效

默认行为

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

    签入,没有任何反应 结帐时,没有任何反应

结论

    如果设置了 text 属性,则签入行为取决于自身,而不是 autocrlf autocrlf 或 core.eol 用于结帐行为,而 autocrlf > core.eol

【讨论】:

【参考方案7】:

在 linux 和 windows 上都做了一些测试。我使用包含以 LF 结尾的行和以 CRLF 结尾的行的测试文件。 文件已提交、删除然后签出。 core.autocrlf 的值在提交之前和结帐之前设置。 结果如下。

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  

【讨论】:

【参考方案8】:

提交时导致CRLF -> LF 的声明core.autocrlf=true 完全错误!正如您将看到的那样,这并不是那么简单......

docs 表示设置对应于...“.gitattributes 中的text=autocore.eol 在 git config 中被设置为 crlf”...究竟是什么意思?

意思是,如果一个文件没有设置.gitattributes text 属性,并且如果core.autocrlftrue,现在取决于您提交的文件是否是新的(在这种情况下,是的,它将在 git repo 数据库中被规范化为 LF),或者它是否是您编辑并正在提交的现有文件(在这种情况下,什么都不会发生......除非您在中运行 git add --renormalize .在这种情况下,它将在 git repo 数据库中标准化)。

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

因此,您真正应该注意的是使用 .gitattributes 并在所有文件上使用默认设置,即:

* -text
# followed by specialization

这会将所有(专业化除外)默认为原样,并完全覆盖core.autocrlf,或使用默认值:

*  text=auto
# followed by specialization

意味着 git 自动检测为非二进制(文本)并且在 git 数据库中具有LF[参见注释 1.] 的所有文件(专业化文件除外)将获得CRLF 无论何时: • core.autocrlftrue,或 • core.eolcrlf,或者 • core.eolnative(默认)并且您在 Windows 平台上。在所有其他情况下,您将获得 LF

我的意思是什么专业?例如,.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 时已正确规范化

【讨论】:

以上是关于行尾转换如何在不同操作系统之间使用 git core.autocrlf的主要内容,如果未能解决你的问题,请参考以下文章

可以在跨操作系统网络共享上使用 git 吗?

Git在Windows上签出带有LF行尾的特定文件类型

git 使用详解

话说 SVN 与 Git 之间的区别

Git 和 SVN 之间的五个基本区别

Git和SVN之间的区别