如何在统一的差异文件中可视化每个字符的差异?

157
假设我使用git format-patch创建了一个补丁文件。该文件基本上是一个带有一些元数据的统一差异。如果我在Vim中打开该文件,我可以看到哪些行已被修改,但我无法看到更改行中哪些字符不同。是否有人知道一种方法(在Vim中或在Ubuntu上运行的其他免费软件)来可视化每个字符的差异?
一个演示每个字符差异的反例是执行vimdiff a b更新时间 Fri Nov 12 22:36:23 UTC 2010 对于您正在使用单个文件的情况,diffpatch很有帮助更新时间Thu Jun 16 17:56:10 UTC 2016 查看git 2.9中的diff-highlight。这个脚本完全做到了我最初想要的功能。

这个问题可能更适合在superuser.com上讨论。 - Daenyth
16
也许。我选择stackoverflow.com,因为FAQ提到这是关于“程序员常用软件工具”的问题的地方。 - Adam Monsen
8
我不确定这是否直接回答了你的问题,但是 git diff --color-words 非常有用,可以仅查看在行内更改了哪些单词,而不是通常的统一差异输出。它基于单词而不是字符,因此,如果您正在比较的内容中没有太多空格,则输出可能不太整齐。(编辑:糟糕,我看到我误解了你的问题 - 尽管如此,也许这条评论对某人会有用。) - Mark Longair
相关 https://dev59.com/fFUM5IYBdhLWcg3wIddd - ks1322
8个回答

210

在git中,您可以合并而不进行提交。首先合并您的补丁,然后执行以下操作:

git diff --word-diff-regex=.

注意等号后面的点号。


184
更好的写法:git diff --color-words=.。该命令用于显示文件的差异,并以单词为单位高亮显示。 - ntc2
6
@ntc2 你应该把你的评论写成一个回答。 - Tyler Collier
3
点赞的用户请注意,我的原始用例假设您只有一个补丁文件,没有git仓库甚至基本/修改版本。这就是为什么我接受了@legoscia的答案...它完全描述了所请求的内容。 - Adam Monsen
2
@ntc2 git diff --color-words=.git diff --color-words . 的作用不同。更好的选择是 git diff --color-words . - abhisekp
2
@abhisekp:感谢提供图片。我想我已经弄清楚了:git diff --color-words .实际上与git diff --color-words -- .相同!也就是说,.被解释为路径。您可以通过mkdir x y; echo foo > x/test; git add x/test; git commit -m test; echo boo > x/test; cd y; git diff --color-words=.; git diff --color-words .; git diff --color-words -- .进行验证。 - ntc2
显示剩余9条评论

179
这里有一些比 git diff --word-diff-regex=<re> 输出更少噪音的版本,打字量也比 git diff --color-words --word-diff-regex=<re> 少,但它们是等效的。

简单版(会突出空格变化):

git diff --color-words

简单(突出显示单个字符更改;不突出显示空格更改):

git diff --color-words=.

更复杂的(可以突出空格变化):

git diff --color-words='[^[:space:]]|([[:alnum:]]|UTF_8_GUARD)+'

总的来说:

git diff --color-words=<re>

其中<re>是一个正则表达式,用于识别更改时的“单词”。

相对于仅使用 --word-diff-regex=<re> 将匹配的“单词”用带有彩色的 -/+ 标记围绕,这种方式更加清晰,因为它会给更改后的“单词”着色。


12
我个人喜欢--color-words,不需要=.部分。 - Tyler Collier
1
git diff --color-words='\w' 在带有变音符号的情况下(git v1.7.10.4),效果更佳。 - n.r.
1
你更复杂的版本很好用。我添加了 --word-diff=plain 以便额外使用 [--] 包围删除,以及 {++} 包围添加。但正如手册所警告的那样,源代码中实际出现的这些分隔符并没有以任何方式进行转义。 - Tobias Kienzler
2
您更复杂的版本似乎不会突出显示缩进更改,我在这里提了一个问题:链接 - Tobias Kienzler
2
这个答案很好!但是有没有一种方法可以将更改的背景实际上变成绿色/红色? - WoLfPwNeR
显示剩余5条评论

50
git diff --color-words="[^[:space:]]|([[:alnum:]]|UTF_8_GUARD)+"

上述正则表达式(来自Thomas Rast)在标点符号/字符级别上很好地分离了diff片段(同时不像--word-diff-regex=.那样嘈杂)。
我在这里发布了输出结果的截图这里

更新:

这篇文章提供了一些很好的建议。具体来说,git repo的contrib/树中有一个diff-highlight perl脚本,可以显示出细粒度的高亮。

使用它的快速方法:

$ curl https://git.kernel.org/cgit/git/git.git/plain/contrib/diff-highlight/diff-highlight > diff-highlight
$ chmod u+x diff-highlight
$ git diff --color=always HEAD~10 | diff-highlight | less -R

5
你可以将其缩短为 --color-words=[^[:space:]]|([[:alnum:]]|UTF_8_GUARD)+' - Eddified
3
文本内容很重要。如果您的更改由空格分隔,则没有区别。但是,如果您将类似于foo.bar的内容更改为foo.qux,您将会看到差异。 - Justin M. Keyes
5
简化版翻译:将下述指令简化为git diff --color-words='[^[:space:]]|([[:alnum:]]|UTF_8_GUARD)+' - ntc2
不知道这个功能是什么时候引入的;在阅读man git diff以理解你的答案时看到了它。此外,看起来我的观点与@Eddfied的第一个评论相同:P - ntc2
2
我使用Homebrew安装了git,并已经有了位于/usr/local/share/git-core/contrib/diff-highlight/diff-highlight的脚本。这个似乎表明Homebrew的git确实会将整个contrib安装在/usr/local/share/git-core/contrib/中。因此,最终,以下命令对我有效:git diff --color=always | /usr/local/share/git-core/contrib/diff-highlight/diff-highlight - Ashutosh Jindal
显示剩余9条评论

15

鉴于您在问题中提到了Vim,我不确定这是否是您想要的答案 :) ,但Emacs可以做到。打开包含差异的文件,确保您处于diff-mode(如果文件命名为foo.difffoo.patch则会自动发生;否则输入M-xdiff-modeRET),转到您感兴趣的块,并按下C-c C-b进行refine-hunk。或使用M-n一次逐个步进文件块;它将自动进行精炼。


1
对我来说没问题!嘿,我用 Vim 十年了,但我刚刚安装了 emacs。 :) - Adam Monsen
但是Emacs不支持从标准输入读取,我无法执行例如git log master.. -p | emacs -的命令。 - Hi-Angel
1
@Hi-Angel 你可以打开Emacs并输入M-!来运行命令,并在缓冲区中捕获输出。 - legoscia

7

如果你不反对安装NodeJS,有一个叫做"diff-so-fancy"(https://github.com/so-fancy/diff-so-fancy)的软件包非常容易安装,并且工作得非常出色:

npm install -g diff-so-fancy
git diff --color | diff-so-fancy | less -R

编辑:刚才发现它实际上是官方diff-highlight的包装器... 至少对于像我这样的Perlophobe来说更容易安装,而且GitHub页面文档化得很好 :)

2

wdiff很有趣,谢谢!为了澄清我的原始问题,我正在寻找一种能够提供增强语法突出显示的工具,用于一个单独的文件,该文件恰好处于统一的差异格式中。 - Adam Monsen
略微偏题(关于逐字差异,而不是增强现有的差异输出),但我发现以下组合最适合逐字可视化:
  • wdiff old_file new_file | cdiff
  • vimdiff,然后在vim内部使用:windo wincmd K以切换到垂直窗口布局(一个在另一个下面)而不是并排的布局。对于具有长行的文件,该布局更好。
- Aleksander Adamowski
2
顺便提一下,还有一些值得检查的其他工具,这些在链接文章中没有提到:wdiff2mdiff谷歌的在线工具 - Aleksander Adamowski

1

经过一番研究,我注意到这个问题最近在主要的Vim邮件列表中出现了两次。NrrwRgn插件被提到了两次(创建两个窄区域并进行差异比较)。按照Christian Brabandt所描述的使用NrrwRgn感觉更像是一种权宜之计而不是解决方案,但也许这已经足够好了。

我试用了NrrwRgn和:diffthis,确实能够很好地展示单个文件部分字符之间的差异。但是需要输入很多按键。虽然我的Vim脚本已经有些生疏,但可能可以编写脚本来简化操作。也许可以对NrrwRgn进行改进以提供所需的功能。

你有什么想法?


0
diffr 是我现在首选的工具。

example diff

在Windows上安装:
1. `winget install -e --id Rustlang.Rustup` 2. `cargo install diffr` 3. `git config --global core.pager "diffr | less -R"` 4. `git config --global interactive.difffilter diffr`
如果使用`less`出现问题:`winget install jftuga.less`

1
很酷,但仍然需要两个文件。OP问的是如何为单个补丁文件进行高亮显示,而不是两个有差异的单独文件。请查看OP和被接受的答案。 我也承认这个问题已经成为了一个搜索结果,用于可视化多个文件之间的差异,不论我的最初问题是什么。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接