How do I view 'git diff' output with my preferred diff tool/ viewer?
Solution 1
Since Git1.6.3, you can use the git difftool script: see my answer below.
May be this article will help you. Here are the best parts:
There are two different ways to specify an external diff tool.
The first is the method you used, by setting the GIT_EXTERNAL_DIFF variable. However, the variable is supposed to point to the full path of the executable. Moreover, the executable specified by GIT_EXTERNAL_DIFF will be called with a fixed set of 7 arguments:
path old-file old-hex old-mode new-file new-hex new-mode
As most diff tools will require a different order (and only some) of the arguments, you will most likely have to specify a wrapper script instead, which in turn calls the real diff tool.
The second method, which I prefer, is to configure the external diff tool via "git config". Here is what I did:
1) Create a wrapper script "git-diff-wrapper.sh" which contains something like
-->8-(snip)--
#!/bin/sh
# diff is called by git with 7 parameters:
# path old-file old-hex old-mode new-file new-hex new-mode
"<path_to_diff_executable>" "$2" "$5" | cat
--8<-(snap)--
As you can see, only the second ("old-file") and fifth ("new-file") arguments will be passed to the diff tool.
2) Type
$ git config --global diff.external <path_to_wrapper_script>
at the command prompt, replacing with the path to "git-diff-wrapper.sh", so your ~/.gitconfig contains
-->8-(snip)--
[diff]
external = <path_to_wrapper_script>
--8<-(snap)--
Be sure to use the correct syntax to specify the paths to the wrapper script and diff tool, i.e. use forward slashed instead of backslashes. In my case, I have
[diff]
external = \"c:/Documents and Settings/sschuber/git-diff-wrapper.sh\"
in .gitconfig and
"d:/Program Files/Beyond Compare 3/BCompare.exe" "$2" "$5" | cat
in the wrapper script. Mind the trailing "cat"!
(I suppose the '| cat
' is needed only for some programs which may not return a proper or consistent return status. You might want to try without the trailing cat if your diff tool has explicit return status)
(Diomidis Spinellis adds in the comments:
The
cat
command is required, becausediff(1)
, by default exits with an error code if the files differ.
Git expects the external diff program to exit with an error code only if an actual error occurred, e.g. if it run out of memory.
By piping the output ofgit
tocat
the non-zero error code is masked.
More efficiently, the program could just runexit
with and argument of 0.)
That (the article quoted above) is the theory for external tool defined through config file (not through environment variable).
In practice (still for config file definition of external tool), you can refer to:
- How do I setup DiffMerge with msysgit / gitk? which illustrates the concrete settings of DiffMerge and WinMerge for MsysGit and gitk
- How can I set up an editor to work with Git on Windows? for the definition of Notepad++ as an external editor.
Solution 2
To complete my previous "diff.external" config answer above:
As mentioned by Jakub, Git1.6.3 introduced git difftool, originally proposed in September 2008:
USAGE='[--tool=tool] [--commit=ref] [--start=ref --end=ref] [--no-prompt] [file to merge]'
(See --extcmd
in the last part of this answer)
$LOCAL
contains the contents of the file from the starting revision and $REMOTE
contains the contents of the file in the ending revision.
$BASE
contains the contents of the file in the wor
It's basically
git-mergetool
modified to operate on the git index/worktree.The usual use case for this script is when you have either staged or unstaged changes and you'd like to see the changes in a side-by-side diff viewer (e.g.
xxdiff
,tkdiff
, etc).
git difftool [<filename>*]
Another use case is when you'd like to see the same information but are comparing arbitrary commits (this is the part where the revarg parsing could be better)
git difftool --start=HEAD^ --end=HEAD [-- <filename>*]
The last use case is when you'd like to compare your current worktree to something other than HEAD (e.g. a tag)
git difftool --commit=v1.0.0 [-- <filename>*]
Note: since Git 2.5, git config diff.tool winmerge
is enough!
See "git mergetool winmerge"
And since Git 1.7.11, you have the option --dir-diff
, in order to to spawn external diff tools that can compare two directory hierarchies at a time after populating two temporary directories, instead of running an instance of the external tool once per a file pair.
Before Git 2.5:
Practical case for configuring difftool
with your custom diff tool:
C:\myGitRepo>git config --global diff.tool winmerge
C:\myGitRepo>git config --global difftool.winmerge.cmd "winmerge.sh \"$LOCAL\" \"$REMOTE\""
C:\myGitRepo>git config --global difftool.prompt false
With winmerge.sh stored in a directory part of your PATH:
#!/bin/sh
echo Launching WinMergeU.exe: $1 $2
"C:/Program Files/WinMerge/WinMergeU.exe" -u -e "$1" "$2" -dl "Local" -dr "Remote"
If you have another tool (kdiff3, P4Diff, ...), create another shell script, and the appropriate difftool.myDiffTool.cmd
config directive.
Then you can easily switch tools with the diff.tool
config.
You have also this blog entry by Dave to add other details.
(Or this question for the winmergeu
options)
The interest with this setting is the winmerge.sh
script: you can customize it to take into account special cases.
See for instance David Marble's answer below for an example which deals with:
- new files in either origin or destination
- removed files in either origin or destination
As Kem Mason mentions in his answer, you can also avoid any wrapper by using the --extcmd
option:
--extcmd=<command>
Specify a custom command for viewing diffs.
git-difftool
ignores the configured defaults and runs$command $LOCAL $REMOTE
when this option is specified.
For instance, this is how gitk
is able to run/use any diff
tool.
Solution 3
Try this solution:
$ meld my_project_using_git
Meld understands Git and provides navigating around the recent changes.
Solution 4
With new git difftool, its as simple as adding this to your .gitconfig file:
[diff]
tool = any-name
[difftool "any-name"]
cmd = "\"C:/path/to/my/ext/diff.exe\" \"$LOCAL\" \"$REMOTE\""
Optionally, also add:
[difftool]
prompt = false
Also check out diffall, a simple script I wrote to extend the annoying (IMO) default diff behaviour of opening each in serial.
Global .gitconfig on Windows is in %USERPROFILE%\.gitconfig
Solution 5
Since Git version 1.6.3 there is "git difftool" which you can configure to use your favorite graphical diff tool.
Currently supported (at the time of writing this answer) out-of-the-box are KDiff3, Kompare, tkdiff, Meld, xxdiff, emerge, vimdiff, gvimdiff, ecmerge, Diffuse and opendiff; if the tool you want to use isn't on this list, you can always use 'difftool.<tool>.cmd
' configuration option.
"git difftool" accepts the same options as "git diff".
user3891
Updated on July 24, 2022Comments
-
user3891 almost 2 years
When I type
git diff
, I want to view the output with my visual diff tool of choice (SourceGear "diffmerge" on Windows). How do I configure git to do this?-
Debajit almost 15 yearsYou can use "git difftool" instead of "git diff" in all newer versions of git. That will open up a visual diff program.
-
VonC almost 15 yearsRegarding the new script difftool, I have added an answer below: stackoverflow.com/questions/255202/…
-
Alex Grande over 12 yearsgitx - gitx.frim.nl. Nuff said.
-
Dmitry Bespalov over 10 yearsBrief tutorial you'd find here: nathanhoad.net/how-to-meld-for-git-diffs-in-ubuntu-hardy
-
potench about 9 years
git difftool -tool=opendiff
just replaceopendiff
with whatever. -
Michael S. about 8 yearsGo to your repository in Git Bash. Type
git config diff.tool winmerge
. Verify it worked by typinggit difftool
. Get rid of the prompt typinggit config --global difftool.prompt false
. I recommend p4merge instead of winmerge. -
Trevor Boyd Smith almost 6 years(1.) to list supported external diff tools do
git difftool --tool-help
(2.) to open using a specific diff tool likevimdiff
just dogit difftool --tool=vimdiff
. This is a summary of the solution written by @JakubNarębski
-
-
user3891 over 15 yearsah, I'd set the external diff program but didn't know about the 7 arguments, thanks.
-
VonC almost 15 years@Ryan: that is great :) Did you use the "diff.external" setting detailed in this answer or the "git difftool" of my second answer below?
-
koustubh over 14 yearsAlso, any idea of how to get the -s option (open several diffs in one winmerge window) to work in this scheme?
-
vfilby over 14 yearsFantastic! Thank you, tried both DiffMerge and opendiff; both work quite well.
-
Mario about 14 yearsGreat script, it saved me the trouble of looking DiffMerge commands. You might want to modify the install line to use quotes - I had trouble on my machine: "%1"=="--install".
-
VonC about 14 years@Frank: I confirm, the
$PATH
or%PATH%
is respected when it comes togit config
directives (what is your setup? Git Version? OS?). And if you want to signal a post to Carlos, your comment needs to begin with '@
': @Carlos (see meta.stackexchange.com/questions/1093/…) -
VonC about 14 years@Carlos: Frank (see comment above) wanted you to look at stackoverflow.com/questions/1220309/… (for opening several diffs in one winmerge window)
-
Frank Schwieterman about 14 yearsthe path issue I had was resolved, stackoverflow.com/questions/2664283/…
-
VonC over 13 yearsExcellent addition to the
winmerge.sh
script. +1. I have updated my answer to link to yours. -
Tom over 13 yearsThat's great, much easier to type
meld .
thangit difftool
and have to view changed files sequentially. And it's much closer to Mercurial'shg vdiff
plugin. -
Tom over 13 yearsAlso,
meld .
works on Mercurial and Subversion projects too, in case anyone is curious. -
VonC over 13 yearsGood point: nobody has mentioned yet that
--extcmd
option. +1. I have included it in my answer. -
misiu_mp almost 13 yearsHmm, when I do this a list of modified files shows. When I click on one of them or do 'compare' it opens alone in a separate tab. How do I get a diff?
-
db42 almost 13 years@misiu_mp, I just tried it, on clicking the modified files, it shows the diff (old file as well as modified file).
-
ΩmegaMan over 12 yearsAraxis Merge is also configured. araxis.com/merge/scm_integration.html
-
emanaton over 12 yearsexample usage:
git difftool -t kdiff3 HEAD
-
Jez over 12 years
old-file old-hex old-mode new-file new-hex new-mode
that's only 6 arguments, not 7... -
VonC over 12 years@Jez: yes that article omit the first argument, which is the path. You will find it though a few line below.
-
MarkSwears about 12 yearsAt what version was this added? It doesn't appear to work with meld version
1.1.5
. -
idbrii almost 12 yearsFor some reason, using "bc3" is no longer working for me, but if I use "beyond" instead, it's fine.
-
VonC almost 12 yearsNote: git difftool now support directory diffs: stackoverflow.com/questions/2113889/…
-
Christoffer Lette over 11 years+1 (+10 if I could.) This is really the most simple solution. I struggled for hours with the accepted answer, and finally gave up (some of my problems were probably related to running Git through PowerShell...) However, I used
git config --global diff.external winmerge.cmd
, instead of setting theGIT_EXTERNAL_DIFF
environment variable, and it works equally well. -
blong over 11 yearsDo you also have kdiff3 defined as your mergetool? Mind sharing that part of your gitconfig if so?
-
miner49r almost 11 yearsUse the -y option to avoid annoying prompts. Unfortunately, git will wait until FileMerge quits before offering the next changed file. Use the -d option to do a directory compare in one shot.
-
C.J. over 10 yearsSo git sends 7 arguments to a diff program? The more I learn about Git, the more I feel it is was made for one person: The original programmer. This dvcs seems more like a shiny toy that doesn't do much.
-
C.J. over 10 yearswhat is $local and what is $remote?
-
jhewlett over 10 years+1 for a method that doesn't require a wrapper script
-
jhewlett over 10 years@CJohnson: Path to the original file and path to the edited file, respectively.
-
Michael over 10 yearsThe
--start=
and--end=
options are not recognised in v1.7.11 -
Steve Chambers over 10 yearsThanks. This didn't quite work for me but it did work when I removed
path
and changedcmd
to"\"C:/Program Files (x86)/KDiff3/kdiff3.exe\" \"$LOCAL\" \"$REMOTE\""
-
Tobias Kienzler over 9 yearsin case the blog-link dies, here's the linked SO answer: stackoverflow.com/a/1291578/321973
-
BartoszKP over 9 years
winmerge.bat
in the second snippet should bewinmerge.sh
-
legends2k over 9 years@VonC What does the option
-ub
do? I don't see it as one of the command line options of WinMerge. -
spec3 about 8 yearsHi, I tried to follow this procedure for TextWrangler. I am able to open the files, find the differences, but when I click on the list of differences it doesn't show where they are in the text...Any idea?
-
Peter Nimmo over 7 years@user3891 is there an alternate link to the article you referenced, that one is no longer reachable on the web
-
VonC over 7 years@PeterNimmo I have found an alternative link: osdir.com/ml/version-control.msysgit/2008-06/msg00200.html
-
Vadim Kotov over 7 yearsOnly one drawback: sometimes meld can scan diffs much longer than through using difftool. Looks like it still scans gitignored files (lots of build generated files in my case). It took several seconds on my machine to create a list of modified files, but with difftool it happened instantly
-
yucer about 7 yearsThe option -t seems to require the complete path. Maybe using git difftool --extcmd=opendiff is better.
-
yucer about 7 yearsCan you make this for many tools ? And associate them by file extension ?
-
Granger over 6 years@CJohnson: $LOCAL is always the latest commit. However $REMOTE isn't consistent. When looking at changes in the local sandbox, it's the current/edited file, But when diffing historical commits, it's the parent commit. IOW for normal diffs $LOCAL = old and $REMOTE = new. For historical, $LOCAL = newer and $REMOTE = older.
-
Ben about 6 years@VonC The alternative link in your comment is also no longer accessible
-
VonC about 6 years@Ben Thank you. I have edited the answer and restored the link to web.archive.org/web/20170508180316/http://git.net:80/ml/…
-
Steve Chambers about 6 yearsAlso worth mentioning the highly useful
--dir-diff
option in order to compare all the files at once and avoid prompts. -
VonC about 6 years@SteveChambers Yes, I mentioned it in stackoverflow.com/a/10879804/6309. I will edit this answer.
-
Diomidis Spinellis about 5 years@JesseRusak The cat command is required, because diff(1), by default exits with an error code if the files differ. Git expects the external diff program to exit with an error code only if an actual error occurred, e.g. if it run out of memory. By piping the output of git to cat the non-zero error code is masked. More efficiently, the program could just run exit with and argument of 0.
-
VonC about 5 years@DiomidisSpinellis Thank you. I have included your comment in the answer for more visibility.
-
Kevin Meboe about 5 yearsNote: step 2 (modifying diff.external) will cause "git diff" to launch your difftool. This can be undesirable, and can cause problems with user interfaces (like SourceTree), causing them to aggressively launch your tool at odd times. It's probably better to modify diff.tool instead (e.g.: git config --global diff.tool p4merge)
-
VonC about 5 years@KevinMeboe I agree: that is what my second answer below (stackoverflow.com/a/949242/6309) proposes.
-
Jesus H almost 5 yearsA couple of issues with this solution: 1. Doesn't work for new files. WinMerge asks me to enter a second file to compare against. 2. Window to compare next file only opens up after you close the current WinMerge window, no easy way to see all files at the same time.
-
Zameer Fouzan almost 5 yearsthis is the simplest and fastest way.
-
Calvin Taylor over 3 yearsI love meld but it has been behaving very poorly on MacOs, so I've switched to sublime merge.
-
Ashark over 3 yearsIs there the same feature for kompare? I liked this solution very much (especially, that it allows you to select interested file from a list).
-
webasdf about 3 yearsAwesome tip! Worked great for me!
-
Peter Mortensen almost 3 years"port"? On BSD?
-
Peter Mortensen almost 3 yearsCan you add references to 'port' and 'diffuse'? And presumed platforms/operating system(s)?
-
Peter Mortensen almost 3 yearsCan you add a reference to "kaleidoscope"?
-
Eric Duminil about 2 yearsThat's excellent if you want to see current changes. I found
git difftool -y -t meld --dir-diff other_branch
to be useful too, to see the difference with any branch.