650

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

我花了一整天的时间在我的 Windows 电脑上尝试不同的策略,几乎被吸引停止尝试使用 Git 而是尝试Mercurial

如何正确处理 CRLF 行尾?

4

9 回答 9

811

问了这个问题快四年了,我终于找到了一个让我完全满意的答案

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

Git 允许您直接使用文件中 的text 属性.gitattributes为 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

对于最流行的编程语言,有一个方便的即用型 .gitattributes 文件集合。帮助您入门很有用。

一旦你创建或调整了你的.gitattributes,你应该执行一次一劳永逸的行尾重新规范化

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

最后,请注意行尾文章提供了更多背景信息,并解释了 Git 在手头的问题上是如何演变的。我认为这是必读的。

您的团队中可能有用户使用 EGit 或 JGit(Eclipse 和 TeamCity 等工具使用它们)来提交他们的更改。然后你不走运,正如@gatinueta 在这个答案的评论中解释的那样:

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

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

谁说软件很简单?:-/

于 2012-06-01T18:56:35.800 回答
127

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

于 2008-10-04T20:42:06.417 回答
83

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

下面的一些附加上下文:

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

上述段落最初是从 gmane.org 上的一个线程中提取的,但此后它已被删除。

于 2009-07-10T22:36:55.893 回答
60

在混合环境(Microsoft + Linux + Mac)中获得一致的行尾的两种替代策略:

A. 全局所有存储库设置

  1. 全部转换为一种格式

    find . -type f -not -path "./.git/*" -exec dos2unix {} \;
    git commit -a -m 'dos2unix conversion'
    
  2. 在 Linux/UNIX 或MS Windows(存储库或全局)上设置core.autocrlfinputtrue

    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 变量的更多信息

于 2012-06-26T01:18:10.747 回答
14

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

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

对我来说,最好的策略(要解决的问题更少)是:将所有文本文件保存在LFgit repo中,即使您正在处理仅限 Windows 的项目。然后让客户自由地使用他们偏好的行尾样式,前提是他们在暂存文件以进行提交时选择了一个尊重您的策略的core.autocrlf属性值(LF on repo) 。

分期是许多人在试图了解换行策略如何工作时感到困惑的地方。core.autocrlf在选择正确的财产价值之前,必须了解以下几点:

  • 添加文本文件以进行提交(暂存它)就像将文件复制到具有转换的行尾的子目录内的另一个位置(取决于您的客户端配置中的值)。所有这些都是在本地完成的。.git/core.autocrlf
  • 设置core.autocrlf就像提供问题的答案(在所有操作系统上完全相同的问题): “应该 git-client:
    • 一种。 从远程签出(拉出)repo 更改时将 LF 转换为 CRLF吗?
    • 湾。 添加文件以提交时将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 客户端不会进行任何转换。从理论上讲,这使您的 repo 仅保留。

很遗憾:

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

要检测上述客户端提交的 ASAP 非 lf 文本文件,您可以按照 --- update 2 ---: ( git grep -I --files-with-matches --perl-regexp '\r' HEAD,在使用:--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 -- : 似乎这是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

另外,我强烈反对在 Windows 上 使用git config --global core.autocrlf false(如果您只有 Windows 客户端) ,这与git 文档中的建议相反 。设置为 false 将在 repo 中提交带有 CRLF 的文件。但是真的没有理由。您永远不知道是否需要与 linux 用户共享项目。另外,对于每个加入项目而不是使用默认值的客户来说,这是一个额外的步骤。

现在对于某些特殊情况下的文件(例如*.bat *.sh),您可以使用 LF 或 CRLF 检出它们.gitattributes

总结一下我的最佳实践是:

  • 确保在 git repo 上使用 LF 提交每个非二进制文件(默认行为)。
  • 使用此命令确保没有使用 CRLF 提交任何文件:(git grep -I --files-with-matches --perl-regexp '\r' HEAD注意在 windows 客户端上仅在使用in编译时才通过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(例如 for *.zipor *.jpgfiles:不会被视为文本。因此不会尝试行尾转换。通过转换程序可以实现差异)
  • text !eol(例如 for *.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消毒剂。

于 2017-09-21T15:17:27.433 回答
11

core.autocrlf=false当我在Visual Studio 2010项目中签出所有文件时,使用会阻止所有文件被标记为已更新。开发团队的另外两名成员也使用 Windows 系统,因此混合环境没有发挥作用,但存储库附带的默认设置始终将所有文件标记为克隆后立即更新。

我想底线是找到适合您环境的 CRLF 设置。特别是因为在我们的 Linux 机器上的许多其他存储库中,设置autocrlf = true会产生更好的结果。

20 多年过去了,我们仍在处理操作系统之间的行尾差异……可悲。

于 2011-03-16T03:10:52.540 回答
10

尝试将core.autocrlf配置选项设置为true. 也看看这个core.safecrlf选项。

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

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

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

最后,我觉得在 Windows 上简单地“使用你给定的”和使用 LF 终止行的建议会导致比它解决的问题更多的问题。Git 有上述选项可以尝试以合理的方式处理行尾,因此使用它们是有意义的。

于 2008-10-05T03:50:12.263 回答
7

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

* 文字=自动

在您的回购.gitattributes文件中添加:

*   text=auto

这将规范化LFrepo 中所有行结尾的文件。

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

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

例子:

Hello\r\nWorld

将在 repo 中标准化为:

Hello\nWorld

结帐时,Windows 中的工作树将转换为:

Hello\r\nWorld

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

Hello\nWorld

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

core.autocrlf = true

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

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

  • 文件仅在添加到 repo时才标准化为LF行尾。如果 repo 中有未规范化的文件,此设置将不会触及它们。
  • 所有文本文件都转换为CRLF工作目录中的行尾。

这种方法的问题在于:

  • 如果您是 Windows 用户autocrlf = input,您将看到一堆带有LF行尾的文件。对团队的其他成员来说不是危险,因为您的提交仍将使用LF行尾进行标准化。
  • 如果您是 Windows 用户core.autocrlf = false,您会看到一堆带有LF行尾的文件,并且您可以将带有CRLF行尾的文件引入 repo。
  • 大多数 Mac 用户使用autocrlf = input并可能获取带有CRLF文件结尾的文件,可能来自带有core.autocrlf = false.
于 2016-02-14T23:02:41.947 回答
5

这只是一个解决方法:

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

在我的例子中,有超过 10 个程序员在 Windows 中开发一个项目。这个项目是用 CRLF 签入的,没有强制到 LF 的选项。

一些设置是在我的机器内部编写的,对 LF 格式没有任何影响;因此,在每次小文件更改时,一些文件都会全局更改为 LF。

我的解决方案:

Windows-Machines: 让一切保持原样。什么都不在乎,因为您是默认的 Windows '孤狼'开发人员,您必须像这样处理:“世界上没有其他系统,是吗?”

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
      
于 2013-03-20T15:21:31.623 回答