ChatGPT解决这个技术问题 Extra ChatGPT

git-diff 忽略 ^M

在某些文件包含 ^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 - 我在 stackoverflow.com/a/46265081/58794 中展示过
使用 Git 2.16(2018 年第一季度),您将拥有 git diff --ignore-cr-at-eol。请参阅my answer below
@JasonPyeron 和未来的 Google 员工:我必须查找 git diff -bgit diff --ignore-space-change 相同。
相关:在 Linux 上,您可以使用命令行实用程序 dos2unix(和 unix2dos)在行尾之间进行转换。

r
random

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”提交中再次签出它们。
R
Ryan Lundy

在 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 安装程序时,您将获得以下三个选项: Checkout Windows-style, commit Unix-style line endings <-- 选择这一项 Checkout as-is, commit Unix-style line endings Checkout as-is, commit原样

签出 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 endingscore.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?我看到他们正在尝试,但他们应该再添加六种换行行为,以解决一个不存在的问题。他们快到了!保持。
J
Jakub Narębski

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


这些都不会真正影响识别换行符的字符。
我也尝试使用“-w”但没有运气,仍然将其视为单行。下一个项目我必须记住永远不要在源代码中加入任何 CR。
只要记住 git config --global core.autocrlf true,或者让 git 的人出错,直到他们将其设为默认值 :)
这解决了我的问题,而无需更改我的 autocrlf 设置。谢谢!
这些标志对我没有影响......仍然显示 ^M 作为差异
R
Rufflewind

另见:

core.whitespace = cr-at-eol

或等效地,

[core]
    whitespace = cr-at-eol

其中 whitespace 前面有一个 tab 字符。


是的,这使得 git diff 工具(也在 git show 中使用)不再困扰我关于更改行上的 ^M 的问题! :)
无论出于何种原因,这对我不起作用。用 = 和没有 = 符号都试过了。 git diff 仍显示 ^M 个字符。
有两种方法可以做到这一点:第一,将上面的行逐字添加到 .git/config 或 ~/.gitconfig 中的 .gitconfig;二,git config --global core.whitespace cr-at-eol(如果您只想在您所在的仓库中使用 --global ,则它是可选的)
这在 Windows 7 上对我有用,虽然我只是把它放在 [core] 下,所以我可以用 TAB 字符替换 core. 前缀。
这个问题是关于如何在 git diff 中隐藏 ^M,而不是首先如何不放入 ^M。这意味着更改 core.autocrlf 的公认答案不是最好的,因为它会在没有用户确认的情况下默默地更改文件。
g
gitaarik

你为什么在你的 git diff 中得到这些 ^M ?

就我而言,我正在从事一个在 Windows 中开发的项目,我使用的是 Linux。当我更改一些代码时,我在 git diff 中添加的行的末尾看到了 ^M。我认为 ^M 出现是因为它们的行尾与文件的其余部分不同。因为文件的其余部分是在 Windows 中开发的,所以它使用 CRLF 行结尾,而在 Linux 中它使用 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 再次添加所有文件。混帐添加。这将显示如下消息:警告:CRLF 将被替换为 中的 LF。该文件将在您的工作目录中具有其原始行结尾。您可以删除 .gitattributes 文件,除非您有顽固的 Windows 用户不想使用“签出 Windows 样式,提交 Unix 样式的行尾”选项。承诺并推动这一切。删除并签出所有使用它们的系统上的适用文件。在 Windows 系统上,确保它们现在使用“Checkout Windows-style, commit Unix-style line endings”选项。您还应该在执行这些任务的系统上执行此操作,因为当您添加文件时 git 说:该文件将在您的工作目录中具有其原始行结尾。您可以执行以下操作来删除文件: 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 是矫枉过正,反 Windows/反 CR 活动似乎与问题无关。
它不应该是 *.ext text eol=lf 代替 crlf 吗?我认为这是一个错字,没有人注意到!
k
kaartic

有没有像“差异时将 ^M 视为换行符”这样的选项?

Git 2.16(2018 年第一季度)将有一个,因为“diff”系列命令学会了忽略行尾回车的差异。

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

diff: --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 很明显。
J
Jason Pyeron

TL;博士

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

这就是为什么

https://i.stack.imgur.com/ysOdN.png

首先要注意的是 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

我在回购中遇到了这个问题,其中一些文件有 \r\n 行结尾,有些有 \n 行结尾(我不知道这是否相关);前者的差异在修改后的行(即 + 行)中显示了 ^Mcore.autocrlf 设置为 true。运行 git config core.pager "tr -d '\r' | less -REX" 摆脱了讨厌的 ^M。谢谢!
谢谢你。如果您必须在存储库中使用不同的行结尾,这是唯一的答案——例如,您有目的地使用原样结帐、原样提交。
git diff -b 是我一直在寻找的,但我非常感谢详尽的解释。
是的!在这个问题的所有答案中,通过添加 pager = tr -d '\\r' | less -REX 来修改 git“config”文件的 [core] 部分是唯一对我有用的答案。谢谢!
git diff -b 无效,但配置修改有效。
a
alesub

就我而言,它是什么命令:

git config  core.whitespace cr-at-eol

来源:https://public-inbox.org/git/8d7e4807-9a79-e357-8265-95f22ab716e0@web.de/T/


I
Ian Wojtowicz

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

而不是键入:

git diff <commitHash> <filename>

尝试:

git difftool <commitHash> <filename>

谢谢!我也刚刚运行了“git difftool”,它基本上比较了所有更改的文件循环
P
Pedro Gimeno

正如 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'

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


m
manuelvigarcia

如果您只想要一条使 git diff 但不显示不同结尾(因此 ^M)的快速行,请使用原始问题的第一条评论中的那个,它对我有用:

 git diff -b

考虑到,从长远来看,您应该正确设置行尾配置,正如所有其他答案所暗示的那样。


A
Arun George

如果 git 补丁已经在 Windows 机器中生成并且您正在使用它,您可以在 Linux 中使用 dos2unix 实用程序格式化补丁。

find -name "*.patch"| xargs dos2unix

这将解决 EOL 的 ^M 问题,您将能够在您的 linux 机器中应用 git apply 补丁。