我尝试使用以 CRLF 结尾的行提交文件,但失败了。
我花了一整天的时间在我的 Windows 电脑上尝试不同的策略,几乎被吸引停止尝试使用 Git 而是尝试Mercurial。
如何正确处理 CRLF 行尾?
我尝试使用以 CRLF 结尾的行提交文件,但失败了。
我花了一整天的时间在我的 Windows 电脑上尝试不同的策略,几乎被吸引停止尝试使用 Git 而是尝试Mercurial。
如何正确处理 CRLF 行尾?
问了这个问题快四年了,我终于找到了一个让我完全满意的答案!
请参阅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。
谁说软件很简单?:-/
不要转换行尾。解释数据不是 VCS 的工作——只是存储和版本化它。无论如何,每个现代文本编辑器都可以读取这两种行尾。
autocrlf=input
除非您真的知道自己在做什么,否则您几乎总是想要。
下面的一些附加上下文:
core.autocrlf=true
如果你喜欢 DOS 结尾或者core.autocrlf=input
你喜欢 unix-newlines ,它应该是。在这两种情况下,您的 Git 存储库都将只有 LF,这是正确的。唯一的论点core.autocrlf=false
是自动启发式可能会错误地将某些二进制文件检测为文本,然后您的图块将被损坏。因此,core.safecrlf
引入了选项以在发生不可逆转的变化时警告用户。事实上,不可逆转的更改有两种可能性——文本文件中的混合行尾,在这种规范化中是可取的,所以可以忽略这个警告,或者(非常不可能)Git 错误地将你的二进制文件检测为文本。然后你需要使用属性告诉Git这个文件是二进制的。
上述段落最初是从 gmane.org 上的一个线程中提取的,但此后它已被删除。
在混合环境(Microsoft + Linux + Mac)中获得一致的行尾的两种替代策略:
全部转换为一种格式
find . -type f -not -path "./.git/*" -exec dos2unix {} \;
git commit -a -m 'dos2unix conversion'
在 Linux/UNIX 或MS Windows(存储库或全局)上设置core.autocrlf
为input
true
git config --global core.autocrlf input
(可选)设置core.safecrlf
为true
(停止)或warn
(唱歌:)以添加额外的保护比较,如果反向换行符转换会导致相同的文件
git config --global core.safecrlf true
全部转换为一种格式
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 unified line-ending'
不要担心你的二进制文件——Git 应该对它们足够聪明。
考虑到 windows 用户更喜欢处理CRLF
而 linux/mac 用户更喜欢处理LF
文本文件的情况。从存储库维护者的角度提供答案:
对我来说,最好的策略(要解决的问题更少)是:将所有文本文件保存在LF
git repo中,即使您正在处理仅限 Windows 的项目。然后让客户自由地使用他们偏好的行尾样式,前提是他们在暂存文件以进行提交时选择了一个尊重您的策略的core.autocrlf
属性值(LF on repo) 。
分期是许多人在试图了解换行策略如何工作时感到困惑的地方。core.autocrlf
在选择正确的财产价值之前,必须了解以下几点:
.git/
core.autocrlf
core.autocrlf
就像提供问题的答案(在所有操作系统上完全相同的问题): “应该 git-client:
false:
“以上都不做”,input:
“只做b ”true
: "做a 和 b "幸运的是
core.autocrlf: true
, linux/mac:
core.autocrlf: false
)将与LF-only-repo策略兼容。很遗憾:
core.autocrlf
值的 GUI 客户端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(或相反)。当涉及解决冲突时,这可能会相当痛苦。或者在某些情况下它可能是不合理冲突的原因。
git 客户端的默认设置在大多数情况下都会起作用。即使您只有 Windows 客户端、Linux 客户端或两者都有。这些都是:
core.autocrlf=true
表示结帐时将行转换为 CRLF,添加文件时将行转换为 LF。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 grep -I --files-with-matches --perl-regexp '\r' HEAD
注意:在 windows 客户端上仅在使用in编译时才通过git-bash
和在 linux 客户端上工作)。--with-libpcre
./configure
core.autocrlf=input
( --- 更新 3 -- ).gitattributes
core.autocrlf
将上述设置为其默认值。.gitattributes
。IDE 的 git-clients 可能会忽略它们或区别对待它们。如前所述,可以在 git 属性中添加一些内容:
# Always checkout with LF
*.sh text eol=lf
# Always checkout with CRLF
*.bat text eol=crlf
我认为其他一些安全选项可以.gitattributes
代替对二进制文件使用自动检测:
-text
(例如 for *.zip
or *.jpg
files:不会被视为文本。因此不会尝试行尾转换。通过转换程序可以实现差异)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
消毒剂。
windows/linux客户端: core.autocrlf=input
承诺.gitattributes
: * text=auto eol=lf
已提交.editorconfig
(http://editorconfig.org/),这是一种标准化格式,与编辑器插件相结合:
core.autocrlf=false
当我在Visual Studio 2010项目中签出所有文件时,使用会阻止所有文件被标记为已更新。开发团队的另外两名成员也使用 Windows 系统,因此混合环境没有发挥作用,但存储库附带的默认设置始终将所有文件标记为克隆后立即更新。
我想底线是找到适合您环境的 CRLF 设置。特别是因为在我们的 Linux 机器上的许多其他存储库中,设置autocrlf = true
会产生更好的结果。
20 多年过去了,我们仍在处理操作系统之间的行尾差异……可悲。
尝试将core.autocrlf
配置选项设置为true
. 也看看这个core.safecrlf
选项。
实际上,听起来core.safecrlf
可能已经在您的存储库中设置了,因为(强调我的):
如果 core.autocrlf 的当前设置不是这种情况,git 将拒绝该文件。
如果是这种情况,那么您可能需要检查您的文本编辑器是否配置为一致地使用行尾。如果文本文件包含 LF 和 CRLF 行尾的混合,您可能会遇到问题。
最后,我觉得在 Windows 上简单地“使用你给定的”和使用 LF 终止行的建议会导致比它解决的问题更多的问题。Git 有上述选项可以尝试以合理的方式处理行尾,因此使用它们是有意义的。
这是与Mac或Linux用户共享代码的Windows和Visual Studio用户的两个选项。有关详细说明,请阅读gitattributes 手册。
在您的回购.gitattributes
文件中添加:
* text=auto
这将规范化LF
repo 中所有行结尾的文件。
并且根据您的操作系统(core.eol
设置),工作树中的文件将被标准化LF
为基于 Unix 的系统或CRLF
Windows 系统。
这是Microsoft .NET存储库使用的配置。
例子:
Hello\r\nWorld
将在 repo 中标准化为:
Hello\nWorld
结帐时,Windows 中的工作树将转换为:
Hello\r\nWorld
在结帐时,Mac 中的工作树将保留为:
Hello\nWorld
注意:如果您的 repo 已经包含未规范化的
git status
文件,下次您对它们进行任何更改时,这些文件将显示为已完全修改,并且其他用户稍后合并他们的更改可能会很痛苦。有关更多信息,请参阅更改行尾后刷新存储库。
如果文件text
中未指定.gitattributes
,Git 使用core.autocrlf
配置变量来确定是否应该转换文件。
对于 Windows 用户,git config --global core.autocrlf true
这是一个不错的选择,因为:
LF
行尾。如果 repo 中有未规范化的文件,此设置将不会触及它们。CRLF
工作目录中的行尾。这种方法的问题在于:
autocrlf = input
,您将看到一堆带有LF
行尾的文件。对团队的其他成员来说不是危险,因为您的提交仍将使用LF
行尾进行标准化。core.autocrlf = false
,您会看到一堆带有LF
行尾的文件,并且您可以将带有CRLF
行尾的文件引入 repo。autocrlf = input
并可能获取带有CRLF
文件结尾的文件,可能来自带有core.autocrlf = false
.这只是一个解决方法:
在正常情况下,使用 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