Git, Vimdiff, and Merge-Base
git merge-base
is this week’s favourite git command. I use it to show me in a vimdiff everything that has changed on a particular branch since it was created. This took a little bit of looking around to find how to combine the tools, so I thought I’d write it all down in one place.
Git Diff and Vimdiff
I’m a vim user, so while I mostly use git diff
unchanged on the command line, for complicated or long-winded changes I like to use vimdiff so that I can see the context of the changes and sometimes move the changes around between old and new versions of the code. To use this you will first need to configure git so it knows which tool it should use.
git config --global diff.tool vimdiff
With this in place, you can do git difftool
anywhere you would do git diff
with the same arguments and get the diff in vimdiff instead.
I can never remember what this option is called however, so I have an alias that allows me to use git vimdiff
instead:
git config --global alias.vimdiff difftool
Diffing the Contents of a Branch
As an open source project lead, I spend a lot of time reviewing code and it can be tricky to pick out which changes are in a specific branch when other things have happened to master in the meantime; if you just diff against master you get all kinds of other features showing up as being removed in the diff.
Enter git merge-base
, which can identify which commit is the best common ancestor between two commits in git. Usually for me this is the current HEAD of whichever branch I need to code review, and wherever this branch came off master. That parent commit can be found like this (run the command from the branch of interest):
git merge-base master HEAD
Having the SHA1 isn’t all that useful though, I want to use it to diff against:
git difftool $(git merge-base master HEAD)
This shows me only the changes on this branch since it diverged from the master branch – I still need to check for conflicts before merging to master, but to understand the changes in a specific branch, it works really well for me. It’s a bit of a nightmare to type though, so here’s the alias I use:
git config --global alias.branchdiff '!git difftool $(git merge-base master HEAD)'
The !
at the start makes it a bash command, so you do need to start with “git” but this allows you to resolve the nested $()
in the middle. Feel free to share, enjoy, and comment to let me know your own top git tips in return :)
I also use `git difftool master…HEAD` to achieve the same thing nowadays