Use vimdiff as git mergetool
Using vimdiff as a git mergetool can be pretty confusing - multiple windows and little explanation. This is a short tutorial which explains basic usage, and what the LOCAL, BASE, and REMOTE keywords mean. This implies that you have at least a little bit of basic vim knowledge (how to move, save, and switch between split windows). If you don’t, there’s a short article for you: Using vim for writing code. Some basic understanding of git and branching is required as well, obviously.
Git config
Prior to doing anything, you need to know how to set vimdiff as a git mergetool. That being said:
git config merge.tool vimdiff
git config merge.conflictstyle diff3
git config mergetool.prompt false
This will set git as the default merge tool, will display a common ancestor while merging, and will disable the prompt to open the vimdiff.
Creating merge conflict
Let’s create a test situation. You are free to skip this part or you can work along with the tutorial.
mkdir zoo
cd zoo
git init
vi animals.txt
Let’s add some animals:
cat
dog
octopus
octocat
Save the file.
git add animals.txt
git commit -m "Initial commit"
git branch octodog
git checkout octodog
vi animals.txt # let's change octopus to octodog
git add animals.txt
git commit -m "Replace octopus with an octodog"
git checkout master
vi animals.txt # let's change octopus to octoman
git add animals.txt
git commit -m "Replace octopus with an octoman"
git merge octodog # merge octodog into master
That’s where we get a merge error:
Auto-merging animals.txt
CONFLICT (content): Merge conflict in animals.txt
Automatic merge failed; fix conflicts and then commit the result.
Resolving merge conflict with vimdiff
Let’s resolve the conflict:
git mergetool
This looks terrifying at first, but let me explain what is going on.
From left to right, top to the bottom:
LOCAL
– this is file from the current branch
BASE
– common ancestor, how file looked before both changes
REMOTE
– file you are merging into your branch
MERGED
– merge result, this is what gets saved in the repo
Let’s assume that we want to keep the “octodog” change (from REMOTE). For that,
move to the MERGED file (Ctrl + w, j
), move your cursor to a merge conflict
area and then:
:diffget RE
This gets the corresponding change from REMOTE and puts it in MERGED file. You can also:
:diffg RE " get from REMOTE
:diffg BA " get from BASE
:diffg LO " get from LOCAL
Save the file and quit (a fast way to write and quit multiple files is :wqa
).
Run git commit
and you are all set!
If you’d like to get even better about using Vim, I wrote a book about it: Mastering Vim. I’m pretty proud of how it turned out, and I hope you like it too.
35 read-only comments
These are the read-only comments I've exported from Disqus (which I no longer use). If you'd like to share your thoughts about this article, you can ✍️ Reply by email.
Thanks, this was a really useful tutorial.
But now I find that vimdiff has created 5 iterations of the merged files which are causing "IllegalMigrationNameError"s in Ruby. Since these iterations won't migrate, can I simply manually delete them from my Ruby project without suffering further complications?
Mark,
Files with illegal name are created by git as a merge by-product. You can freely delete them (these are the files that end with
.orig
I assume).Awesome, thanks.
Don't forget
[c
and]c
to jump to the previous and next conflict.I wish vimdiff supported a 3-way diff. A 3-file diff is not the same as a 3-way diff.
eljay451,
Do you mean 3-way merge? Because example above does outline 3-way merge: file A, file B and their common ancestor. See Three way merge on Wikipedia.
Great post! Helped me out a lot
This can be done without a wrapper.
git config --global diff.tool = 'vimdiff'
git config --global merge.tool = 'vimdiff'
git config --global alias.d = 'difftool'
git config --global alias.m = 'mergetool'
Thanks a lot for a great article, man. It was simple and straight to the point, and still reminded me of my long abandoned (in favor of Emacs) - but still cool to use - VIM.
Great article!
You saved me!! Thanks for sharing this.
For those who are using gvim instead of vim, you can set the tool to be "gvimdiff" and it will work the same way with the GUI version of the editor.
This article is perfect!
In truth this jumps between previous and next difference, not conflict. For that you need to /=== etc, or use a plugin like ConflictMotions.
Ah, that's true. Didn't know about ConflictMotions, thanks!
The `.orig` files are byproducts of the merge conflict process and are created by any merge tool. You can use `git clean` to clean these up once your work tree is in a happy place again.
Didn't no `git clean` removes `.orig` files, nice!
Actually the explain about LOCAL, BASE and REMOTE is not quite right and confusing. I found explanation in here is more correct and easy to understand - https://stackoverflow.com/q...
In short
The BASE is correct
The LOCAL is the target branch (we are merging into or rebase into)
The REMOTE is the current branch (We are merging or rebasing from)
The file itself is in the bottom buffer.
Thanks for this post. Very helpful
Thank you for your concise explanation.
Awesome... I forgot how I did it in the past... Now I can start using Vim again for merge conflicts.... I just love ViM.
For the peeps interested, here you can find my .vimrc with some really handy plugins and configurations. https://github.com/marcofra...
This is pretty good, love the plugins you using. Lots of setting match my vimrc, even though mine is starting to look a little messy... https://github.com/ruslanos...
That's very usefull! Thanks!
What is [c and ]c?
`]c` and `[c` are keyboard shortcuts which let you navigate between changes (literally a `[` or a `]` press followed by `c`). See `:help ]c` for more details.
i think it doesn't need to clean orig file, get 'cat file.orig' well you see a good history about conflict, maybe needed in future :)
I prefer to commit it too
I got 3 vertical splits, but no `MERGED` horizontal split at the bottom. The `diffget` command didn't do anything. I guess things have changed since you wrote this.
I end up coming back to this page once every few months for a refresher. Absolute lifesaver!
The 3 window setup is actually recommended here https://www.grzegorowski.co...
is it possible to apply changes from both RE and LO (one below the other) ?
https://stackoverflow.com/q...
The best source on this specific topic! Thanks for the clear documentation!
I have this problem at the moment and it is driving me mad. Did you find a way to get the 'MERGED' pane back?
Try to expand your terminal. In my case (vimdiff run under screen) small terminal size was the problem.
thank you for this - i made a comic and linked to your post because it is so clear
I love your comic <3