Conflicts generally arise when two people have changed the same lines in a file…
In these cases, Git cannot automatically determine what is correct.
Conflicts only affect the developer conducting the merge, the rest of the team is unaware of the conflict.
Git will mark the file as being conflicted and halt the merging process.
It is then the developers’ responsibility to resolve the conflict.
Solving a git conflict was always a personal hurdle; either I tried ignoring it by not doing the merge/undoing changes in HEAD or another hacky solution I found randomly.
Once I accepted the fact that conflicts happen I tried rebasing, by even setting my merge by default to git merge --rebase thinking this would make all conflicts go away.
But it turns out that rebasing won’t keep you away from conflicts; rebase applies your commits one by one on top of the target branch’s HEAD,
as such, rebase often introduces conflicts that must be dealt with to
git merge --continue.
Vim Fugitive is an awesome plugin by @tpope https://github.com/tpope/vim-fugitive.
One of its awesome features is Gstatus and Gdiff which allow you to watch your project’s status and diffs much like using git status & git diff from your terminal or favorite git interface.
There’s a very smooth way of dealing with these conflicts right inside VIM; using Gdiff when editing a conflicted file, fugitive would launch a three-way diff by surrounding your current workspace file. Two new buffers would appear: one for the target branch (i.e. the one you’re merging *into*), and the other would be the merge branch (i.e. the branch that is being merged to).
Validation of the previous concept: If I’m working on master, and I’d like to merge staging into it, I’d run git merge staging.
In this case master being the target branch, and staging is the mergebranch.
This terminology is important for later reference to be clear on which buffer we’ll be choosing for the conflict resolution.
Here’s an excellent video by Drew Niel describing the above (practical VIM): http://vimcasts.org/episodes/fugitive-vim-resolving-merge-conflicts-with-vimdiff/
The method above goes through working with inconvenient buffer system and hard to follow commands like diffput or diffget which made little sense to me when I tried figuring out buffer name reference. The flow wasn’t smooth and I felt something was missing.
To solve my problem, I used a few aliases integrated into my .vimrc so that resolving conflicts became enjoyable, smooth and most importantly — intuitive; I don’t want to think about what I’m doing, I want to do it. Plus, I want it to be better and faster than any other tool I’ve seen doing the same, by removing the complexity and unintuitive processes in the way.
Let’s review the additions I made to my .vimrc and how they become useful when solving conflicts:
" Fugitive Conflict Resolution
nnoremap <leader>gd :Gvdiff<CR>
nnoremap gdh :diffget //2<CR>
nnoremap gdl :diffget //3<CR>
The three lines above are all it takes to resolve a conflict with ease;
Start by typing <leader>gd as in git diff, which creates a three-way split screen described above. In my mapping, I use Gvdiff to split the panes vertically. If your preference is a horizontal view leave the v out: Gdiff.
Here’s what it looks like:
Note how the center pane is my current workspace, the left side is HEAD and how my code will look like should I choose that option, while the right side is describing master branch state.
In order to decide on my changes in HEAD, according to my mapping, I type gdh, the gd stand for git diff and the h being VIM’s left key. I intentionally left the leader key out of this sequence as it is an inner process combination.
After choosing master my current workspace changes to:
Note that the actual command in the bottom left corner mentions
:diffget //2 which is fugitive’s way of getting the changes from the buffer with //2 in its name.
Useful additions to make this process whole:
That’s all it takes.
Getting used to this sequence is a breeze, making conflicts life much easier (and fun) to work through.