34

In my repository, if I type

$ git diff some-file

or

$ git difftool some-file

I get the in-terminal diff display. I think this should not happen, because I have set up an external diff tool, as shown by the output of git config -l:

$ git config -l
user.name=blah blah
user.email=blah blah
http.sslverify=true
diff.external=/home/daniel/bin/git-diff  <--This is the important line
push.default=simple
core.filemode=false
core.editor=gedit
alias.tree=log --all --graph --decorate=short --color --format=format:'%C(bold blue)%h%C(reset) %C(auto)%d%C(reset)
         %C(black)[%cr]%C(reset)  %x09%C(black)%an: %s %C(reset)'
core.repositoryformatversion=0
core.filemode=false
core.bare=false
core.logallrefupdates=true
core.ignorecase=true
remote.origin.url=https://daniel@skynet/git/pyle.git
remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
branch.master.remote=origin
branch.master.merge=refs/heads/master
branch.daniel.remote=origin
branch.daniel.merge=refs/heads/daniel

The git-diff file referenced in the diff.external line looks like this

#!/bin/bash

meld $2 $5

Why doesn't git diff invoke meld?

I get the same behaviour if I set things up so that git config -l has the following line:

diff.tool = meld

or

diff.external = usr/bin/meld

Note: Other repositories on my machine don't have this problem.

Related, but not equivalent, SO questions:

  1. What is the difference between git diff and git difftool?
  2. Cannot make git diff use diff.external for external diff tool
Community
  • 1
  • 1
DanielSank
  • 3,303
  • 3
  • 24
  • 42

3 Answers3

23

I get the in-terminal diff display. I this should not happen, because I have set up an external diff tool

Yes, it should: diff.external is for "in-terminal diff display".

(from git config man page)

diff.external

If this config variable is set, diff generation is not performed using the internal diff machinery, but using the given command.
Can be overridden with the GIT_EXTERNAL_DIFF environment variable.
The command is called with parameters as described under "git Diffs" in git(1). Note: if you want to use an external diff program only on a subset of your files, you might want to use gitattributes(5) instead.

The question you link explains why meld wouldn't be able to play the role of an "external diff".

Viewing a diff visually with another tool is done with:

git difftool --dir-diff shaOfHisCheckIn^!
git difftool --tool=meld --dir-diff shaOfHisCheckIn^!
git difftool -t meld -d shaOfHisCheckIn^!

meld can be configured on Windows as a difftool: see "Git Diff and Meld on Windows".


If you wanted to configure meld for git diff, you could (on Ubuntu) use the diff.external, but with a wrapper script:

create a file called git-diff.sh, using the following content:

#!/bin/bash
meld "$2" "$5" > /dev/null 2>&1

Save this to a location such as /usr/local/bin, giving it executable rights:

$ sudo mv git-diff.sh /usr/local/bin/
$ sudo chmod +x /usr/local/bin/git-diff.sh

The final step is to open your $HOME/.gitconfig file and add the following few lines:

[diff]
        external = /usr/local/bin/git-diff.sh

The next time you type git diff in a Git project with changes, Meld will be launched showing you a split-pane diff viewer.
Note that you are required to close the open instance of meld before the next diff viewer is opened.


will notes in the comments:

That wrapper script works great on my Ubuntu system.

I did discover a gottcha: I detached the meld command as so:

meld "$2" "$5" > /dev/null 2>&1 &

Kept failing to open the $2 file (tempory file).
What happens? Well, git removes $2 once the wrapper exits.
My suggestion, if you wish to detach copy the tmp file, invoke meld and remove tmp file yourself.

will proposes the gist gist-meld.bash, using meld --newtab, as seen here:

#!/bin/bash
#  * expects meld to be on your default PATH
#
function detach_meld()
{
    local f1="/tmp/mld1-$(basename "$1")"
    local f2="/tmp/mld2-$(basename "$2")"
    
##  echo "f1 = ${f1}"
##  echo "f2 = ${f2}"

    cp "$1" "${f1}"
    cp "$2" "${f2}"
#
    (meld  --newtab  "${f1}" "${f2}" ; rm  "${f1}"  "${f2}" ) > /dev/null 2>&1  &    
}

detach_meld  "$2"  "$5"
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • 4
    `git difftool` seems to be the solution. I tried using a wrapper script but for some reason that doesn't work. – DanielSank Jul 29 '14 at 02:11
  • That wrapper script works great on my Ubuntu system. I did discover a _gottcha_. I detached the `meld` command as so: `meld "$2" "$5" > /dev/null 2>&1 &`. Kept failing to open the `$2` file (tempory file). What happens? Well, `git` removes `$2` once the wrapper exits. My suggestion, if you wish to detach copy the tmp file, invoke `meld` and remove tmp file yourself. – will Jul 19 '21 at 13:39
  • @will Thank you for your feedback. I have included your comment in the answer for more visibility. – VonC Jul 19 '21 at 14:21
  • @VonC .. Me again. Today I discovered the branch diff operation: `git diff main...mybranch` -- It compares two temporary files when you use a `meld` wrapper script. One is always blank for the same "temporary file" reason above. I changed my wrapper script to make two copy temp files -- **Works**!! – will Jul 28 '21 at 05:56
  • @will Great! Do you have a link to your wrapper script? – VonC Jul 28 '21 at 06:00
  • 1
    I put up a gist: [git-meld.bash](https://gist.github.com/aplatypus/5ac6ba4bab2b145a3a24ef9760b836b4). If you actually do compare branches, be prepared for a great number of meld windows to pop-up. One for each file in the branch. Please leave a commend if you know how open the files as tabs in meld? – will Jul 29 '21 at 03:29
  • @will Maybe by using the meld `--newtab` option ? Seen here in the context of bzr: https://askubuntu.com/a/1058344/5470: see if you can adapt it to git difftool option. – VonC Jul 29 '21 at 06:35
  • @VonC ... Great idea. I was concerned that the temp files might get lost or overritten -- No Worries. It works smoothly opening all the files and I feel it is faster using ` --newtab` . Gist updated: [git-meld.bash](https://gist.github.com/aplatypus/5ac6ba4bab2b145a3a24ef9760b836b4). Thanks. Great suggestion. – will Aug 04 '21 at 12:58
16

It seems that git diff (at least, as of git version 1.7.12.4) will not run anything other than the internal, console-only diff on a file which is in the "both modified" state. git mergetool works on such files, though.

Trebor Rude
  • 1,904
  • 1
  • 21
  • 31
  • 3
    This is still true with git version 1.9.1, What an annoyance! I just wasted an hour trying to figure out why my git config settings for difftool had suddenly stopped working. – Die in Sente Jan 20 '16 at 20:52
  • 2
    Still the case on `git version 2.5.4 (Apple Git-61)`. The console only 3-way-merge workflow is a pretty big pain point. There's really a huge shortage of capable console native diff tools. I believe the path i will take is to allow git to dump the conflict markers into the files, and then use a simple tool, that I will write, to processes these to generate readable diff outputs. – Steven Lu Feb 21 '16 at 22:17
  • 2
    Aha! @trebor-rude, you just saved my sanity with wondering why none of my difftool selections were working – jaygooby Jan 26 '17 at 14:14
2

I usually just want to check whether the changes I'm about to check in are correct. So I followed the procedure suggested here (similar to the one noted by VonC). However, running git difftool still didn't open meld. I then created an alias:

alias git-diff='git difftool $(git rev-parse HEAD)'

Save this in your .bashrc or .zshrc or the corresponding config for your shell. This essentially compares the state of the branch with the previous commit on the branch.

Do a git-diff to see changes on a file per file basis or git-diff --dir to see all changes in a directory view.

Lodewyk
  • 396
  • 4
  • 6