git-diff 忽略 ^M
Posted
技术标签:
【中文标题】git-diff 忽略 ^M【英文标题】:git-diff to ignore ^M 【发布时间】:2010-12-25 18:19:19 【问题描述】:在某些文件包含 ^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
【问题讨论】:
你可能想git diff -b
- 我在***.com/a/46265081/58794展示了这个
使用 Git 2.16(2018 年第一季度),您将拥有 git diff --ignore-cr-at-eol
。见my answer below。
@JasonPyeron 和未来的 Google 员工:我必须查一下 git diff -b
与 git diff --ignore-space-change
相同。
【参考方案1】:
GitHub suggests 你应该确保在 git-handled repos 中只使用 \n 作为换行符。有一个自动转换的选项:
$ git config --global core.autocrlf true
当然,这里说是把crlf转成lf,而你想把cr转成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 描述于the man page。
【讨论】:
不,当然不是,一旦设置在那里,它会在提交时静默转换。如果一切都按照我的想法进行,那就是…… 问题是我已经在存储库中有一些文件有 CRLF 结尾和其他没有。我怀疑即使我使用的是 Mac 版本,Adobe Flash 也会添加 CRLF。我需要与这些文件的旧版本进行比较。从现在开始转换行尾并不能解决旧版本的问题:-/ 您在这里没有使用 CRLF 文件,至少在您发布的示例中没有。那是一个老式的 mac 文件(仅使用 \r 表示 EOL)。这就是为什么差异显示在一行上的原因。使用 dos EOL 的文件会以结尾的 ^M 清楚地显示每一行,您可以通过git config core.whitespace cr-at-eol
告诉 get 处理。
我正在尝试这个,但我不断收到warning: LF will be replaced by CRLF
而不是warning: CRLF will be replaced by LF
,而且我在Linux 中。知道为什么吗?我希望一切都以 LF 结束,而不是 CRLF!
@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”提交中再次签出它们。【参考方案2】:
在Windows上开发,我在使用git tfs
时遇到了这个问题。我是这样解决的:
git config --global core.whitespace cr-at-eol
这基本上告诉 Git 行尾 CR 不是错误。因此,那些烦人的^M
字符不再出现在git diff
、git 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 文件,您可以轻松删除要删除的行。 (或者你可以在它们前面加上'#'来注释掉它们。)
【讨论】:
对于那些现在发现这个的人,值得注意的是 Checkout Windows-style, commit Unix-style line endings 自动设置core.autocrlf
到 true
请注意,git config --global core.whitespace cr-at-eol
行将关闭其他默认设置。有三个默认值:blank-at-eol、blank-at-eof 和 space-before-tab。因此,要启用 cr-at-eol,同时保留其他功能,您需要使用 git config --global core.whitespace blank-at-eol,blank-at-eof,space-before-tab,cr-at-eol
。
对于我的项目(它是在 Windows 上结帐,我正在 Linux 上查看它),cr-at-eol
在 git diff
的行尾去掉了 ^M
好吧,但是GIT 仍然将这些行显示为不同,尽管行尾是唯一的区别。
@Zitrax 的评论是假的; core.whitespace 的默认值为 ""。例如,如果您想启用 cr-at-eol 并禁用blank-at-eol,则需要将 core.whitespace 设置为“cr-at-eol -blank-at-eol”。另请参阅git help config
。
我认为 git 需要更复杂一点,行尾需要更多冲突设置。我认为 git 应该更多关注我的空格。例如,当在 Windows(但不是 Linux)机器上遇到 Mac 行结尾时,抛出一个不相关的致命错误并使存储库处于损坏状态。我的意思是为什么我要使用一个会介意它的业务并让我使用我想要的任何行尾的 VCS?我看到他们正在尝试,但他们应该再添加六种换行行为,以解决一个不存在的问题。他们快到了!坚持下去。【参考方案3】:
试试git diff --ignore-space-at-eol
,或git diff --ignore-space-change
,或git diff --ignore-all-space
。
【讨论】:
这些都不会真正影响识别换行符的字符。 我也尝试过使用“-w”但没有运气,仍然将其视为单行。下一个项目我必须记住永远不要在源代码中添加任何 CR。 只要记住 git config --global core.autocrlf true,或者在 git 人员将其设为默认值之前对其进行 bug :) 这解决了我的问题,而无需更改我的autocrlf
设置。谢谢!
这些标志对我没有影响...仍然显示 ^M 作为差异【参考方案4】:
另见:
core.whitespace = cr-at-eol
或等价的,
[core]
whitespace = cr-at-eol
其中whitespace
前面有一个制表符 字符。
【讨论】:
是的,这使得 git diff 工具(也用于git show
)不再困扰我关于更改行上的^M
s! :)
无论出于何种原因,这对我都不起作用。用 = 和没有 = 符号都试过了。 git diff
仍然显示 ^M 个字符。
有两种方法可以做到这一点:一种,将上面的行逐字添加到您的 .gitconfig 中,或者在 .git/config 中,或者在 ~/.gitconfig 中;二,git config --global core.whitespace cr-at-eol
(如果你只想在你所在的仓库中使用 --global 是可选的)
这在 Windows 7 上对我有用,虽然我只是把它放在 [core]
下,所以我可以用 TAB 字符替换 core.
前缀。
这个问题是关于如何在git diff
中隐藏^M
,而不是首先如何不放入^M。这意味着更改 core.autocrlf
的公认答案不是最好的,因为它会在没有用户确认的情况下默默地更改文件。【参考方案5】:
为什么你的git diff
中会出现这些^M
?
就我而言,我正在开发一个在 Windows 中开发的项目,我使用的是 OS X。当我更改一些代码时,我在 git diff
中添加的行的末尾看到了 ^M
。我认为 ^M
之所以出现是因为它们的行尾与文件的其余部分不同。因为文件的其余部分是在 Windows 中开发的,所以它使用 CRLF
行尾,而在 OS X 中它使用 LF
行尾。
显然,Windows 开发人员在安装 Git 期间没有使用“Checkout Windows-style, commit Unix-style line endings”选项。
那么我们应该怎么做呢?
您可以让 Windows 用户重新安装 git 并使用“Checkout Windows-style, commit Unix-style line endings”选项。这是我更喜欢的,因为我认为 Windows 在其行尾字符中是一个例外,而 Windows 以这种方式解决了它自己的问题。
如果您选择此选项,则应该修复当前文件(因为它们仍在使用 CRLF
行尾)。我是按照以下步骤完成的:
从存储库中删除所有文件,但不要从您的文件系统中删除。
git rm --cached -r .
添加一个.gitattributes
文件,强制某些文件使用LF
作为行尾。将其放入文件中:
* text=auto eol=lf
再次添加所有文件。
git add .
这将显示如下消息:
warning: CRLF will be replaced by LF in <filename>.
The file will have its original line endings in your working directory.
您可以删除 .gitattributes
文件,除非您有顽固的 Windows 用户不想使用“Checkout Windows-style, commit Unix-style line endings”选项。
提交并推送所有内容。
删除并签出所有使用它们的系统上的适用文件。在 Windows 系统上,确保它们现在使用“Checkout Windows-style, commit Unix-style line endings”选项。您还应该在执行这些任务的系统上执行此操作,因为当您添加文件时 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
【讨论】:
要修复特定文件中的所有行尾,如果使用 Sublime Text,您可以转到View
-> Line Endings
并点击 Unix
。
^M
到底是什么意思?它是windows还是linux换行符?还是与文件中的其他换行符相比,它只是一个“不同”的换行符?
好一个,我认为这只是一个“不同”的换行符(与大多数其他人不同)
-1 因为重新安装 git 以完成 git config --global core.autocrlf true
是矫枉过正,而且 anti-Windows/anti-CR
活动似乎与问题无关。
不应该是 *.ext text eol=lf
代替 crlf
吗?我认为这是一个错字,没有人注意到!【参考方案6】:
是否有类似“区分时将 ^M 视为换行符”之类的选项?
Git 2.16(2018 年第一季度)将会有一个,因为“diff
”系列命令学会了忽略行尾回车的差异。
见commit e9282f0(2017 年 10 月 26 日)Junio C Hamano (gitster
)。
帮助者:Johannes Schindelin (dscho
)。(由 Junio C Hamano -- gitster
-- 合并于 commit 10f65c2,2017 年 11 月 27 日)
差异:
--ignore-cr-at-eol
新选项
--ignore-cr-at-eol
告诉 diff 机制将(完整)行末尾的回车视为不存在。就像其他用于忽略各种空白差异的“
--ignore-*
”选项一样,这将有助于查看您所做的实际更改,而不会被您的编辑器程序进行的虚假CRLF<->LF
转换分心。
【讨论】:
@kaartic 感谢您编辑答案并引用正确的提交! 虽然将git config --global core.autocrlf true
设置为已接受的答案通常是一种好习惯,但这更直接地回答了OP的问题:'是否有类似“区分时将^M视为换行符”的选项?'
从 Git 2.20 开始,这不会隐藏 ^M 的
@user1944491 我没有注意到任何回归,这意味着在 Git 2.26 中使用此选项进行比较时它仍然会忽略 eol。
@VonC 在 git diff 命令中使用此参数不起作用。也没有在git version 2.20.1 (Apple Git-117)
上设置我的 core.whitespace 值,但添加 Jason Pyeron 的 core.pager 答案修复了它。显然是 YMMV。【参考方案7】:
TL;DR
将core.pager
改为"tr -d '\r' | less -REX"
,而不是源代码
这就是原因
显示的那些讨厌的 ^M 是着色和寻呼机的产物。
它是由默认的 git 寻呼机选项 less -R
引起的。 (git的默认寻呼机是less -REX
)
首先要注意的是git diff -b
不会显示空白的变化(例如 \r\n vs \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
【讨论】:
我在一个 repo 中遇到了这个问题,其中一些文件有\r\n
行尾,有些有 \n
行尾(我不知道这是否相关);前者的差异在修改后的行(即+
行)中显示了^M
。 core.autocrlf
设置为 true
。运行git config core.pager "tr -d '\r' | less -REX"
摆脱了讨厌的^M
s。谢谢!
谢谢。如果您必须在回购中使用不同的行尾,这是唯一的答案——例如您有目的地按原样使用结帐,按原样提交。
git diff -b
是我一直在寻找的,但我非常感谢您的详尽解释。
这就是答案!谢谢你。 -b 标志对我不起作用。
是的!在这个问题的所有答案中,通过添加 pager = tr -d '\\r' | less -REX
来修改 git "config" 文件的 [core]
部分是唯一对我有用的答案。谢谢!【参考方案8】:
在我的例子中,这个命令是做什么的:
git config core.whitespace cr-at-eol
来源:https://public-inbox.org/git/8d7e4807-9a79-e357-8265-95f22ab716e0@web.de/T/
【讨论】:
【参考方案9】:我为这个问题苦苦挣扎了很长时间。到目前为止,最简单的解决方案是不用担心 ^M 字符,只需使用可以处理它们的视觉差异工具即可。
不用打字:
git diff <commitHash> <filename>
尝试:
git difftool <commitHash> <filename>
【讨论】:
谢谢!我也刚刚运行了“git difftool”,它基本上比较了循环中所有更改的文件【参考方案10】:正如 VonC 所指出的,这已经包含在 git 2.16+ 中。不幸的是,该选项的名称 (--ignore-cr-at-eol
) 与我习惯使用的 GNU diff 使用的名称 (--strip-trailing-cr
) 不同。
当我遇到这个问题时,我的解决方案是调用 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'
但它不使用配置的寻呼机设置,这就是为什么我更喜欢前者。
【讨论】:
以上是关于git-diff 忽略 ^M的主要内容,如果未能解决你的问题,请参考以下文章
如何使 git-diff 和 git log 忽略新文件和已删除文件?
为啥 Fluent NHibernate 会忽略我对组件的唯一约束?