Adam Monsen
Adam Monsen

Reputation: 9420

How can I visualize per-character differences in a unified diff file?

Say I get a patch created with git format-patch. The file is basically a unified diff with some metadata. If I open the file in Vim, I can see which lines have been modified, but I cannot see which characters in the changed lines differ. Does anyone know a way (in Vim, or some other free software that runs on Ubuntu) to visualize per-character differences?

A counter example where per-character diff is visualized is when executing vimdiff a b.

update Fri Nov 12 22:36:23 UTC 2010

diffpatch is helpful for the scenario where you're working with a single file.

update Thu Jun 16 17:56:10 UTC 2016

Check out diff-highlight in git 2.9. This script does exactly what I was originally seeking.

Upvotes: 167

Views: 41880

Answers (8)

koppor
koppor

Reputation: 20501

diffr is my tool of choice now.

example diff

Installation on 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

In case there are issues with less: winget install jftuga.less

Upvotes: 1

ntc2
ntc2

Reputation: 11912

Here are some versions with less noisy output than git diff --word-diff-regex=<re> and that require less typing than, but are equivalent to, git diff --color-words --word-diff-regex=<re>.

Simple (does highlight space changes):

git diff --color-words

Simple (highlights individual character changes; does not highlight space changes):

git diff --color-words=.

More complex (does highlight space changes):

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

In general:

git diff --color-words=<re>

where <re> is a regexp defining "words" for the purpose of identifying changes.

These are less noisy in that they color the changed "words", whereas using just --word-diff-regex=<re> surrounds matched "words" with colored -/+ markers.

Upvotes: 188

Justin M. Keyes
Justin M. Keyes

Reputation: 6964

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

The above regex (from Thomas Rast) does a decent job of separating diff fragments at the punctuation/character level (while not being as noisy as --word-diff-regex=.).

I posted a screenshot of the resulting output here.


Update:

This article has some great suggestions. Specifically, the contrib/ tree of the git repo has a diff-highlight perl script that shows fine-grained highlights.

Quick start to use it:

$ 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

Upvotes: 51

Jeremy Philippe
Jeremy Philippe

Reputation: 101

If you have nothing against installing NodeJS, there's a package called "diff-so-fancy" (https://github.com/so-fancy/diff-so-fancy), which is very easy to install and works perfectly:

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

Edit: Just found out it's actually a wrapper for the official diff-highlight... At least it's easier to install for perlophobes like me and the GitHub page is nicely documented :)

Upvotes: 7

legoscia
legoscia

Reputation: 41527

Given your references to Vim in the question, I'm not sure if this is the answer you want :) but Emacs can do this. Open the file containing the diff, make sure that you're in diff-mode (if the file is named foo.diff or foo.patch this happens automatically; otherwise type M-x diff-mode RET), go to the hunk you are interested in and hit C-c C-b for refine-hunk. Or step through the file one hunk at a time with M-n; that will do the refining automatically.

Upvotes: 16

yingted
yingted

Reputation: 10544

In git, you can merge without committing. Merge your patch first, then do:

git diff --word-diff-regex=.

Note the dot after the equals sign.

Upvotes: 217

thegeek
thegeek

Reputation: 2458

Am not aware of per character difference tool, but there is a per word difference tool: wdiff.

refer examples Top 4 File Difference Tools on UNIX / Linux – Diff, Colordiff, Wdiff, Vimdiff.

Upvotes: 2

Adam Monsen
Adam Monsen

Reputation: 9420

After a little research, I notice this question has come up twice recently on the main Vim mailing list. The NrrwRgn plugin was mentioned both times (make two narrow regions and diff them). Using NrrwRgn as described by Christian Brabandt feels more like a workaround than a solution, but maybe that's good enough.

I tried out NrrwRgn and it, together with :diffthis, was indeed useful for illustrating per-character differences within parts of a single file. But it took many keystrokes. My Vimscript is pretty rusty, but it could likely be scripted. Maybe NrrwRgn could be enhanced to provide the desired functionality.

Thoughts?

Upvotes: 1

Related Questions