我尝试使用以 CRLF 结尾的行提交文件,但失败了。
我花了一整天的时间在我的 Windows 计算机上尝试不同的策略,几乎被吸引停止尝试使用 Git 而是尝试 Mercurial。
如何正确处理 CRLF 行尾?
问了这个问题快四年了,我终于找到了一个让我完全满意的答案!
请参阅 github:help 的 Dealing with line endings 指南中的详细信息。
Git 允许您直接使用 .gitattributes 文件中的 text 属性为 repo 设置行结束属性。该文件被提交到 repo 并覆盖 core.autocrlf 设置,允许您确保所有用户的行为一致,而不管他们的 git 设置如何。
因此
这样做的好处是您的终端配置现在随您的存储库一起移动,您无需担心协作者是否具有正确的全局设置。
这是 .gitattributes
文件的示例
# Auto detect text files and perform LF normalization
* text=auto
*.cs text diff=csharp
*.java text diff=java
*.html text diff=html
*.css text
*.js text
*.sql text
*.csproj text merge=union
*.sln text merge=union eol=crlf
*.docx diff=astextplain
*.DOCX diff=astextplain
# absolute paths are ok, as are globs
/**/postinst* text eol=lf
# paths that don't start with / are treated relative to the .gitattributes folder
relative/path/*.txt text eol=lf
对于最流行的编程语言,有一个方便的 collection of ready to use .gitattributes files。帮助您入门很有用。
创建或调整 .gitattributes
后,您应该执行一次性的 line endings re-normalization。
请注意,在您在应用中打开项目的 Git 存储库后,GitHub Desktop 应用可以建议并创建一个 .gitattributes
文件。要尝试这样做,请单击齿轮图标(在右上角)>存储库设置...>行尾和属性。系统会要求您添加推荐的 .gitattributes
,如果您同意,该应用程序还将对您的存储库中的所有文件执行规范化。
最后,Mind the End of Your Line 文章提供了更多背景知识,并解释了 Git 如何在手头的问题上发展。我认为这是必读。
您的团队中可能有用户使用 EGit 或 JGit(Eclipse 和 TeamCity 等工具使用它们)来提交他们的更改。然后你不走运,正如@gatinueta 在这个答案的评论中解释的那样:
如果您的团队中有使用 Egit 或 JGit 的人,此设置将无法完全满足您,因为这些工具只会忽略 .gitattributes 并愉快地签入 CRLF 文件 https://bugs.eclipse.org/bugs/show_bug.cgi?编号=342372
一个技巧可能是让他们在另一个客户端中提交更改,例如 SourceTree。那时,我们的团队在许多用例中更喜欢使用该工具而不是 Eclipse 的 EGit。
谁说软件很简单? :-/
不要转换行尾。解释数据不是 VCS 的工作——只是存储和版本化它。无论如何,每个现代文本编辑器都可以读取这两种行尾。
除非您真的知道自己在做什么,否则您几乎总是想要 autocrlf=input
。
下面的一些附加上下文:
如果你喜欢 DOS 结尾,它应该是 core.autocrlf=true,如果你喜欢 unix-newlines,它应该是 core.autocrlf=input。在这两种情况下,您的 Git 存储库都将只有 LF,这是正确的。 core.autocrlf=false 的唯一参数是自动启发式可能会错误地将某些二进制文件检测为文本,然后您的图块将被损坏。因此,引入了 core.safecrlf 选项以在发生不可逆转的更改时警告用户。事实上,不可逆转的更改有两种可能性——文本文件中的混合行尾,在这种规范化中是可取的,所以可以忽略这个警告,或者(非常不可能)Git 错误地将你的二进制文件检测为文本。然后你需要使用属性告诉Git这个文件是二进制的。
上述段落最初是从 gmane.org 上的一个线程中提取的,但此后它已被删除。
core.autocrlf=input
是规范答案。对于大多数用例,core.autocrlf=true
和 core.autocrlf=false
过于热情(……当然,以相反但同样可怕的方式),因此具有内在的破坏性。 “Git for Windows”应该真的附带“按原样结帐,提交 Unix 样式的行尾”(即 core.autocrlf=input
)作为其默认换行策略。它没有。所以我们在这里——in frickin' 2015——仍在无休止地争论这个问题。
在混合环境(Microsoft + Linux + Mac)中获得一致的行尾的两种替代策略:
A. 全局所有存储库设置
将所有转换为一种格式 find . -type f -not -path "./.git/*" -exec dos2unix {} \; git commit -a -m 'dos2unix conversion' 将 core.autocrlf 设置为 Linux/UNIX 上的输入或 MS Windows(存储库或全局)上的 true git config --global core.autocrlf input 可选地,将 core.safecrlf 设置为 true(停止) 或警告 (唱:) 添加额外的保护比较反向换行符转换是否会导致相同的文件 git config --global core.safecrlf true
B. 或按存储库设置
将所有转换为一种格式 find . -type f -not -path "./.git/*" -exec dos2unix {} \; git commit -a -m 'dos2unix conversion' 将 .gitattributes 文件添加到您的存储库 echo "* text=auto" > .gitattributes git add .gitattributes git commit -m 'adding .gitattributes for统一行尾'
不要担心你的二进制文件——Git 应该对它们足够聪明。
More about safecrlf/autocrlf variables
dos2unix
是一个命令行工具,取决于您可能需要额外安装的系统
dos2unix
时要非常小心 - 存在 corrupting .git/index
的风险,我们不需要将其应用于每个文件。最好使用 find ./ -name "*.html"
之类的内容并指定要将其应用于哪些文件。
find
行之前,请注意:Windows 版 Git 附带的 dos2unix
有一个特殊的(IMO 愚蠢和危险的)行为,没有参数:它不是更改为 UNIX,而是 切换 换行格式 (DOS <-> UNIX)
--- 更新 3 ---(与更新 2 不冲突)
考虑到 Windows 用户更喜欢在 CRLF
上工作而 linux/mac 用户更喜欢在 LF
上处理文本文件的情况。从存储库维护者的角度提供答案:
对我而言,最佳策略(要解决的问题更少)是:将 所有文本文件与 LF
保存在 git repo 中,即使您正在工作在仅限 Windows 的项目上。然后让客户自由处理他们喜欢的行尾样式,前提是他们选择的core.autocrlf
属性值将尊重您的策略(LF on repo) 暂存文件以进行提交。
分期是许多人在尝试了解换行策略如何工作时所混淆的。在为 core.autocrlf
属性选择正确值之前,必须了解以下几点:
添加文本文件以进行提交(暂存)就像将文件复制到 .git/ 子目录中的另一个位置,并转换了行尾(取决于客户端配置上的 core.autocrlf 值)。所有这些都是在本地完成的。
设置 core.autocrlf 就像提供问题的答案(在所有操作系统上完全相同的问题):“应该 git-client:a. 在从远程签出(拉出)repo 更改时将 LF 转换为 CRLF?b . 为提交添加文件时将 CRLF 转换为 LF?”
一个。从远程签出(拉出)回购更改时将LF转换为CRLF?
湾。添加文件以提交时将 CRLF 转换为 LF?”
可能的答案(值)是:假:“以上都不做”,输入:“只做b”真:“做a和b”注意没有“只做a”
false: "以上都不做",
输入:“只做b”
真:“做 a 和 b”
请注意,没有“只做一个”
幸运的是
git 客户端默认值 (windows: core.autocrlf: true, linux/mac: core.autocrlf: false) 将与 LF-only-repo 策略兼容。含义:默认情况下,Windows 客户端在签出存储库时将转换为 CRLF,并在添加提交时转换为 LF。默认情况下,Linux 客户端不会进行任何转换。从理论上讲,这使您的 repo 仅保留。
很遗憾:
可能有不尊重 git core.autocrlf 值的 GUI 客户端
可能有些人不使用价值来尊重您的 lf-repo 策略。例如,他们使用 core.autocrlf=false 并添加一个带有 CRLF 的文件以进行提交。
要尽快检测上述客户端提交的非 lf 文本文件,您可以按照 --- update 2 ---: (git grep -I --files-with-matches --perl-regexp '\r' HEAD
, on a client compiled using: --with-libpcre
旗帜)
这是关键:。我作为 repo 维护者保留一个 git.autocrlf=input
以便我可以通过再次添加它们来修复任何错误提交的文件以进行提交。我提供了一个提交文本:“修复错误提交的文件”。
就 .gitattributes
而言。我不指望它,因为有更多的ui客户端不理解它。我只用它来为文本和二进制文件提供提示,并可能标记一些应该在任何地方都保持相同行尾的特殊文件:
*.java text !eol # Don't do auto-detection. Treat as text (don't set any eol rule. use client's)
*.jpg -text # Don't do auto-detection. Treat as binary
*.sh text eol=lf # Don't do auto-detection. Treat as text. Checkout and add with eol=lf
*.bat text eol=crlf # Treat as text. Checkout and add with eol=crlf
问题:但是为什么我们对换行处理策略感兴趣呢?
回答:为避免单个字母更改提交,显示为 5000 行更改,因为执行更改的客户端在添加提交之前将完整文件从 crlf 自动转换为 lf(或相反)。当涉及解决冲突时,这可能会相当痛苦。或者在某些情况下它可能是不合理冲突的原因。
--- 更新 2 ---
git 客户端的默认设置在大多数情况下都会起作用。即使您只有 Windows 客户端、Linux 客户端或两者都有。这些是:
windows: core.autocrlf=true 表示结帐时将行转换为 CRLF,添加文件时将行转换为 LF。
linux: core.autocrlf=input 表示不要在结帐时转换行(不需要,因为文件预计会使用 LF 提交)并在添加文件时将行转换为 LF(如果需要)。 (-- update3 -- : 似乎默认情况下这是错误的,但又没问题)
该属性可以在不同的范围内设置。我建议在 --global
范围内明确设置,以避免最后描述的一些 IDE 问题。
git config core.autocrlf
git config --global core.autocrlf
git config --system core.autocrlf
git config --local core.autocrlf
git config --show-origin core.autocrlf
此外,我强烈不鼓励使用 在 Windows 上 git config --global core.autocrlf false
(如果您只有 Windows 客户端)与建议的内容相反 {1 }。设置为 false 将在 repo 中提交带有 CRLF 的文件。但是真的没有理由。您永远不知道是否需要与 linux 用户共享项目。另外,对于每个加入项目而不是使用默认值的客户来说,这是一个额外的步骤。
现在对于某些特殊情况的文件(例如 *.bat
*.sh
),您希望它们使用 LF 或 CRLF 签出,您可以使用 .gitattributes
总结一下我的最佳实践是:
确保在 git repo 上使用 LF 提交每个非二进制文件(默认行为)。
使用此命令确保没有使用 CRLF 提交任何文件: git grep -I --files-with-matches --perl-regexp '\r' HEAD (注意:在 Windows 客户端上只能通过 git-bash 和在 linux 上工作客户端仅在使用 ./configure 中的 --with-libpcre 编译时)。
如果您通过执行上述命令找到任何此类文件,请更正它们。这涉及(至少在 linux 上): set core.autocrlf=input (--- update 3 --) 更改文件 恢复更改(文件仍显示为已更改)提交它
设置 core.autocrlf=input (--- 更新 3 --)
更改文件
还原更改(文件仍显示为已更改)
提交它
仅使用最低限度的 .gitattributes
指示用户将上述 core.autocrlf 设置为其默认值。
不要指望 .gitattributes 的存在 100%。 IDE 的 git-clients 可能会忽略它们或区别对待它们。
如前所述,可以在 git 属性中添加一些内容:
# Always checkout with LF
*.sh text eol=lf
# Always checkout with CRLF
*.bat text eol=crlf
我认为 .gitattributes
有一些其他安全选项,而不是对二进制文件使用自动检测:
-text(例如,对于 *.zip 或 *.jpg 文件:不会被视为文本。因此不会尝试行尾转换。通过转换程序可能会出现差异)
text !eol(例如,对于 *.java、*.html:视为文本,但未设置 eol 样式首选项。因此使用客户端设置。)
-text -diff -merge(例如,对于 *.hugefile:不被视为文本。没有 diff/merge 可能)
--- 以前的更新 ---
错误提交文件的客户端的一个痛苦示例:
netbeans 8.2(在 Windows 上)会错误地提交所有带有 CRLF 的文本文件,除非您明确将 core.autocrlf
设置为全局。这与标准的 git 客户端行为相矛盾,并在以后更新/合并时导致很多问题。这就是使某些文件看起来不同(尽管它们不是)即使您还原的原因。
即使您添加了正确的 {2 } 到你的项目。
在提交后使用以下命令,至少可以帮助您及早检测您的 git repo 是否存在行尾问题:git grep -I --files-with-matches --perl-regexp '\r' HEAD
我花了好几个小时想出最好的 .gitattributes
用法,最终意识到,我不能指望它。
不幸的是,只要存在基于 JGit 的编辑器(无法正确处理 .gitattributes
),安全的解决方案就是在任何地方强制使用 LF,即使在编辑器级别也是如此。 罢工>
使用以下抗 CRLF 消毒剂。
windows/linux 客户端:core.autocrlf=input
提交的 .gitattributes: * text=auto eol=lf
提交的 .editorconfig (http://editorconfig.org/) 这是一种标准化格式,结合编辑器插件:https://github.com/editorconfig/ https://github.com/welovecoding/editorconfig-netbeans/
https://github.com/editorconfig/
https://github.com/welovecoding/editorconfig-netbeans/
.gitattributes
行,它在 Git < 中有意想不到的后果。 2.10,见stackoverflow.com/a/29508751/2261442
git config --global core.autocrlf false
的答案,并建议仅在 .gitattributes
指令中处理 eol。
一旦我在我的 Visual Studio 2010 项目中签出所有文件,使用 core.autocrlf=false
就不会将它们标记为已更新。开发团队的另外两名成员也使用 Windows 系统,因此混合环境没有发挥作用,但存储库附带的默认设置始终将所有文件标记为克隆后立即更新。
我想底线是找到适合您环境的 CRLF 设置。特别是因为在我们的 Linux 机器上的许多其他存储库中,设置 autocrlf = true
会产生更好的结果。
20 多年过去了,我们仍在处理操作系统之间的行尾差异……可悲。
尝试将 core.autocrlf
配置选项设置为 true
。另请查看 core.safecrlf
选项。
实际上听起来 core.safecrlf
可能已经在您的存储库中设置,因为(强调我的):
如果 core.autocrlf 的当前设置不是这种情况,git 将拒绝该文件。
如果是这种情况,那么您可能需要检查您的文本编辑器是否配置为一致地使用行尾。如果文本文件包含 LF 和 CRLF 行尾的混合,您可能会遇到问题。
最后,我觉得在 Windows 上简单地“使用你给定的”和使用 LF 终止行的建议会导致比它解决的问题更多的问题。 Git 有上述选项可以尝试以合理的方式处理行尾,因此使用它们是有意义的。
这是 Windows 和 Visual Studio 用户与 Mac 或 Linux 用户共享代码的两个选项。有关详细说明,请阅读 gitattributes manual。
* 文字=自动
在您的存储库的 .gitattributes
文件中添加:
* text=auto
这将规范化 repo 中所有以 LF
行结尾的文件。
并且根据您的操作系统(core.eol
设置),工作树中的文件将被标准化为 LF
(对于基于 Unix 的系统)或 CRLF
(对于 Windows 系统)。
这是 Microsoft .NET 存储库使用的配置。
例子:
Hello\r\nWorld
将在 repo 中标准化为:
Hello\nWorld
结帐时,Windows 中的工作树将转换为:
Hello\r\nWorld
在结帐时,Mac 中的工作树将保留为:
Hello\nWorld
注意:如果您的 repo 已经包含未规范化的文件,git status 将在您下次对它们进行任何更改时将这些文件显示为完全修改,并且其他用户稍后合并他们的更改可能会很痛苦。有关更多信息,请参阅更改行尾后刷新存储库。
core.autocrlf = true
如果 .gitattributes
文件中未指定 text
,Git 将使用 core.autocrlf
配置变量来确定是否应转换文件。
对于 Windows 用户,git config --global core.autocrlf true
是一个不错的选择,因为:
只有在添加到 repo 时,文件才会被规范化为 LF 行结尾。如果 repo 中有未规范化的文件,此设置将不会触及它们。
所有文本文件都转换为工作目录中的 CRLF 行尾。
这种方法的问题在于:
如果您是使用 autocrlf = 输入的 Windows 用户,您将看到一堆以 LF 行结尾的文件。对团队的其他成员来说不是危险,因为您的提交仍将使用 LF 行结尾进行规范化。
如果您是 core.autocrlf = false 的 Windows 用户,您将看到一堆以 LF 行结尾的文件,您可以将带有 CRLF 行结尾的文件引入 repo。
大多数 Mac 用户使用 autocrlf = 输入,并且可能会从带有 core.autocrlf = false 的 Windows 用户那里获得带有 CRLF 文件结尾的文件。
git config --global core.autocrl true
。你的意思是git config --global core.autocrlf true
。
这只是一个解决方法:
在正常情况下,使用 git 附带的解决方案。这些在大多数情况下都很好用。如果您通过设置 .gitattributes 在基于 Windows 和 Unix 的系统上共享开发,则强制使用 LF。
在我的例子中,有超过 10 个程序员在 Windows 中开发一个项目。这个项目是用 CRLF 签入的,没有强制到 LF 的选项。
一些设置是在我的机器内部编写的,对 LF 格式没有任何影响;因此,在每次小文件更改时,一些文件都会全局更改为 LF。
我的解决方案:
Windows-Machines:让一切保持原样。什么都不在乎,因为您是默认的 Windows '孤狼'开发人员,您必须像这样处理:“世界上没有其他系统,是吗?”
Unix机器
将以下行添加到配置的 [alias] 部分。此命令列出所有更改(即修改/新)的文件: lc = "!f() { git status --porcelain \ | egrep -r \"^(\?| ).\*\\(.[a-zA -Z])*\" \ | cut -c 4- ; }; f " 将所有更改的文件转换为 dos 格式: unix2dos $(git lc) 可选...为此操作创建一个 git 挂钩以自动化此过程使用参数并包含它并修改 grep 函数以仅匹配特定的文件名,例如:... | egrep -r "^(\?| ).*\.(txt|conf)" | ...随意使用附加快捷方式使其更加方便: c2dos = "!f() { unix2dos $(git lc) ; }; f " ... 并通过键入 git c2dos 触发转换后的内容
.gitattributes
?core.autocrlf = false
- 我更喜欢任何地方的 LF,但一些 Windows 工具(如 Visual Studio)坚持在某些文件中使用 CRLF 结尾(甚至将它们混合在一些文件中......);不修改行尾是最安全的选择。如果您知道自己在做什么,我可能会使用core.autocrlf = input
并为您知道对行尾敏感的 Windows 项目设置例外。正如其他人指出的那样,现在每个体面的文本编辑器都支持 LF 结尾。我实际上认为core.autocrlf = true
可能会造成比它所阻止的更多的麻烦。*.sh text eol=lf