using meld with git

meld

Obviously git is awesome. I don't use any graphical front-ends, nor any IDEs with built-in support. I don't need them, and I don't want them. The only GUI tool I want in my git workflow is meld. It is a graphical diff tool that lets you see the old and new versions side-by-side for easy comparison, with highlighting.

In this post I'll explain both how I use it with git, and how I arrived there.

preparation

First of all, you'll need to write a shell script that passes the output of git diff to meld. Here's the simplest possible version. git diff passes a bunch of arguments, but we only care about the second and fifth -- the old and new filenames:

#!/usr/bin/env bash

meld $2 $5

Secondly, you'll need to tell git to use your script:

git config --global diff.external /home/username/git_meld.sh

done?

If you want, you can use the above as-is and it will work. However, there's a major drawback here. If your diff is more than one file, then what will happen when you run git diff is that you'll get a meld window for just one file. You have to close it in order to see the next file.

That's a problem for me, because I may want to review a previous file if questions come up while reviewing a later file. Or I just want to choose the order in which I review the files.

obviously...

The obvious (and wrong) solution is just to change this:

meld $2 $5

to this:

meld $2 $5 &

You'd think it would open them all at once. In reality, however, you get no diff at all. This is because git diff creates temp files for the previous version of the file. Think about it -- what are you comparing your current files to? The stuff hidden in git blobs. So git helpfully creates tempfiles for you, and automatically deletes them after the diff is done. Running with & tells git it's done, and it deletes the temp files before you even get to see them.

take control of your temp files

Okay, if the temp files get deleted on us, why not just make a copy of them? If we copy them to our own temp files, we can just use those and let git delete the ones it creates:

#!/usr/bin/env bash

OLD=$(mktemp)
NEW=$(mktemp)

cp $2 $OLD
cp $5 $NEW

meld $OLD $NEW  &

Okay, now we're getting somewhere. This works. But there's one problem. The filenames at the top of the page in meld are just randomly-generated tempfile names. If your project is small then maybe this is okay. We could use the basename command to add the actual filename to the tempfile name, but if your project has multiple files with the same name (perhaps a Django project with multiple files named views.py or models.py), then this could get confusing.

finale

Here's the final script that I actually use:

#!/usr/bin/env bash

OLD=$(mktemp)_$(echo $2 | tr '/' '_')
NEW=$(mktemp)_$(echo $5 | tr '/' '_')

cp $2 $OLD
cp $5 $NEW

meld $OLD $NEW  &

All this does is use the tr command to replace forward-slashes with underscores. Now the meld window will show the full path and filename of the files being compared.

Comments !

blogroll

social