git-diff忽略^ M


473

在某些文件包含^ M作为换行符的项目中。显然,不可能对这些文件进行区分,因为git-diff将其视为整个文件只是一行。

与以前的版本有何不同?

是否有类似“比较时将^ M作为换行符”的选项?

prompt> git-diff "HEAD^" -- MyFile.as 
diff --git a/myproject/MyFile.as b/myproject/MyFile.as
index be78321..a393ba3 100644
--- a/myproject/MyFile.cpp
+++ b/myproject/MyFile.cpp
@@ -1 +1 @@
-<U+FEFF>import flash.events.MouseEvent;^Mimport mx.controls.*;^Mimport mx.utils.Delegate
\ No newline at end of file
+<U+FEFF>import flash.events.MouseEvent;^Mimport mx.controls.*;^Mimport mx.utils.Delegate
\ No newline at end of file
prompt>

更新:

现在,我编写了一个Ruby脚本,该脚本签出了最新的10个修订并将CR转换为LF。

require 'fileutils'

if ARGV.size != 3
  puts "a git-path must be provided"
  puts "a filename must be provided"
  puts "a result-dir must be provided"
  puts "example:"
  puts "ruby gitcrdiff.rb project/dir1/dir2/dir3/ SomeFile.cpp tmp_somefile"
  exit(1)
end

gitpath = ARGV[0]
filename = ARGV[1]
resultdir = ARGV[2]

unless FileTest.exist?(".git")
  puts "this command must be run in the same dir as where .git resides"
  exit(1)
end

if FileTest.exist?(resultdir)
  puts "the result dir must not exist"
  exit(1)
end
FileUtils.mkdir(resultdir)

10.times do |i|
  revision = "^" * i
  cmd = "git show HEAD#{revision}:#{gitpath}#{filename} | tr '\\r' '\\n' > #{resultdir}/#{filename}_rev#{i}"
  puts cmd 
  system cmd
end

7
您可能想要git diff -b-我在stackoverflow.com/a/46265081/58794中
Jason Pyeron

6
使用Git 2.16(Q1 2018),您将拥有git diff --ignore-cr-at-eol。请参阅下面的答案
VonC

7
@JasonPyeron和未来的Google员工:我必须查找git diff -b与相同的内容git diff --ignore-space-change
Gogowitsch

Answers:


392

GitHub建议您确保在git处理的存储库中仅使用\ n作为换行符。有一个选项可以自动转换:

$ git config --global core.autocrlf true

当然,据说这是将crlf转换为lf,而您想将crlf转换为lf。我希望这仍然有效...

然后转换文件:

# Remove everything from the index
$ git rm --cached -r .

# Re-add all the deleted files to the index
# You should get lots of messages like: "warning: CRLF will be replaced by LF in <file>."
$ git diff --cached --name-only -z | xargs -0 git add

# Commit
$ git commit -m "Fix CRLF"

手册页中介绍 core.autocrlf 。


1
不,当然不会,一旦设置存在,它将在提交时静默转换。如果一切都按照我的想法进行,那就是……
nes1983

1
问题是我在存储库中已经有一些文件带有CRLF结尾,而其他文件则没有。我怀疑即使使用Mac版本,Adobe Flash也会添加CRLF。我需要与这些文件的旧版本进行比较。从现在开始转换行尾不能解决旧版本的问题:-/
neoneye,2009年

65
您在这里没有使用CRLF文件,至少在您发布的示例中没有。那是旧式的mac文件(对于EOL仅使用\ r)。这就是差异显示在一行上的原因。使用dos EOL的文件将以尾随^ M清楚地显示每行,您可以通过告诉它处理git config core.whitespace cr-at-eol
jamessan

12
我正在尝试此操作,但是我一直在获取warning: LF will be replaced by CRLF而不是warning: CRLF will be replaced by LF,并且我正在使用Linux。知道为什么吗?我希望所有人都以LF结尾,而不是CRLF!
trusktr 2014年

5
@trusktr,对我来说也是一样。在Linux中,对于偶然的CRLF,请使用git config --global core.autocrlf input,执行此答案中的步骤(rm,add,commit),您将获得warning: CRLF will be replaced by LF. The file will have its original line endings in your working directory.。删除文件(因为它们具有错误的原始CRLF),然后从上一次“修复CRLF”提交中再次检出它们。
jmmut 2015年

370

在Windows上进行开发时,使用时遇到了这个问题git tfs。我是这样解决的:

git config --global core.whitespace cr-at-eol

这基本上告诉Git行尾CR并不是错误。结果,那些烦人的^M字符不再出现在线路末端git diffgit show等等。

似乎保留了其他设置。例如,行尾的多余空格仍会在差异中显示为错误(以红色突出显示)。

(其他答案都暗示了这一点,但以上正是设置设置的方法。要仅为一个项目设置设置,请省略 --global。)

编辑

在经历了许多行尾麻烦之后,在.NET团队中工作时,我有以下设置是最幸运的:

  • 没有core.eol设置
  • 没有core.whitespace设置
  • 没有core.autocrlf设置
  • 当运行Windows的Git安装程序时,您将获得以下三个选项:
    • 签出Windows风格,提交Unix风格的行结尾 <-选择这一行
    • 按原样签出,提交Unix样式的行尾
    • 按原样签出,按原样提交

如果需要使用空格设置,则可能需要在与TFS进行交互时仅在每个项目中启用它。只需省略--global

git config core.whitespace cr-at-eol

如果您需要删除一些core。*设置,最简单的方法是运行以下命令:

git config --global -e

这将在文本编辑器中打开全局.gitconfig文件,您可以轻松删除要删除的行。(或者,您也可以在它们前面加上“#”以将其注释掉。)


30
对于那些谁现在发现这一点,值得一提的是,结账Windows风格,致力于Unix风格的行结束自动套core.autocrlftrue
K.卡彭特

14
请注意,该行将git config --global core.whitespace cr-at-eol关闭其他默认设置。共有三个默认值:eol时空白,eof时空白和制表符前空格。因此,要在保持其他功能的同时启用cr-at-eol,您需要使用git config --global core.whitespace blank-at-eol,blank-at-eof,space-before-tab,cr-at-eol
Zitrax

2
对于我的项目(它是在Windows上签出的,而我正在Linux上查看的),在行尾完全cr-at-eol删除了,但是GIT仍然显示这些行是不同的,尽管行尾是唯一的不同。^Mgit diff
雅尼斯·埃默里斯(JānisElmeris)'17

SourceInsight继续按^ M字符,而git仍显示行尾的差异。@Zitrax的命令是我的情况的正确答案,git diff显示了很好的输出。
黎光维战

3
我认为git需要更多的复杂性,在行尾需要更多冲突的设置。我认为git应该关注我的空白。例如,在Windows(但不是Linux)计算机上遇到Mac行尾时,引发无关的致命错误并使存储库处于损坏状态。我的意思是为什么我要使用VCS来考虑这事,让我使用想要的任何行尾?我看到他们正在尝试,但是他们应该抛出六行更多的行尾行为,以解决不存在的问题。他们快到了!保持。
罗尔夫(Rolf)'18

124

尝试git diff --ignore-space-at-eolgit diff --ignore-space-changegit diff --ignore-all-space


22
这些都不会真正影响识别换行符的字符。
nes1983

4
我也尝试使用“ -w”,但没有运气,仍然将其视为一行。我必须记住的下一个项目永远不要在源代码中添加任何CR。
neoneye

3
只要记住git config --global core.autocrlf是,否则就对git伙计们进行调试,直到他们将其设置为默认:)
nes1983

10
这解决了我的问题,而无需更改autocrlf设置。谢谢!
nneonneo

11
这些标志有没有效果我...仍显示^ M的的diff
马格努斯

103

另请参阅:

core.whitespace = cr-at-eol

或等效地,

[core]
    whitespace = cr-at-eol

其中whitespace制表符开头。


4
是的,这使git diff工具(也用于中git show)不再让我烦恼^M更改行上的!:)
Rijk 2012年

2
不管出于什么原因,这都不适合我。尝试使用=和no =符号。 git diff仍显示^ M个字符。
丹尼斯

6
有两种方法:一种是将逐字上方的行添加到.git / config或〜/ .gitconfig中的.gitconfig中;第二,git config --global core.whitespace cr-at-eol(如果您只想在回购中使用它,则--global是可选的)
K. Carpenter

尽管我只是将其放在Windows 7下,但这对我来说还是有效的,[core]因此我可以用core.TAB字符替换前缀。
Rufflewind

这个问题是上面如何隐藏^Mgit diff,不是关于如何没有投入^ M摆在首位。这意味着公认的更改答案core.autocrlf不是最好的,因为它会在没有用户确认的情况下默默地更改文件。
deddebme

45

为什么要把这些^M放进去git diff

在我的情况下,我正在开发一个使用Windows开发的项目,并且使用OSX。当我更改一些代码时,我看到了^M在添加的行的结尾git diff。我认为^M之所以出现是因为它们的行尾与文件其余部分不同。由于该文件的其余部分是在Windows中开发的,因此它使用了CR行尾,而在OS X中则使用了LF行尾。

显然,Windows开发人员在安装Git的过程中没有使用“ 签出Windows风格,提交Unix风格的行尾 ” 选项。

那么我们应该怎么做呢?

您可以让Windows用户重新安装git并使用“ Checkout Windows风格,提交Unix风格的行尾 ”选项。这是我想要的,因为我将Windows视为行尾字符的例外,并且Windows以此方式解决了自己的问题。

如果选择此选项,则应修复当前文件(因为它们仍在使用CR行尾)。我是按照以下步骤进行的:

  1. 从存储库中删除所有文件,但从文件系统中删除所有文件。

    git rm --cached -r .
    
  2. 添加一个.gitattributes强制某些文件使用a LF作为行尾的文件。把它放在文件中:

    *.ext text eol=crlf
    

    .ext您要匹配的文件扩展名替换。

  3. 再次添加所有文件。

    git add .
    

    这将显示如下消息:

    warning: CRLF will be replaced by LF in <filename>.
    The file will have its original line endings in your working directory.
    
  4. .gitattributes除非您拥有不想使用“ Checkout Windows风格,提交Unix风格的行尾 ”选项的顽固Windows用户,否则可以删除该文件。

  5. 提交并推送所有内容。

  6. 在使用它们的所有系统上删除并签出适用的文件。在Windows系统上,确保它们现在使用“ Checkout Windows风格,提交Unix风格的行尾 ”选项。您还应该在执行这些任务的系统上执行此操作,因为添加文件git时说:

    The file will have its original line endings in your working directory.
    

    您可以执行以下操作删除文件:

    git ls | grep ".ext$" | xargs rm -f
    

    然后,这样做可以使它们返回正确的行尾:

    git ls | grep ".ext$" | xargs git checkout
    

    当然要替换.ext为所需的扩展名。

现在,您的项目仅使用LF字符作为行尾,讨厌的CR字符将永远不会回来:)。

另一种选择是强制执行Windows样式行的结尾。您也可以.gitattributes为此使用文件。

更多信息:https : //help.github.com/articles/dealing-with-line-endings/#platform-all


4
要将所有行尾固定在特定文件中,如果使用Sublime Text,则可以转到View-> Line Endings并单击Unix
Topher Hunt 2015年

这到底是什么^M意思?是Windows还是Linux换行符?还是与文件中的其他换行符相比只是“不同的”换行符?
buhtz

好人,我认为这只是一个“不同的”换行符(与大多数其他换行符不同)
gitaarik

-1作为重新安装git来完成git config --global core.autocrlf true是过大的,并且反Windows /反CR运动似乎与这个问题相切。
RJFalconer

41

是否有类似“比较时将^ M作为换行符”的选项?

Git 2.16(Q1 2018)将是其中一款,diff ”系列命令学会了忽略行尾的回车差异。

参见Junio C Hamano()提交的e9282f0(2017年10月26日。 帮助:Johannes Schindelin((由Junio C Hamano合并--commit 10f65c2中,2017年11月27日)gitster
dscho
gitster

差异: --ignore-cr-at-eol

一个新的选项--ignore-cr-at-eol告诉diff机械在(完整)行的末尾将回车视为不存在。

就像其他--ignore-*忽略各种空格差异的选项一样,这将有助于检查您所做的实际更改,而不会CRLF<->LF因编辑器程序进行的虚假转换而分心。


@kaartic感谢您编辑答案并引用正确的提交!
VonC

3
设置git config --global core.autocrlf true为接受的答案通常是一个很好的做法,但这会更直接地回答OP的问题:“是否有一个选项,例如“在比较时将^ M作为换行符”?
drkvogel

1
作为Git的2.20,这不能掩盖^ M的
user1944491

@ user1944491我没有注意到任何回归,这意味着在Git 2.26中使用此选项进行比较时,它仍会忽略eol。
VonC

@VonC在git diff命令中使用此参数无效。也没有设置我的core.whitespace值,git version 2.20.1 (Apple Git-117)而是添加了Jason Pyeron的core.pager答案来修复它。YMMV显然。
user1944491

26

TL; DR

更改core.pager"tr -d '\r' | less -REX",而不是源代码

这就是为什么

所显示的那些讨厌的^ M是着色和寻呼机的伪影。在此处输入图片说明 这是由less -R默认git pager选项引起的。(git的默认传呼机是less -REX

首先要注意的是 git diff -b不会显示空白的变化(例如\ r \ n与\ n)

设定:

git clone https://github.com/CipherShed/CipherShed
cd CipherShed

创建unix文件并更改行尾的快速测试不会显示任何变化git diff -b

echo -e 'The quick brown fox\njumped over the lazy\ndogs.' > test.txt
git add test.txt
unix2dos.exe test.txt
git diff -b test.txt

我们注意到,将管道强制减少不会显示^ M,但是启用颜色并less -R可以:

git diff origin/v0.7.4.0 origin/v0.7.4.1 | less
git -c color.ui=always diff origin/v0.7.4.0 origin/v0.7.4.1 | less -R

通过使用管道从输出中去除\ r(^ M)来显示此修复程序:

git diff origin/v0.7.4.0 origin/v0.7.4.1
git -c core.pager="tr -d '\r' | less -REX"  diff origin/v0.7.4.0 origin/v0.7.4.1

一个不明智的选择是使用less -r,因为它将通过所有控制代码,而不仅仅是颜色代码。

如果您只想直接编辑git配置文件,这是要更新/添加的条目:

[core]
        pager = tr -d '\\r' | less -REX

我在一个回购中遇到了这个问题,其中一些文件带有\r\n行尾,有些文件带有\n行尾(我不知道这是否相关);前者的diff ^M在修改的行(即+行)中显示。core.autocrlf设置为true。跑步git config core.pager "tr -d '\r' | less -REX"摆脱了讨厌^M的问题。谢谢!
labreuer18年

5
谢谢你 如果您必须在仓库中使用不同的行尾,这是唯一的答案-例如,您按原样使用checkout,按原样提交。
迈克

git diff -b是我一直在寻找的东西,但我确实感谢您的详尽解释。
马丁·伯奇

这就是答案!谢谢。-b标志对我不起作用。
克里斯,

是! 在此问题的所有答案中,[core]通过添加来修改git“ config”文件的部分pager = tr -d '\\r' | less -REX是对我有用的唯一答案。谢谢!
拉希基

13

我为这个问题苦苦挣扎了很长时间。到目前为止,最简单的解决方案是不用担心^ M个字符,而只是使用可以处理它们的可视化diff工具。

而不是输入:

git diff <commitHash> <filename>

尝试:

git difftool <commitHash> <filename>

1
谢谢!我也只是运行了“ git difftool”,它基本上在一个循环中比较了所有更改的文件
Bhanuprakash D D17年


2

正如VonC所指出的,它已经包含在git 2.16+中。不幸的是,选项(--ignore-cr-at-eol)的名称与我习惯于(--strip-trailing-cr)的GNU diff使用的名称不同。

当我遇到这个问题时,我的解决方案是调用GNU diff而不是git的内置diff,因为我的git早于2.16。我使用以下命令行来做到这一点:

GIT_EXTERNAL_DIFF='diff -u --strip-trailing-cr "$2" "$5";true;#' git diff --ext-diff

这允许使用--strip-trailing-cr和任何其他GNU diff选项。

还有另一种方式:

git difftool -y -x 'diff -u --strip-trailing-cr'

但它不使用配置的寻呼机设置,这就是为什么我更喜欢前者的原因。


我的答案很有趣。已投票。
VonC
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.