How to use --color-words with git add --patch?

Git

Git Problem Overview


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?

Git Solutions


Solution 1 - Git

Building off of what VonC said:

Starting with Git 2.9, you can use this command to color words during add --patch:

git -c interactive.diffFilter="git diff --color-words" add -p

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:

git config --global alias.addcw '-c interactive.diffFilter="git diff --color-words" add -p'

Solution 2 - Git

Taking cue from VonC's answer. Here are detailed steps to use --interactive option introduced in git 2.9.

Add diff-highlight to your PATH.

On Ubuntu, diff-highlight comes with git and can be found in /usr/share/git/diff-highlight/diff-highlight.

Otherwise, you can download and set it up manually.

cd ~/bin curl -LO "https://raw.githubusercontent.com/git/git/master/contrib/diff-highlight/diff-highlight" chmod u+x diff-highlight

Restart your shell, if necessary.

Then configure Git to filter your diffs whenever it's showing them in a pager:

git config --global pager.log 'diff-highlight | less'
git config --global pager.show 'diff-highlight | less'
git config --global pager.diff 'diff-highlight | less'
git config --global interactive.diffFilter diff-highlight

This will put an extra emphasis on the changed part of a line, which is almost same as --word-diff.

The advantage is you get word diff every where, like git log --patch or git add -p.

Demonstration of diff-highlight in git log --patch

Solution 3 - Git

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.

  1. Copy git-add--interactive from your installation to somewhere in your PATH environment variable and rename it git-add--interactive-words.
  2. Edit a line about half way down to change*

@colored = run_cmd_pipe("git", @diff_cmd, qw(--color --), $path);

to

@colored = run_cmd_pipe("git", @diff_cmd, qw(--color --color-words --), $path);

3. You can now run git add-interactive--words to do the equivalent of git add --interactive with colorized word-based diff. 4. 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:

[alias]
iaddpw = add--interactive-words --patch=stage --

which means git iaddpw runs the equivalent of git add --interactive --patch with colorized word-based diff.


*- For Git 2.18, this command is:

my @display_cmd = ("git", @diff_cmd, qw(--color --), $path);

Solution 4 - Git

With git 2.9 (June 2016), you will have a new option: interactive.diffFilter.

See commit 0114384 (27 Feb 2016) by Jeff King (peff).
(Merged by Junio C Hamano -- gitster -- in commit 2052c52, 03 Apr 2016)

> ## add --interactive: allow custom diff highlighting programs

> 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.

As commented by Andrew Dufresne, the GitHub blog post refers to the contrib script contrib/diff-highlight:

> 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:

diff colors

Regarding those diffs, "diff-highlight" filter (in contrib/) learned to undertand "git log --graph" output better.

See commit 4551fbb, commit 009a81e, commit fbcf99e, commit 7ce2f4c, commit e28ae50, commit 53ab9f0, commit 5013acc (21 Mar 2018) by Jeff King (peff).
(Merged by Junio C Hamano -- gitster -- in commit d19e556, 10 Apr 2018)

See more in "diff-highlight: detect --graph by indent"


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.

See commit 42f7d45, commit af3570e (03 Mar 2018) by Jeff King (peff).
(Merged by Junio C Hamano -- gitster -- in commit c5e2df0, 14 Mar 2018)


With Git 2.30 (Q1 2021), "git add -i"(man) failed to honor custom colors configured to show patches, which has been corrected.

See commit 96386fa, commit 890b68b, commit 0cb8939, commit afae3cb, commit 6681e36 (16 Nov 2020), commit 25d9e5c, commit c62cd17, commit 6f1a5ca, commit decc9ee (11 Nov 2020), and commit cb581b1, commit d34e450 (10 Nov 2020) by Johannes Schindelin (dscho).
(Merged by Junio C Hamano -- gitster -- in commit e0d2568, 08 Dec 2020)

> ## 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 any color.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.

Solution 5 - Git

Solution

Use diff-highlight | less -FRX --tabs=4 as your diffFilter:

git -c interactive.diffFilter="diff-highlight | less -FRX --tabs=4" add --patch

For more on diff-highlight: source, a quick primer

Homebrew

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.

diff-so-fancy now supports this (as of v1.4.0) since https://github.com/so-fancy/diff-so-fancy/issues/35 has been closed. See this.

Solution 6 - Git

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:

git config interactive.diffFilter "perl /usr/share/doc/git/contrib/diff-highlight/diff-highlight"

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.

Solution 7 - Git

This tool does it well https://github.com/mookid/diffr

[core]
    pager = diffr | less -R
[interactive]
	diffFilter = diffr

Solution 8 - Git

This is also possible via delta:

[interactive]
    diffFilter = delta --color-only --features=interactive

and via diff-so-fancy:

[interactive]
    diffFilter = diff-so-fancy --patch

Solution 9 - Git

In your $(HOME)/.gitconfig file add this

[color]
        diff = auto
        interactive = auto

This should do.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionmybuddymichaelView Question on Stackoverflow
Solution 1 - GitadzenithView Answer on Stackoverflow
Solution 2 - GitAndrew-DufresneView Answer on Stackoverflow
Solution 3 - GitmabrahamView Answer on Stackoverflow
Solution 4 - GitVonCView Answer on Stackoverflow
Solution 5 - GitOlivier Le FlochView Answer on Stackoverflow
Solution 6 - GitsgtpepView Answer on Stackoverflow
Solution 7 - GitPaddy RoddyView Answer on Stackoverflow
Solution 8 - GitjoelostblomView Answer on Stackoverflow
Solution 9 - GitpositronView Answer on Stackoverflow