使用Git最好的CRLF(回车,换行)处理策略是什么?


598

我尝试使用CRLF结尾行提交文件,但失败。

我在Windows计算机上花了整整一天的时间来尝试不同的策略,但几乎被迫停止使用Git并尝试使用Mercurial

每个答案仅分享一个最佳实践。

Answers:


753

问了这个问题将近四年之后,我终于找到了一个完全令我满意的答案

请参阅github:help行尾处理指南中 的详细信息。

Git的允许您设置为结束直接使用回购性质的行文本属性.gitattributes的文件。该文件将提交到存储库中并覆盖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

对于大多数流行的编程语言,都有一个方便的现成可用的.gitattributes文件集合。这对您入门很有帮助。

创建或调整后.gitattributes,您应该对所有行尾进行一次归一化

请注意,在应用程序中打开项目的Git存储库后,GitHub Desktop应用程序可以建议并创建.gitattributes文件。要尝试此操作,请单击齿轮图标(位于右上角)>存储库设置...>行的结尾和属性。系统将要求您添加推荐的内容.gitattributes,如果您同意,该应用程序还将对存储库中的所有文件进行规范化。

最后,“ 尽你所能”一文提供了更多背景知识,并解释了Git在当前问题上的发展。我认为这是必读的

您的团队中可能已经有使用EGit或JGit的用户(Eclipse和TeamCity之类的工具使用它们)来提交更改。然后,您就走运了,就像@gatinueta在此答案的评论中解释的那样:

如果您的团队中有使用Egit或JGit的人员,此设置将无法完全满足您的需要,因为这些工具只会忽略.gitattributes并愉快地检入CRLF文件https://bugs.eclipse.org/bugs/show_bug.cgi? id = 342372

一个提示可能是让他们在另一个客户端中提交更改,如SourceTree。那时,我们的团队在许多用例中都喜欢使用Eclipse的EGit工具。

谁说软件很简单?:-/


7
关心共享Windows .gitattributes
Panic Panic 2012年

您如何查看.gitattributesGitHub for Windows对您的项目有何建议?我安装了适用于Windows的GitHub,启动了GUI版本,但找不到与.gitattributes建议相关的任何选项。
JLDiaz 2013年

4
如果您的团队中有与Egit合作的人员,此设置将无法完全满足您的需要,因为egit只会忽略.gitattributes并愉快地检入CRLF文件bugs.eclipse.org/bugs/show_bug.cgi?id=342372
gatinueta

19
对于Windows,我通常倾向于设置全局变量core.autocrlf = false-我更喜欢在任何地方使用LF,但是某些Windows工具(如Visual Studio)坚持在某些文件中使用CRLF结尾(甚至将它们混合在几个文件中。);不更改行尾是最安全的选择。如果您知道自己在做什么,我可能core.autocrlf = input会对Windows上对行尾敏感的项目使用例外。正如其他人指出的那样,每个体面的文本编辑器现在都支持LF结尾。我实际上认为core.autocrlf = true可能会造成更多的麻烦,而不是无法避免。
阿德里安

1
@gatinueta更具体地说,这是一个JGit问题。含义TeamCity(也使用JGit)直接忽略.gitattributes。
2014年

122

不要转换行尾。解释数据不是VCS的工作-只是存储和版本化数据。每个现代的文本编辑器都可以读取两种行尾。


25
第二。如果您遇到行尾不一致的问题,最好的解决方案是对使用错误的编辑器设置的人大喊大叫,直到他们修复该错误。

136
不同意。所有平台上的本机换行很方便。
乔纳斯·比斯特伦(JonasByström)2010年

25
除了CRLF之外,Visual Studio都是PITA。
Brett Ryan 2010年

32
Git有一个不转换行尾的选项,它是autocrlf = false,除非您正在进行跨平台开发,例如说Mono,否则最好在Windows下运行时留为false;如果要开发开源,则设置为true。单声道。
克里斯·尼古拉

24
行尾的问题是计算正确的差异。因此,答案是错误的且具有误导性。
cos 2012年

84

autocrlf=input除非您真的知道自己在做什么,否则您几乎总是想要。

以下是一些其他上下文:

core.autocrlf=true如果您喜欢DOS结束,或者core.autocrlf=input您喜欢unix-newlines ,则应该是。在这两种情况下,您的Git存储库将只有LF,这是正确的事情。唯一的论据core.autocrlf=false是自动启发式可能会错误地将某些二进制文件检测为文本,然后您的图块将被破坏。因此, core.safecrlf引入了一个选项来警告用户是否发生了不可逆的更改。实际上,存在两种不可逆更改的可能性-文本文件中混合的行尾,在这种规范化中是可取的,因此可以忽略此警告,或者(极不可能)Git错误地将二进制文件检测为文本。然后,您需要使用属性来告诉Git该文件是二进制文件。

上一段最初是从gmane.org上的一个线程中拉出来的,但是此后就消失了。


31
为什么是“正确的事情”?
Artem Tikhomirov

35
core.autocrlf = true是一个糟糕的主意。我对该选项没有任何麻烦,而且您必须记住在克隆存储库时进行设置。
路易斯·奥利维拉(LuísOliveira)2010年

28
除非您知道自己在做什么,否则请勿使用autocrlf = true。如果您使用DOS / Win开发,则autocrlf = false将使远程和本地存储库的结尾保持相同,并且在几乎每种情况下都是最佳选择。
克里斯·尼古拉

13
@Chris-如果您的开发人员具有Windows和多平台项目,其中一些多平台开发人员在OSX或Linux上工作,该怎么办?那么最好的选择应该不是autocrlf = true吗?
Brett Ryan

20
已投票支持,但有保留。引言部分无济于事。core.autocrlf=input是规范的答案。对于大多数使用情况,core.autocrlf=true以及core.autocrlf=false过于热心(...相反,但同样可怕的方式,当然,),因此内在的破坏性。“ Git for Windows” 确实应该附带“按原样签出,提交Unix样式的行尾”(即core.autocrlf=input)作为默认的换行策略。没有。因此,在这里- 在2015Frickin上 -我们仍在无休止地辩论这一点。
Cecil Curry 2015年

58

为了使混合环境(Microsoft + Linux + Mac)中的行尾保持一致,有两种替代策略:

A. 每个存储库的全局设置

1)全部转换为一种格式

find . -type f -not -path "./.git/*" -exec dos2unix {} \;
git commit -a -m 'dos2unix conversion'

2)设置core.autocrlfinput在Linux / UNIX或true在MS Windows(库或全球)

git config --global core.autocrlf input

3)[可选]设置core.safecrlftrue(停止)或warn(唱歌:)以添加额外的保护,以比较反向换行符转换是否会导致相同文件

git config --global core.safecrlf true


B.或按存储库设置

1)全部转换为一种格式

find . -type f -not -path "./.git/*" -exec dos2unix {} \;
git commit -a -m 'dos2unix conversion'

2)将.gitattributes文件添加到您的存储库

echo "* text=auto" > .gitattributes
git add .gitattributes
git commit -m 'adding .gitattributes for unified line-ending'

不用担心您的二进制文件-Git对它们应该足够聪明。


有关safecrlf / autocrlf变量的更多信息


5
全局方法 ==设置并忘记所有回购与每个回购 ==不需要其他人更改其全局配置。
lukmdo 2012年

4
dos2unix是一个命令行工具,具体取决于系统,您可能需要另外安装
lukmdo 2012年

2
它们不是唯一的,您可以同时使用两种方法。另外,使用时请务必小心dos2unix-存在损坏.git/index的风险,我们不需要将其应用于每个文件。最好使用类似的东西,find ./ -name "*.html"并指定要应用到的文件。
cregox

6
警告:在运行命令find行之前,请注意:dos2unixGit for Windows附带的行为具有特殊的(IMO愚蠢和危险的)行为,没有任何参数:而不是更改为UNIX,而是切换了换行格式(DOS <-> UNIX )
leonbloy

2
另一个警告:不要在DOS2UNIX的.git文件夹中。只是说。
hakre 2014年

10

尝试将core.autocrlf配置选项设置为true。也可以看看该core.safecrlf选项。

实际上,这听起来core.safecrlf可能已经在您的存储库中设置了,因为(强调我的):

如果当前的core.autocrlf设置不是这种情况,则git将拒绝该文件

如果是这种情况,那么您可能要检查文本编辑器是否配置为一致地使用行尾。如果文本文件包含LF和CRLF行尾的混合,您可能会遇到问题。

最后,我认为建议简单地“使用给出的内容”并在Windows上使用LF终止的行将引起更多的问题,而不是解决的问题。Git具有以上选项,试图以一种明智的方式处理行尾,因此使用它们很有意义。


1
通过.gitattributes文件使用存储库范围的设置会更好吗?只是想知道:强迫每个用户在机器上照顾他的行结束设置是不方便的……还是还有其他缺点?
trainoasis

10

core.autocrlf=false当我在Visual Studio 2010项目中检出它们时,using 停止了所有文件的标记为更新的操作。开发团队的其他两个成员也在使用Windows系统,因此没有使用混合环境,但是存储库随附的默认设置始终将所有文件标记为在克隆后立即更新。

我想最重要的是找到适合您的环境的CRLF设置。尤其是因为在我们Linux盒子上的许多其他存储库中,设置autocrlf = true会产生更好的结果。

20多年后的今天,我们仍在处理OS之间的行尾差异……令人遗憾。


31
@ orange80,这种差异是不幸的,但是没有理由将其称为Windows的错误。从最低限度的角度来看,仅LF才有意义。但是根据CR和LF的含义,CRLF更有意义。“回车”是指返回到行首;“换行”是指直接向下移动到下一行,而不是下一行的开头。从语义的角度来看,Windows在以下两个方面更为正确:返回到开头(CR),然后向下一行(LF)。
瑞安·伦迪

40
@Kyralessa“更正确”,仍然假装一台计算机是一台打字机,但事实并非如此。考虑到这不是最终用户将要处理的事情,保持打字机类比没有任何意义,而且两个字符而不是一个字符是没有意义的。
jpswain 2011年

1
这次聚会晚了几年,但是您忽略了CR和LF是光标定位工具的事实。在历史的这一点上,“ CR”也可能是“游标返回”。如果我希望光标返回到行的开头,我会告诉应用程序执行此操作。否则,它需要留在我放置的位置。
EKW

2
同样,如果CRLF是“更正确的”,因为文本文件换行符实际上既是“向下移动一行”又是“向下移动到行首”,则可以认为仅CR会导致文本编辑器用下一行。我知道实际上没有哪个编辑器支持此功能,这意味着实际上不存在将CRLF和CR表示为不同事物的需求。
avl_sweden

@avl_sweden在DOS之前,这是非常普遍的行为,并且由于Microsoft认为兼容性很重要,因此从那以后它一直保持这种状态。这也是美国(作为pere ASA)的标准方式-ISO允许CR + LF和LF(所以再次,DOS符合标准);在这两种情况下,都是从六十年代开始。Multics(Unix前身)支持CR进行粗体/删除。如今,许多应用程序(包括.NET的“按行分隔”功能)都查找这三个(单独的CR,单独的LF,CRLF)中的任何一个,并将它们中的每一个都视为结束行。但是,许多应用程序仍然对文件中混合的行尾感到困惑。
六安

7

这是WindowsVisual Studio用户与MacLinux用户共享代码的两个选项。有关详细说明,请阅读gitattributes手册

*文字=自动

在回购.gitattributes文件中添加:

*   text=auto

这将规范化仓库中所有以LF行结尾的文件。

并且,根据您的操作系统(core.eol设置),工作树中的文件将被标准化LF为基于Unix的系统或CRLFWindows系统。

这是Microsoft .NET存储库使用的配置。

例:

Hello\r\nWorld

将在回购中始终归一化为:

Hello\nWorld

签出时,Windows中的工作树将转换为:

Hello\r\nWorld

结帐时,Mac中的工作树将保留为:

Hello\nWorld

注意:如果您的存储库中已经包含未规范化的git status文件,则下次您对它们进行任何更改时,这些文件将显示为已完全修改,并且其他用户以后合并它们的更改可能会很痛苦。有关更多信息,请参见更改行尾后刷新存储库

core.autocrlf =真

如果text.gitattributes文件中未指定if ,则Git使用core.autocrlf配置变量来确定是否应转换文件。

对于Windows用户,git config --global core.autocrlf true是一个不错的选择,因为:

  • 仅当将文件添加到仓库中,它们才被标准化为LF行尾。如果存储库中有未规范化的文件,则此设置将不会影响它们。
  • 所有文本文件都将转换为CRLF工作目录中的行尾。

这种方法的问题是:

  • 如果您是Windows用户autocrlf = input,则将看到一堆带有LF行尾的文件。对于团队其他成员而言,这没有危险,因为您的提交仍将使用LF行尾进行标准化。
  • 如果您是Windows用户core.autocrlf = false,则将看到一堆带有LF行尾的文件,并且可以将带有CRLF行尾的文件引入仓库。
  • 大多数Mac用户使用Windows并可能以Windows结尾的Windows用户使用autocrlf = input带有CRLF文件结尾的文件core.autocrlf = false

1
Windows用户的命令说git config --global core.autocrl true。你是说git config --global core.autocrlf true
JellicleCat

6

---更新3 ---(与更新2不冲突)

考虑到Windows用户喜欢使用文本文件,CRLF而linux / mac用户喜欢LF使用文本文件的情况。从存储库维护者角度提供答案:

对我来说,最好的策略(少的问题解决)是:保留所有文本文件LF内部的git回购,即使你是一个只有Windows的项目。然后,让客户可以自由选择其首选项行尾样式,前提是他们选择一个core.autocrlf属性值,该属性值在暂存提交文件时会尊重您的策略(回购交易中的LF)

分阶段是很多人在试图了解换行策略如何工作时会感到困惑的地方。在为core.autocrlf属性选择正确的值之前,必须理解以下几点:

  • 增加对提交(文本文件分期的话)是一样的文件复制到另一个地方,里面.git/的子目录与转换行结束(取决于core.autocrlf值在客户端的配置)。所有这些都是在本地完成的
  • 设置core.autocrlf就像提供问题的答案(在所有操作系统上都是相同的问题):
    • “ git-client 是a。 从远程签出(拉出)回购更改时应将LF转换为CRLF,还是b。 添加要提交的文件时应将CRLF转换为LF? ”以及可能的答案(值)是:
    • false:以上都不 ”,
    • input:仅有B
    • true:“ a和b
    • 请注意,没有“ 只能做一个

幸好

  • git客户端默认值(windows:core.autocrlf: true,linux / mac:) core.autocrlf: false将与LF-only-repo策略兼容。
    含义:Windows客户端默认在签出存储库时将转换为CRLF,并在添加提交时转换为LF。缺省情况下,Linux客户端不会进行任何转换。从理论上讲,这仅使您的仓库保持只读。

不幸:

  • 可能有一些GUI客户端不遵守git core.autocrlf
  • 可能有些人不使用价值来尊重您的lf-repo策略。例如,他们使用core.autocrlf=falseCRLF并添加带有CRLF的文件进行提交。

要检测上述客户端提交的ASAP非lf文本文件,您可以按照---更新2 ---:(git grep -I --files-with-matches --perl-regexp '\r' HEAD,在使用:--with-libpcre标志编译的客户端上)进行描述。

这是要抓住的地方:。我作为回购维护者保留一个,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 client的dafaults在大多数情况下都可以使用。即使您只有Windows仅客户机,Linux仅客户机或两者都有。这些是:

  • Windows: core.autocrlf=true表示在结帐时将行转换为CRLF,并在添加文件时将行转换为LF。
  • linux: core.autocrlf=input意味着在结帐时不转换行(不需要,因为期望文件使用LF提交),并且在添加文件时将行转换为LF(如果需要)。(-update3-:看来这是false默认设置,但也可以)

可以在不同的范围内设置该属性。我建议显式设置--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

另外,与git documentation 相比,我强烈建议不要在Windows上 使用git config --global core.autocrlf false(如果您只有Windows客户端)。设置为false将在仓库中提交带有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客户端仅在使用编译--with-libpcre./configure)。
  • 如果通过执行上述命令找到任何此类文件,请更正它们。这涉及(至少在Linux上):
    • 设置core.autocrlf=input-更新3-
    • 更改文件
    • 还原更改(文件仍显示为更改)
    • 提交
  • 仅使用最低限度 .gitattributes
  • 指示用户core.autocrlf将上述内容设置为其默认值。
  • 请勿将100%计为存在.gitattributes。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::不被视为文本。不能进行差异/合并)

-以前的更新-

客户端错误提交文件的一个痛苦示例

netbeans 8.2(在Windows上)将错误地提交所有带有CRLF的文本文件,除非您已明确将其设置core.autocrlf为global。这与标准的git客户行为相矛盾,并在以后更新/合并时引起很多问题。这就是使某些 文件即使在还原时也看起来有所不同(尽管它们没有差异)的原因。
即使您.gitattributes向项目中添加了正确的代码,在netbeans中也会发生相同的行为。

提交后使用以下命令,至少可以帮助您及早发现git repo是否存在行尾问题: git grep -I --files-with-matches --perl-regexp '\r' HEAD

我花了几个小时来想尽最大可能地使用.gitattributes,最终意识到我不能指望它。
不幸的是,只要存在基于JGit的编辑器(无法.gitattributes正确处理),安全的解决方案就是即使在编辑器级别也将LF强制到处。

使用以下anti-CRLF消毒剂。


我同意您的观点,这是最好的方法,没有LF支持的人都不能使用编辑器。但是请注意您的.gitattributes生产线,它在Git <2.10中有意想不到的后果,请参见stackoverflow.com/a/29508751/2261442
phk

真是的...我有很多主张git config --global core.autocrlf false,并建议.gitattributes仅在指令中处理eol 的答案。
VonC

5

这只是一个解决方法:

在正常情况下,请使用git随附的解决方案。在大多数情况下,这些效果很好。如果通过设置.gitattributes共享基于Windows和Unix的系统上的开发,请强制使用LF 。

以我为例,有十多个程序员在Windows中开发项目。该项目已通过CRLF签入,没有选择强制使用LF。

有些设置是在我的机器上内部写入的,而不会影响LF格式;因此,每次小文件更改时,某些文件就会全局更改为LF。

我的解决方案:

Windows机器: 让一切保持原样。不用担心,因为您是默认的Windows'lone wolf'开发人员,因此您必须像这样处理:“广阔的世界上没有其他系统了,对吗?”

Unix机器

  1. 将以下行添加到配置[alias]部分。此命令列出所有已更改(即已修改/新)的文件:

    lc = "!f() { git status --porcelain \
                 | egrep -r \"^(\?| ).\*\\(.[a-zA-Z])*\" \
                 | cut -c 4- ; }; f "
  2. 将所有这些更改的文件转换为dos格式:

    unix2dos $(git lc)
  3. 选择性地...

    1. 为此操作创建一个git 挂钩,以自动执行此过程

    2. 使用参数并将其包含在内并修改grep函数以仅匹配特定的文件名,例如:

      ... | egrep -r "^(\?| ).*\.(txt|conf)" | ...
    3. 随意使用其他快捷方式使其更加方便:

      c2dos = "!f() { unix2dos $(git lc) ; }; f "

      ...并输入以下内容触发转换后的内容

      git c2dos
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.