When diffing files, I prefer to use git diff --color-words. Is there a way to make this the default format for diffs when using git add --patch or git add --interactive?
OK if I edit this question to cover `--word-diff` in addition to `--color-words`? If so, then my *near* duplicate question [here](https://stackoverflow.com/q/49058817) will be able to be closed as an *exact* duplicate of this one. That will allow answers to be consolidated here, which in turn will be more efficient for the community.
– Sep 12 '18 at 16:33
May be a duplicate of what you can find here: https://stackoverflow.com/questions/49278577/how-to-improve-gits-diff-highlighting/60970801#60970801 . Please have a look at the answers there.
– Zorglub29Apr 01 '20 at 12:39
9 Answers9
20
Building off of what VonC said:
Starting with Git 2.9, you can use this command to color words during add --patch:
This sets the interactive.diffFilter variable for the call to add -p without affecting further calls. For me this is ideal because I usually want to run add -p normally, but sometimes want to run it with --color-words.
You can easily add an alias for this command like so:
I'm getting: Use of uninitialized value $_ in print at /usr/libexec/git-core/git-add--interactive line 1368. (Git 2.10.0)
– Pavel ŠimerdaNov 11 '16 at 12:49
@PavelŠimerda Someone in another comment thread below has figured that one out: http://stackoverflow.com/questions/10873882/how-to-use-color-words-with-git-add-patch/37817331?noredirect=1#comment18417877_12297461
– adzenithDec 04 '16 at 20:52
Using `git -c interactive.diffFilter="git diff --color-words" add -p folder/file` actually patch-adds the first modified file in my (git)root folder instead of `folder/file`. (I'm using Git v2.13.)
– ebosiJun 08 '17 at 15:16
2
Like already pointed out that answer is (sadly) **wrong**, because the used command `git diff --color-words` will not colourise stdin but get's executed usually.
Just execute `echo test | git diff` or `git show | git diff` to get evidence.
– doakJan 12 '18 at 11:32
You can just run `git config interactive.diffFilter diff-highlight` once to make it permanent globally.
– naught101Sep 13 '18 at 01:30
13
Git 2.17.2 on macOS from Command Line Tools, I see `fatal: mismatched output from interactive.diffFilter
hint: Your filter must maintain a one-to-one correspondence
hint: between its input and output lines.`
– Vitaly ZdanevichNov 08 '18 at 21:59
This almost worked for me but the URL is no longer valid, so I had to build `diff-highlight` from source (download correct git version -- not sure how much it matters --; `cd /contrib/diff-highlight`; execute `make`; add new `diff-highlight` to your `PATH`) then start from step `chmod` in this answer . Worked this way for me with `git version 2.17.2 (Apple Git-113)`.
– shoeJul 06 '19 at 05:37
For a brew installed git, the path was `/usr/local/Cellar/git/2.27.0//share/git-core/contrib/diff-highlight/diff-highlight`
– Ashutosh JindalOct 20 '20 at 12:49
Also you can install it via "pip3 install --user diff-highlight" with adding "~/.local/bin" to $PATH
– Alexey ShrubFeb 25 '21 at 08:02
@TomHale That doesn’t matter, because when `diff-highlight` is not executable, you can always just call `perl diff-highlight` instead.
– cawJul 30 '21 at 15:33
Is it just me or does the colorized git diff gives an optical illusion of red being at a higher level, green being at a lower level, and white at the normal level.
– Sriram MuraliJul 26 '22 at 16:31
16
I recently solved this issue, but it requires modifying a Perl script in git. That's easy and requires no special skill, however.
This solution requires that your git configuration use colorization for screen output, because that's the only circumstance under which git will show a word-based diff.
Copy git-add--interactive from your installation to somewhere in your PATH environment variable and rename it git-add--interactive-words.
You can now run git add-interactive--words to do the equivalent of git add --interactive with colorized word-based diff.
However, combining git add --patch with that is awkward because you need to pass the new script the right parameters. Fortunately, you can create an alias to the magic words in your .gitconfig:
@mabraham but I get this warning: `Use of uninitialized value $_ in print at /usr/local/Cellar/git/1.8.0/libexec/git-core/git-add--interactive-words line 1339` but using `git add -p` doesn't give me that warning
– BPmNov 20 '12 at 00:42
5
@BPm @mabraham: You can squelch that message by surrounding line 1339 (which is `print;`) with an if statement to make sure `$_` is defined, i.e. replace line 1339 by `if ($_) { print; }`
– Nevik RehnelFeb 03 '13 at 16:15
3
The existing colorization code in lines 1270-1340 assumes that the "before" and "after" hunks have content, which is not necessarily the case any more. The fix from @Nevik is effective there and line 1282.
– mabrahamJun 15 '13 at 14:10
@mybuddymichael I have submitted a patch to git, based on using color.word-diff-in-interactive-add boolean configuration option.
– mabrahamJun 15 '13 at 14:12
1
@K3---rnc I submitted a patch about a year ago, and it got a little bit of discussion. A proper implementation would take a bit more work, and down at the C level, and I have not prioritised it.
– mabrahamJul 24 '14 at 16:27
On my machine, even the unmodified `git add--interactive --patch=stage --` only works when called from the root directory of my git repository. Can you confirm that? Is there a way to make it work when run from subdirectories? In my case it only outputs one empty line per file.
– EdgarFeb 09 '16 at 09:42
11
With git 2.9 (June 2016), you will have a new option: interactive.diffFilter.
The patch hunk selector of add--interactive knows how ask
git for colorized diffs, and correlate them with the
uncolored diffs we apply. But there's not any way for
somebody who uses a diff-filter tool like contrib's
diff-highlight to see their normal highlighting.
This patch lets users define an arbitrary shell command to
pipe the colorized diff through. The exact output shouldn't
matter (since we just show the result to humans) as long as
it is line-compatible with the original diff (so that
hunk-splitting can split the colorized version, too).
You could then pipe that diff to a diff --color-words.
You can use "--color-words" to highlight only the changed portions of
lines. However, this can often be hard to read for code, as it loses
the line structure, and you end up with oddly formatted bits.
Instead, this script post-processes the line-oriented diff, finds pairs
of lines, and highlights the differing segments.
The result puts an extra emphasis on the changed part of a line:
Regarding those diffs, "diff-highlight" filter (in contrib/) learned to undertand "git log --graph" output better.
Note: before Git 2.17 (Q2 2018), The "interactive.diffFilter" used by "git add -i" must retain one-to-one correspondence between its input and output, but it was not enforced and caused end-user confusion.
We now at least make sure the filtered result has the same number of lines as its input to detect a broken filter.
add -p: prefer color.diff.context over color.diff.plain
Signed-off-by: Johannes Schindelin
Git's diff machinery allows users to override the colors to use in diffs, even the plain-colored context lines. As of 8dbf3eb6850 (diff.h: rename DIFF_PLAIN color slot to DIFF_CONTEXT, 2015-05-27, Git v2.4.5), the preferred name of the config setting is color.diff.context, although Git still allows color.diff.plain.
In the context of git add -p(man), this logic is a bit hard to replicate: git_diff_basic_config() reads all config values sequentially and if it sees anycolor.diff.context or color.diff.plain, it accepts the new color.
The Perl version of git add -p(man) needs to go through git config --get-color(man), though, which allows only one key to be specified.
The same goes for the built-in version of git add -p(man), which has to go through repo_config_get_value().
The best we can do here is to look for .context and if none is found, fall back to looking for .plain, and if still not found, fall back to the hard-coded default (which in this case is simply the empty string, as context lines are typically rendered without colored).
This still leads to inconsistencies when both config names are used: the initial diff will be colored by the diff machinery.
Once edited by a user, a hunk has to be re-colored by git add -p(man), though, which would then use the other setting to color the context lines.
In practice, this is not all that bad. The git config(man) manual says this in the color.diff.<slot>:
`context` (context text - `plain` is a historical synonym)
We should therefore assume that users use either one or the other, but not both names.
Besides, it is relatively uncommon to look at a hunk after editing it because it is immediately staged by default.
This [github tutorial](https://github.com/blog/2188-git-2-9-has-been-released) has better description on how to employ this new option.
– Andrew-DufresneOct 01 '16 at 14:01
@Andrew-Dufresne I agree. I have included a reference to the contrib script the blog post references.
– VonCOct 01 '16 at 14:09
1
Executed `git config interactive.diffFilter diff-highlight` - now in `git commit -p` no colors at all. `git version 2.17.1 (Apple Git-112)`
– Vitaly ZdanevichOct 04 '18 at 11:20
If you're using Homebrew (OS X), you can put the following in your .gitconfig (to use the already installed diff-highlight):
[interactive]
diffFilter = "$(git --exec-path | sed 's/libexec/share/')/contrib/diff-highlight/diff-highlight | less -FRX --tabs=4"
1-1 correspondence between input and output
As of git 2.17, the word diff solution must keep a 1-1 correspondence between input and output lines to avoid:
$ git -c interactive.diffFilter="git diff --word-diff --color" add --patch
fatal: mismatched output from interactive.diffFilter
hint: Your filter must maintain a one-to-one correspondence
hint: between its input and output lines.
I've only tested on OS X with Homebrew's install, indeed. Here are some instructions from `git` themselves on how to do so: https://git-scm.com/book/en/v1/Getting-Started-Installing-Git#Installing-on-Mac
– Olivier Le FlochOct 06 '18 at 00:27
5
As mentioned earlier adding diff-highlight to the interactive.diffFilter config key is the easiest option (since Git 2.9). The following comand does the trick on Debian/Ubuntu without copying scripts, changing permissions or mangling $PATH:
Things like git -c interactive.diffFilter="git diff --color-words" add -p or git config interactive.diffFilter "git diff --color-words" don't work properly: add -p always keeps suggesting the first modified file.
Thanks, but that's not what I'm talking about. It's not the *color*, but rather the word-by-word diff that I'm looking for.
– mybuddymichaelJun 07 '12 at 05:05
2
No. I'm talking about a character by character diff, rather than a line by line diff. Try `git diff --color-words` and you'll see what I mean.
– mybuddymichaelJun 08 '12 at 04:08