How to colorize diff on the command line
Asked Answered
G

17

611

When I have a diff, how can I colorize it so that it looks good?

I want it for the command line, so please no GUI solutions.

Guyot answered 10/1, 2012 at 8:49 Comment(3)
Any particular operating system/shell?Gild
Try github.com/walles/riff. As an added bonus, it highlights what parts of the lines that changed.Nigrescent
emacs does great color diffs in a terminal; is that what you mean by non-GUI? See unix.stackexchange.com/a/613399/80268 .Dearly
F
700

Man pages for diff suggest no solution for colorization from within itself. Please consider using colordiff. It's a wrapper around diff that produces the same output as diff, except that it augments the output using colored syntax highlighting to increase readability:

diff old new | colordiff

or just:

colordiff old new

Installation:

  • Ubuntu/Debian: sudo apt-get install colordiff
  • OS X: brew install colordiff or port install colordiff
Foe answered 10/1, 2012 at 8:54 Comment(9)
Just found that myself :-). It can be piped into less by using less -R, which displays the escape sequences for colors correctly.Guyot
Can just use the syntax: colordiff file1 file2Orchardman
Alas, it doesn't work for the side-by-side output (-y option to enable) ☹ The vimdiff suggestion below probably a better wayNicely
on centos I needed repository rpm -Uvh epel-release-5-4.noarch.rpm then I could yum install colordiffLipread
colordiff works well for svn diff | colordiff (i.e. in situations where you only have the diff, not the two files being diffed).Eberly
you can just use it instead of diff, just colordiff -y old new.Grangerize
As an update to @Nicely 's comment: colordiff has been updated and now includes side by side (-y) support.Pullulate
I used this to quickly get color when using git over ssh: git diff | colordiffPurpurin
@BaileyParker I am using 1.0.19 which seems to be the latest version. Using -y does not have any colorization.Infundibulum
A
388

Use Vim:

diff /path/to/a /path/to/b | vim -R -

Or better still, VimDiff (or vim -d, which is shorter to type) will show differences between two, three or four files side-by-side.

Examples:

vim -d /path/to/[ab]

vimdiff file1 file2 file3 file4
Achitophel answered 10/1, 2012 at 8:56 Comment(15)
function ddiff(){ diff $1 $2 | vim -R - } export -f ddiffTestee
@Jichao: I prefer to learn the commands rather than alias them away. That way I can use them anywhere, even when my dotfiles aren't available.Achitophel
vim -d has the advantage of remembering the last open position, if correct vimrc setting is used. (Such as here.)Bartel
looks good! I just dont understand why they dont allow ctrl+c or ctrl+q or ctrl+x on vim to exit; I always have to look on internet to quit it hehe..Eisenhart
@AquariusPower: ctrl-c and ctrl-x have other uses in Vim. ctrl-q is captured by many terminals. See Writing and quitting to find the way that best suits your needs.Achitophel
vimdiff won't handle directory diffs. Alternatively, you can save diff to a file, and open it with vim. That way you will have vim colorize it using built-in syntax highlighting facilities.Carine
@x-yuri. Yes... you could use your shell to do this too, vim -d =(ls -l ~/src/m) =(ls -l ~/src/n)Achitophel
First, what kind of shell is this? zsh? I don't recognize =(...) construct. Second, I had diff -ur a b in mind.Carine
Indeed. In Zsh, a command of the form =(...) is replaced with the name of a file containing its output.Achitophel
diff -ur ~/src/{m,n} | vim - is a nice alternative. Thanks.Achitophel
@Johnsyweb and @Carine - in Bash it's <(...) instead.Vaccination
@BrianMcCutchon The <(...) form is present in zsh as well.Dow
Actually for me it's shortest to type vimd + tab (autocomplete).Chihli
This solution is better than the accepted answer, as it does not require you to have system administrator rights and install any additional toolCoalfish
Adding a note that -R is vim's readonly mode so you can also use the equivalent view command which is just vim's readonly command, i.e., diff file1 file 2 | view -. Adding it here for those that may prefer one over the other. Cool solution, OP!Shred
B
205

Actually there seems to be yet another option (which I only noticed recently, when running into the problem described above):

git diff --no-index <file1> <file2>
# output to console instead of opening a pager
git --no-pager diff --no-index <file1> <file2>

If you have Git around (which you already might be using anyway), then you will be able to use it for comparison, even if the files themselves are not under version control. If not enabled for you by default, then enabling color support here seems to be considerably easier than some of the previously mentioned workarounds.

Bump answered 12/11, 2013 at 13:27 Comment(12)
This is neat, but sadly this doesn't work when the inputs are pipes. For example comparing binary files via git diff <(xxd file1) <(xxd filed) doesn't work.Tera
Oddly, at least one of the files has to be 'outside the current repository', according to git help diff. So if your git diff is coming up empty, try cd out of where you are.Cigar
To enable colors for git diff: git config color.diff autoClunk
super simple and quickDebonair
If both files are inside the current repository, use git diff --no-index to compare two files.Myelitis
This is excellent! Compared to regular diff, I much prefer the way git diff handles files that are only in one side of a recursive diff, but I hadn't realized I could use it outside of a Git repository. Thank you!Tamanaha
If you want a nicer colored git diff I would take a look at this answer.Rommel
I'm a fan of git diff --word-diff --patienceMadelinemadella
The other advantage of git diff is the --- and +++ at the top clarifying the direction of the changes.Classics
To enable color one just one run, git diff --color <file1> <file2>Laudable
~/.bashrc += alias cdiff='git diff --no-index'Vorfeld
Great workaround if diff --color and colordiff are not available at a site!Arawak
V
155

diff --color option (added to GNU diffutils 3.4 in 2016-08-08)

This is the default diff implementation on most distributions, which will soon be getting it.

Ubuntu 18.04 (Bionic Beaver) has diffutils 3.6 and therefore has it.

On 3.5 it looks like this:

Enter image description here

Tested with:

diff --color -u \
  <(seq 6 | sed 's/$/ a/') \
  <(seq 8 | grep -Ev '^(2|3)$' | sed 's/$/ a/')

Apparently added in commit c0fa19fe92da71404f809aafb5f51cfd99b1bee2 (Mar 2015).

Word-level diff

Like diff-highlight. It is not possible it seems, but there is a feature request: https://lists.gnu.org/archive/html/diffutils-devel/2017-01/msg00001.html

Related questions:

ydiff does it though. See below.

ydiff side-by-side word level diff

https://github.com/ymattw/ydiff

Is this nirvana?

python3 -m pip install --user ydiff
diff -u a b | ydiff -s

Outcome:

Enter image description here

If the lines are too narrow (default 80 columns), fit to the screen with:

diff -u a b | ydiff -w 0 -s

Contents of the test files:

a

1
2
3
4
5 the original line the original line the original line the original line
6
7
8
9
10
11
12
13
14
15 the original line the original line the original line the original line
16
17
18
19
20

b

1
2
3
4
5 the original line the original line the original line the original line
6
7
8
9
10
11
12
13
14
15 the original line the original line the original line the original line
16
17
18
19
20

ydiff Git integration

ydiff integrates with Git without any configuration required.

From inside a Git repository, instead of git diff, you can do just:

ydiff -s

and instead of git log:

ydiff -ls

See also: How can I get a side-by-side diff when I do "git diff"?

Tested on Ubuntu 16.04 (Xenial Xerus), Git 2.18.0, and ydiff 1.1.

Valois answered 20/1, 2017 at 18:54 Comment(5)
Here is the documentation.Beckett
In that mailing list thread: There is no word-highlighting, yet - any updates? This is what I came to this question for (I want grep --color-like diff output).Academy
@Academy no updates unfortunately, if I get any, I will update the question. Ping me if you find anything.Valois
By the way git diff --color works too. Useful when working over ssh.Purpurin
Diff too large? use diff --color=always | less -RImpendent
J
79

And for those occasions when a yum install colordiff or an apt-get install colordiff is not an option due to some insane constraint beyond your immediate control, or you're just feeling crazy, you can reinvent the wheel with a line of sed:

sed 's/^-/\x1b[41m-/;s/^+/\x1b[42m+/;s/^@/\x1b[34m@/;s/$/\x1b[0m/'

Throw that in a shell script and pipe unified diff output through it.

It makes hunk markers blue and highlights new/old filenames and added/removed lines in green and red background, respectively.1 And it will make trailing space2 changes more readily apparent than colordiff can.


1 Incidentally, the reason for highlighting the filenames the same as the modified lines is that to correctly differentiate between the filenames and the modified lines requires properly parsing the diff format, which is not something to tackle with a regex. Highlighting them the same works "well enough" visually and makes the problem trivial. That said, there are some interesting subtleties.

2 But not trailing tabs. Apparently tabs don't get their background set, at least in my xterm. It does make tab vs. space changes stand out a bit though.

Judkins answered 31/5, 2013 at 20:36 Comment(11)
@Matt: Here's a brute-force approach for a Mac: sed "s/^-/`echo -e \"\x1b\"`[41m-/;s/^+/`echo -e \"\x1b\"`[42m+/;s/^@/`echo -e \"\x1b\"`[34m@/;s/$/`echo -e \"\x1b\"`[0m/" (though I expect there is a better way).Judkins
Hmm, it sort of worked... gave the 3 dashes between each chunk a pink background.Berkey
Manual unreadable, unmaintainable way without an option to easily change the colors for example.Bartel
@Svetlana I think you're taking this a bit too seriously... :)Judkins
Dude this is awesome! Way to go! That is some nice sed wizardry.Apatite
aliased this awesomeness as colorize-diff-u. Thanks.Ballast
sed 's/^-/\x1b[31m-/;s/^+/\x1b[32m+/;s/^@/\x1b[34m@/;s/$/\x1b[0m/' looks also greatPaunchy
Particularly, this answer by retracile has inspired me to develop the bash function as wrapper over the original diff tool. I have briefly described it here - with-love-from-siberia.blogspot.ru/2016/07/color-diff.html. I have made attempt to cover all the possible formatting options. Sadly, it has some lacks described by retracile in his article but those lacks are quite rare. So I can say this it works properly.Dactylogram
There's always a case for doing something without involving yum, apt-get, etc. -- something as simple as not wanting to bother IT with installing yet another program that only one developer will use.Londrina
Thanks! You can also use sed -e '1,2s/^/\x1b[97m/;3,$s/^-/\x1b[31m-/;3,$s/^+/\x1b[32m+/;3,$s/^@/\x1b[36m@/;s/$/\x1b[0m/' for an output closer to diff --color.Telencephalon
Here is another solution that works on macOS and does not require spelling out the ANSI escape sequences explicitly: diff -u old new | sed "s/^-/$(tput setaf 1)&/; s/^+/$(tput setaf 2)&/; s/^@/$(tput setaf 6)&/; s/$/$(tput sgr0)/". See https://mcmap.net/q/64141/-how-to-colorize-diff-on-the-command-line for more details.Bradley
O
18

Coloured, word-level diff ouput

Here's what you can do with the the below script and diff-highlight:

Coloured diff screenshot

#!/bin/sh -eu

# Use diff-highlight to show word-level differences

diff -U3 --minimal "$@" |
  sed 's/^-/\x1b[1;31m-/;s/^+/\x1b[1;32m+/;s/^@/\x1b[1;34m@/;s/$/\x1b[0m/' |
  diff-highlight

(Credit to @retracile's answer for the sed highlighting)

Oracular answered 5/10, 2016 at 4:6 Comment(4)
How do I use this output in GVim?Xerosis
For vim, use a plugin, eg diffchar.Oracular
This answer deserves more credit! It uses a toolchain you probably already have, and works awesome (and applies to git log, git show, and git diff!Apomict
Actually, diff-highlight does not do a word-level output. It just detects a common prefix and a common suffix on a changed line. For instance, if several words are changed, it will highlight everything from the first changed word to the last changed word. Moreover, this is effective only when only one line is changed between unchanged lines. In GNU Emacs, diff-mode does much better.Cullie
F
16

You can change the Subversion configuration to use colordiff:

~/.subversion/config.diff

 ### Set diff-cmd to the absolute path of your 'diff' program.
 ###   This will override the compile-time default, which is to use
 ###   Subversion's internal diff implementation.
-# diff-cmd = diff_program (diff, gdiff, etc.)
+diff-cmd = colordiff

via: https://gist.github.com/westonruter/846524

Footless answered 20/9, 2013 at 12:21 Comment(4)
svn: Can't start process 'colordiff': Resource temporarily unavailablePerchloride
Did you install colordiff?Footless
Yup, I tried hardcoding the path as well (running in cygwin)Perchloride
idk try might this superuser.com/questions/635995/…Footless
R
11

I use grc (Generic Colouriser), which allows you to colour the output of a number of commands including diff.

It is a Python script which can be wrapped around any command. So instead of invoking diff file1 file2, you would invoke grc diff file1 file2 to see colourised output. I have aliased diff to grc diff to make it easier.

Referendum answered 10/1, 2012 at 8:56 Comment(1)
Does not work on Windows with mingw/cygwin due to fork() calls, although likely to work with WSL.Provencal
S
10

Since wdiff accepts arguments specifying the string at the beginning and end of both insertions and deletions, you can use ANSI color sequences as those strings:

wdiff -n -w $'\033[30;41m' -x $'\033[0m' -y $'\033[30;42m' -z $'\033[0m' file1 file2

For example, this is the output of comparing two CSV files:

diff output of CSV files

Example from 2.2 Actual examples of wdiff usage.

Seminar answered 13/1, 2017 at 23:25 Comment(1)
colordiff now (1.0.16) understands wdiff, so you can also just pipe: wdiff -n f1 f2 | colordiff. wdiff should be merged into diffutils...Valois
B
10

Here is another solution that invokes sed to insert the appropriate ANSI escape sequences for colors to show the +, -, and @ lines in red, green, and cyan, respectively.

diff -u old new | sed "s/^-/$(tput setaf 1)&/; s/^+/$(tput setaf 2)&/; s/^@/$(tput setaf 6)&/; s/$/$(tput sgr0)/"

Unlike the other solutions to this question, this solution does not spell out the ANSI escape sequences explicitly. Instead, it invokes the tput setaf and tput sgr0 commands to generate the ANSI escape sequences to set an appropriate color and reset terminal attributes, respectively.

To see the available colors for each argument to tput setaf, use this command:

for i in {0..255}; do tput setaf $i; printf %4d $i; done; tput sgr0; echo

Here is how the output looks:

enter image description here

Here is the evidence that the tput setaf and tput sgr0 commands generate the appropriate ANSI escape sequences:

$ tput setaf 1 | xxd -g1
00000000: 1b 5b 33 31 6d                                   .[31m
$ tput setaf 2 | xxd -g1
00000000: 1b 5b 33 32 6d                                   .[32m
$ tput setaf 6 | xxd -g1
00000000: 1b 5b 33 36 6d                                   .[36m
$ tput sgr0 | xxd -g1
00000000: 1b 28 42 1b 5b 6d                                .(B.[m
Bradley answered 10/3, 2019 at 14:17 Comment(1)
if you get tput: unkown terminfo capability in 'srg0' means your os is old and tput does not recognize srg0 , i was able to use tput setaf 7 in last sed command to get color back to whitePerchloride
I
10

No one has mentioned delta so far. It supports syntax colored diff view with syntax highlighting.

Image source: Delta

Inamorato answered 20/11, 2022 at 19:52 Comment(4)
Wohoooo is this a terminal application?!Nonconformance
doesn't seem to support .diff filesRoshan
It's in Pacman... delta -s file1 file2 # -s is "side by side"Rale
brew install git-deltaLailaibach
A
4

I would suggest you to give diff-so-fancy a try. I use it during my work and it sure seems great as of now. It comes packed with many options and it's really easy to configure your diffs the way you want.

You can install it by:

sudo npm install -g diff-so-fancy

or on Mac:

brew install diff-so-fancy

Afterwards, you can highlight your diffs like this:

diff -u file1 file2 | diff-so-fancy
Antecedents answered 15/9, 2018 at 2:8 Comment(0)
R
4

Character-level color diff: Install ccdiff

ccdiff -r /usr/share/dict/words /tmp/new-dict

Output of ccdiff

Randers answered 19/12, 2019 at 17:55 Comment(1)
ccdiff seems to work well as a diff program, but unfortunately, it cannot color an existing diff (such as a patch).Cullie
H
2

With the bat command:

diff file1 file2 | bat -l diff
Hark answered 26/10, 2019 at 18:25 Comment(1)
What is bat supposed to do? Can you elaborate? Please respond by editing (changing) your answer, not here in comments (without "Edit:", "Update:", or similar - the answer should appear as if it was written today).Palmar
A
2
diff --color=always file_a file_b | less

works for me

Anaya answered 9/2, 2023 at 11:49 Comment(0)
J
0

On recent versions of Git on Ubuntu, you can enable diff-highlighting with:

sudo ln -s /usr/share/doc/git/contrib/diff-highlight/diff-highlight /usr/local/bin
sudo chmod a+x /usr/share/doc/git/contrib/diff-highlight/diff-highlight

And then adding this to your .gitconfig file:

[pager]
    log = diff-highlight | less
    show = diff-highlight | less
    diff = diff-highlight | less

It's possible the script is located somewhere else in other distributions. You can use locate diff-highlight to find out where.

Jestinejesting answered 16/10, 2019 at 3:52 Comment(0)
S
0

My favorite choice is vdiff <file1> <file2> function (I forgot from where I got it).

It will open two windows in Vim side-by-side, to see clearly see the difference between the two files.

vdiff () {
    if [ "${#}" -ne 2 ] ; then
        echo "vdiff requires two arguments"
        echo "  comparing dirs:  vdiff dir_a dir_b"
        echo "  comparing files: vdiff file_a file_b"
        return 1
    fi

    local left="${1}"
    local right="${2}"

    if [ -d "${left}" ] && [ -d "${right}" ]; then
        vim +"DirDiff ${left} ${right}"
    else
        vim -d "${left}" "${right}"
    fi
}

Put this script in your (.alias) or (.zshrc), and then call it using vdiff <file1> <file2>.

Example

Enter image description here

The results are:

Enter image description here

Submarine answered 2/6, 2021 at 5:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.