When I type git diff
, I'd like to see a side-by-side diff, like with diff -y
, or like to display the diff in an interactive diff tool like kdiff3
. How can this be done?
Although Git has an internal implementation of diff, you can set up an external tool instead.
There are two different ways to specify an external diff tool:
- setting the
GIT_EXTERNAL_DIFF
and theGIT_DIFF_OPTS
environment variables. - configuring the external diff tool via
git config
ymattw
's answer is also pretty neat, using ydiff
See also:
- https://git-scm.com/book/en/v2/Customizing-Git-Git-Configuration
git diff --help
- http://www.pixelbeat.org/programming/diffs/
When doing a git diff
, Git checks both the settings of above environment variables and its .gitconfig
file.
By default, Git passes the following seven arguments to the diff program:
path old-file old-hex old-mode new-file new-hex new-mode
You typically only need the old-file and new-file parameters. Of course most diff tools only take two file names as an argument. This means that you need to write a small wrapper-script, which takes the arguments which Git provides to the script, and hands them on to the external git program of your choice.
Let's say you put your wrapper-script under ~/scripts/my_diff.sh
:
#!/bin/bash
# un-comment one diff tool you'd like to use
# use standard diff command with options: (2023)
/usr/bin/diff -y "$2" "$5"
# side-by-side diff with custom options:
# /usr/bin/sdiff -w200 -l "$2" "$5"
# using kdiff3 as the side-by-side diff:
# /usr/bin/kdiff3 "$2" "$5"
# using Meld
/usr/bin/meld "$2" "$5"
# using VIM
# /usr/bin/vim -d "$2" "$5"
you then need to make that script executable:
chmod a+x ~/scripts/my_diff.sh
you then need to tell Git how and where to find your custom diff wrapper script. You have three choices how to do that: (I prefer editing the .gitconfig file)
Using
GIT_EXTERNAL_DIFF
,GIT_DIFF_OPTS
e.g. in your .bashrc or .bash_profile file you can set:
GIT_EXTERNAL_DIFF=$HOME/scripts/my_diff.sh export GIT_EXTERNAL_DIFF
Using
git config
use "git config" to define where your wrapper script can be found:
git config --global diff.external ~/scripts/my_diff.sh
Editing your
~/.gitconfig
fileyou can edit your
~/.gitconfig
file to add these lines:[diff] external = ~/scripts/my_diff.sh
Note:
Similarly to installing your custom diff tool, you can also install a custom merge-tool, which could be a visual merging tool to better help visualizing the merge. (see the progit.org page)
See: http://fredpalma.com/518/visual-diff-and-merge-tool/ and https://git-scm.com/book/en/v2/Customizing-Git-Git-Configuration
meld
? –
Petuntse meld
version be configured to do a directory diff, where I can choose which file(s) I want to see the diff for? Currently it runs a separate meld
command for each file, and I have to quit meld
in order to see the next file. I'd rather have meld
show me a directory listing of changed files like it behaves when meld
is used from Mercurial. –
Philbrook Try git difftool
Use git difftool
instead of git diff
. You'll never go back.
UPDATE to add an example usage:
Here is a link to another stackoverflow that talks about git difftool
: How do I view 'git diff' output with my preferred diff tool/ viewer?
For newer versions of git
, the difftool
command supports many external diff tools out-of-the-box. For example vimdiff
is auto supported and can be opened from the command line by:
cd /path/to/git/repo
git difftool --tool=vimdiff
Other supported external diff tools are listed via git difftool --tool-help
here is an example output:
'git difftool --tool=<tool>' may be set to one of the following:
araxis
kompare
vimdiff
vimdiff2
The following tools are valid, but not currently available:
bc3
codecompare
deltawalker
diffuse
ecmerge
emerge
gvimdiff
gvimdiff2
kdiff3
meld
opendiff
tkdiff
xxdiff
This message is displayed because 'diff.tool' is not configured.
. Perhaps update answer with minimal how-to configure this thing, so that it display side-by-side diffs in terminal, which is what OP asked for? GUI tools are quite useless on remote server where you connect using ssh. –
Irrepealable git difftool
with vimdiff
doesn't always line up the two files/buffers correctly. –
Hofuf git difftool -y
to prevent tkdiff prompt –
Prong git difftool
in Windows & Linux: https://mcmap.net/q/12247/-git-mergetool-with-meld-on-windows –
Bradwell dir-diff
option: https://mcmap.net/q/12824/-git-difftool-open-all-diff-files-immediately-not-in-serial –
Ascendant $PATH
. "Araxis" is a tool for Windows and Mac whose name in the shell is compare
. compare
also happens to be a program included with ImageMagick on Linux, so if you've never heard of Araxis and see it on your machine you probably don't actually have it and passing it to --tool=
will do nothing. –
Joachima Although Git has an internal implementation of diff, you can set up an external tool instead.
There are two different ways to specify an external diff tool:
- setting the
GIT_EXTERNAL_DIFF
and theGIT_DIFF_OPTS
environment variables. - configuring the external diff tool via
git config
ymattw
's answer is also pretty neat, using ydiff
See also:
- https://git-scm.com/book/en/v2/Customizing-Git-Git-Configuration
git diff --help
- http://www.pixelbeat.org/programming/diffs/
When doing a git diff
, Git checks both the settings of above environment variables and its .gitconfig
file.
By default, Git passes the following seven arguments to the diff program:
path old-file old-hex old-mode new-file new-hex new-mode
You typically only need the old-file and new-file parameters. Of course most diff tools only take two file names as an argument. This means that you need to write a small wrapper-script, which takes the arguments which Git provides to the script, and hands them on to the external git program of your choice.
Let's say you put your wrapper-script under ~/scripts/my_diff.sh
:
#!/bin/bash
# un-comment one diff tool you'd like to use
# use standard diff command with options: (2023)
/usr/bin/diff -y "$2" "$5"
# side-by-side diff with custom options:
# /usr/bin/sdiff -w200 -l "$2" "$5"
# using kdiff3 as the side-by-side diff:
# /usr/bin/kdiff3 "$2" "$5"
# using Meld
/usr/bin/meld "$2" "$5"
# using VIM
# /usr/bin/vim -d "$2" "$5"
you then need to make that script executable:
chmod a+x ~/scripts/my_diff.sh
you then need to tell Git how and where to find your custom diff wrapper script. You have three choices how to do that: (I prefer editing the .gitconfig file)
Using
GIT_EXTERNAL_DIFF
,GIT_DIFF_OPTS
e.g. in your .bashrc or .bash_profile file you can set:
GIT_EXTERNAL_DIFF=$HOME/scripts/my_diff.sh export GIT_EXTERNAL_DIFF
Using
git config
use "git config" to define where your wrapper script can be found:
git config --global diff.external ~/scripts/my_diff.sh
Editing your
~/.gitconfig
fileyou can edit your
~/.gitconfig
file to add these lines:[diff] external = ~/scripts/my_diff.sh
Note:
Similarly to installing your custom diff tool, you can also install a custom merge-tool, which could be a visual merging tool to better help visualizing the merge. (see the progit.org page)
See: http://fredpalma.com/518/visual-diff-and-merge-tool/ and https://git-scm.com/book/en/v2/Customizing-Git-Git-Configuration
meld
? –
Petuntse meld
version be configured to do a directory diff, where I can choose which file(s) I want to see the diff for? Currently it runs a separate meld
command for each file, and I have to quit meld
in order to see the next file. I'd rather have meld
show me a directory listing of changed files like it behaves when meld
is used from Mercurial. –
Philbrook You can also try git diff --word-diff
.
It's not exactly side-by-side, but somehow better, so you might prefer it to your actual side-by-side need.
git diff --word-diff=color
–
Abvolt --word-diff=color
gives me an invalid option error. Which version was it introduced in? –
Taproom git diff --color-words
does work. –
Taproom git diff --color-words
is the way to go on modern git versions. –
Webster ydiff
Formerly called cdiff
, this tool can display side by side, incremental, and colorful diff.
Instead of doing git diff
, do:
ydiff -s -w0
This will launch ydiff
in side-by-side display mode for each of the files with differences.
Install with:
python3 -m pip install --user ydiff
-or-
brew install ydiff
For git log
, you can use:
ydiff -ls -w0
-w0
auto-detects your terminal width. See the ydiff
GitHub repository page for detail and demo.
Tested in Git 2.18.0, ydiff 1.1.
git diff | cdiff -s
with icdiff? –
Noach ydiff -s
from a git/svn/hg workspace, you don't have to pipe in. –
Cultigen cd <git repo>
and then run ydiff -ls <path/to/file>
–
Rainproof ~/.local/bin/ydiff
–
Maybellemayberry ydiff
does not work for me –
Trilinear You can do a side-by-side diff
using sdiff
as follows:
$ git difftool -y -x sdiff HEAD^ | less
where HEAD^
is an example that you should replace with whatever you want to diff against.
I found this solution here where there are a couple of other suggestions also. However, this one answer's the OP's question succinctly and clearly.
See the man git-difftool for an explanation of the arguments.
Taking the comments on board, you can create a handy git sdiff
command by writing the following executable script:
#!/bin/sh
git difftool -y -x "sdiff -w $(tput cols)" "${@}" | less
Save it as /usr/bin/git-sdiff
and chmod +x
it. Then you'll be able to do this:
$ git sdiff HEAD^
Extra Tip
As suggested in comments you can use icdiff
to do what sdiff
does with colored output:
$ more /usr/bin/git-sdiff
#!/bin/sh
git difftool -y -x "icdiff --cols $(tput cols)" "${@}" | less --raw-control-chars
For unix, combining just git
and the built-in diff
:
git show HEAD:path/to/file | diff -y - path/to/file
Of course, you can replace HEAD with any other git reference, and you probably want to add something like -W 170
to the diff command.
This assumes that you are just comparing your directory contents with a past commit. Comparing between two commits is more complex. If your shell is bash
you can use "process substitution":
diff -y -W 170 <(git show REF1:path/to/file) <(git show REF2:path/to/file)
where REF1
and REF2
are git references – tags, branches or hashes.
I recently implemented a tool that does exactly this: https://github.com/banga/git-split-diffs
Here's how to use it:
npm install -g git-split-diffs
git config --global core.pager "git-split-diffs --color | less -RFX"
And this is how it looks in your terminal (with the default theme):
As you can see, it also supports syntax highlighting and highlighting changed words within lines
git diff --staged
–
Endsley export GIT_EXTERNAL_DIFF='meld $2 $5; echo >/dev/null'
then simply:
git diff
meld
works also quite good with XQartz-X-Display-Redirect. (Debian to macOS) –
Whangee If you'd like to see side-by-side diffs in a browser without involving GitHub, you might enjoy git webdiff, a drop-in replacement for git diff
:
$ pip install webdiff
$ git webdiff
This offers a number of advantages over traditional GUI difftools like tkdiff
in that it can give you syntax highlighting and show image diffs.
Read more about it here.
I use colordiff.
On Mac OS X, install it with
$ sudo port install colordiff
On Linux is possibly apt get install colordiff
or something like that, depending on your distro.
Then:
$ git difftool --extcmd="colordiff -ydw" HEAD^ HEAD
Or create an alias
$ git alias diffy "difftool --extcmd=\"colordiff -ydw\""
Then you can use it
$ git diffy HEAD^ HEAD
I called it "diffy" because diff -y
is the side-by-side diff in unix. Colordiff also adds colors, that are nicer.
In the option -ydw
, the y
is for the side-by-side, the w
is to ignore whitespaces, and the d
is to produce the minimal diff (usually you get a better result as diff)
-y
to skip the Launch 'colordiff' [Y/n]:
prompt. –
Wenwenceslaus git alias diffy "difftool --extcmd=\"colordiff -ydw\""
? Shouldn't it be git config --global alias.diffy "difftool --extcmd=\"colordiff -ydw\""
? –
Flews apt install colordiff
or apt-get install colordiff
, apt get install colordiff
is not working. –
Whangee git difftool -y -x 'colordiff -y --width=$(tput cols) --tabsize=4 --expand-tabs --ignore-all-space' HEAD~1
- HEAD~1 is just an example, and I'm sure someone can create an alias or a script from that. –
Phonology I personally really like icdiff !
If you're on Mac OS X
with HomeBrew
, just do brew install icdiff
.
To get the file labels correctly, plus other cool features, I have in my ~/.gitconfig
:
[pager]
difftool = true
[diff]
tool = icdiff
[difftool "icdiff"]
cmd = icdiff --head=5000 --highlight --line-numbers -L \"$BASE\" -L \"$REMOTE\" \"$LOCAL\" \"$REMOTE\"
And I use it like: git difftool
This question showed up when I was searching for a fast way to use git builtin way to locate differences. My solution criteria:
- Fast startup, needed builtin options
- Can handle many formats easily, xml, different programming languages
- Quickly identify small code changes in big textfiles
I found this answer to get color in git.
To get side by side diff instead of line diff I tweaked mb14's excellent answer on this question with the following parameters:
$ git diff --word-diff-regex="[A-Za-z0-9. ]|[^[:space:]]"
If you do not like the extra [- or {+ the option --word-diff=color
can be used.
$ git diff --word-diff-regex="[A-Za-z0-9. ]|[^[:space:]]" --word-diff=color
That helped to get proper comparison with both json and xml text and java code.
In summary the --word-diff-regex
options has a helpful visibility together with color settings to get a colorized side by side source code experience compared to the standard line diff, when browsing through big files with small line changes.
Use delta
.
In your gitconfig file (usually ~/.gitconfig
or ~/.config/git/config
),
add:
[core]
pager = delta --light --side-by-side
Open Intellij IDEA, select a single or multiple commits in the "Version Control" tool window, browse changed files, and double click them to inspect changes side by side for each file.
With the bundled command-line launcher you can bring IDEA up anywhere with a simple idea some/path
Here's an approach. If you pipe through less, the xterm width is set to 80, which ain't so hot. But if you proceed the command with, e.g. COLS=210, you can utilize your expanded xterm.
gitdiff()
{
local width=${COLS:-$(tput cols)}
GIT_EXTERNAL_DIFF="diff -yW$width \$2 \$5; echo >/dev/null" git diff "$@"
}
Several others already mentioned cdiff for git side-by-side diffing but no one gave a full implementation of it.
Setup cdiff:
git clone https://github.com/ymattw/cdiff.git
cd cdiff
ln -s `pwd`/cdiff ~/bin/cdiff
hash -r # refresh your PATH executable in bash (or 'rehash' if you use tcsh)
# or just create a new terminal
Edit ~/.gitconfig inserting these lines:
[pager]
diff = false
show = false
[diff]
tool = cdiff
external = "cdiff -s $2 $5 #"
[difftool "cdiff"]
cmd = cdiff -s \"$LOCAL\" \"$REMOTE\"
[alias]
showw = show --ext-dif
The pager off is needed for cdiff to work with Diff, it is essentially a pager anyway so this is fine. Difftool will work regardless of these settings.
The show alias is needed because git show only supports external diff tools via argument.
The '#' at the end of the diff external command is important. Git's diff command appends a $@ (all available diff variables) to the diff command, but we only want the two filenames. So we call out those two explicitly with $2 and $5, and then hide the $@ behind a comment which would otherwise confuse sdiff. Resulting in an error that looks like:
fatal: <FILENAME>: no such path in the working tree
Use 'git <command> -- <path>...' to specify paths that do not exist locally.
Git commands that now produce side-by-side diffing:
git diff <SHA1> <SHA2>
git difftool <SHA1> <SHA2>
git showw <SHA>
Cdiff usage:
'SPACEBAR' - Advances the page of the current file.
'Q' - Quits current file, thus advancing you to the next file.
You now have side-by-side diff via git diff and difftool. And you have the cdiff python source code for power user customization should you need it.
This may be a somewhat limited solution, but does the job using the system's diff
command without external tools:
diff -y <(git show from-rev:the/file/path) <(git show to-rev:the/file/path)
- filter just the change lines use
--suppress-common-lines
(if yourdiff
supports the option). - no colors in this case, just the usual
diff
markers - can tweak the column width
--width=term-width
; in Bash can get the width as$COLUMNS
ortput cols
.
This can be wrapped into a helper git-script too for more convenience, for example, usage like this:
git diffy the/file/path --from rev1 --to rev2
There are multiple solutions:
Solution 1 : Meld :
Install meld (in ubuntu I used sudo apt install meld
). Then configure it like bellow.
git config --global diff.tool meld
git config --global difftool.meld.path "$(which meld)"
git config --global difftool.prompt false
git config --global merge.tool meld
git config --global mergetool.meld.path "$(which meld)"
Solution 2 : Delta :
If you decide to use cli, then install delta. The config I use is:
git config --global core.pager 'delta'
git config --global interactive.diffFilter 'delta --color-only'
git config --global delta.side-by-side true
git config --global delta.line-numbers true
git config --global delta.syntax-theme 'Solarized (dark)'
Solution 3 : Melt :
You can also use Melt. It's syntax highlighting is done with bat. This is also a cli tool.
There are a lot of good answers on this thread. My solution for this issue was to write a script.
Name this 'git-scriptname' (and make it executable and put it in your PATH, like any script), and you can invoke it like a normal git command by running
$ git scriptname
The actual functionality is just the last line. Here's the source:
#!/usr/bin/env zsh
#
# Show a side-by-side diff of a particular file how it currently exists between:
# * the file system
# * in HEAD (latest committed changes)
function usage() {
cat <<-HERE
USAGE
$(basename $1) <file>
Show a side-by-side diff of a particular file between the current versions:
* on the file system (latest edited changes)
* in HEAD (latest committed changes)
HERE
}
if [[ $# = 0 ]]; then
usage $0
exit
fi
file=$1
diff -y =(git show HEAD:$file) $file | pygmentize -g | less -R
© 2022 - 2024 — McMap. All rights reserved.
diff
. I better get used to reading the non-side-by-side format, which is hard for a visual person. – Triumphant