行尾转换如何在不同操作系统之间使用 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,例如
CRLF
和 LF
在同一文件中的组合。
这是如何发生的不是这里的问题,但它确实发生了。
我在 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.autocrlf
是 true
和
repo 中的文件具有 LF
EOL。
对我来说最令人惊讶的是,我怀疑许多 EOL 问题的原因是没有像 CRLF
+LF
这样的混合 EOL 得到规范化的配置。
另请注意,CR
的“旧”Mac EOL 也永远不会被转换。
这意味着如果一个写得不好的 EOL 转换脚本试图通过将LF
s 转换为CRLF
s 来转换带有CRLF
s+LF
s 的混合结尾文件,那么它将使文件处于混合模式在 CRLF
被转换为 CRCRLF
的任何地方都带有“孤独”CR
s。
然后,即使在 true
模式下,Git 也不会转换任何内容,并且 EOL 的破坏仍在继续。这实际上发生在我身上,并且把我的文件弄得一团糟,因为一些编辑器和编译器(例如 VS2010)不喜欢 Mac EOL。
我想真正处理这些问题的唯一方法是偶尔通过检查 input
或 false
模式下的所有文件来规范整个 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=true
和 core.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.autocrlf
,core.eol
。
-
core.autocrlf = 输入:没有任何反应
core.autocrlf = true : 仅当存储库中的文件为 'LF', 'LF' -> 'CRLF' 时才会发生转换
core.autocrlf = false : 只有当存储库中的文件是 'LF', 'LF' ->
core.eol
时才会发生转换
text
属性是Unspecified
,它依赖于core.autocrlf
。
-
同
2.1
同2.2
None,什么都没有发生,当text
属性为Unspecified
时core.eol无效
默认行为
所以默认行为是text
属性是Unspecified
和core.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=auto
和 core.eol
在 git config 中被设置为 crlf
”...究竟是什么意思?
意思是,如果一个文件没有设置.gitattributes
text 属性,并且如果core.autocrlf
是true
,现在取决于您提交的文件是否是新的(在这种情况下,是的,它将在 git repo 数据库中被规范化为 LF),或者它是否是您编辑并正在提交的现有文件(在这种情况下,什么都不会发生......除非您在中运行 git add --renormalize .
在这种情况下,它将在 git repo 数据库中标准化)。
你看...整个机制只发生在.gitattributes
未为其放置文本属性变体的文件:text
、-text
、text=auto
.
因此,您真正应该注意的是使用 .gitattributes
并在所有文件上使用默认设置,即:
* -text
# followed by specialization
这会将所有(专业化除外)默认为原样,并完全覆盖core.autocrlf
,或使用默认值:
* text=auto
# followed by specialization
意味着 git 自动检测为非二进制(文本)并且在 git 数据库中具有LF
[参见注释 1.] 的所有文件(专业化文件除外)将获得CRLF
无论何时:
• core.autocrlf
是 true
,或
• core.eol
是 crlf
,或者
• core.eol
是 native
(默认)并且您在 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的主要内容,如果未能解决你的问题,请参考以下文章