Resolving Git Merge Conflicts
Merge conflicts are no stranger to anyone that uses some form of version control. Git does a great job at auto-merging conflicts, but there are many instances when Git cannot determine what must be done automatically and a manual merge is required. Though this can be a pain at times, Git provides many useful tools to help with more difficult merges. Specifically options like ours
and theirs
allow us to tell Git what strategy to use when handling merge conflicts so we do not have to merge them manually.
Let's assume we have a branch, branch1
, that has diverged from our master branch. Since branch1
split from the master branch both branch1
and master
have both made changes to the same line of the same file. This means that there will be merge conflicts that Git cannot resolve for us.
Resolving conflicts in the middle of a rebase
If we are trying to rebase our branch with the new changes in master we might do something like the following.
git checkout branch1
git rebase master
git diff
# ++<<<<<<< HEAD
# + Master change
# ++=======
# + Branch1 change
# ++>>>>>>> Branch1 branch
Notice the output of git diff
. There might be many conflicts within the file, I am just showing one for brevity. Since this is a rebase, the HEAD
is the branch we are rebasing with (master
). If I want to take all of the changes for a file from branch1
, the current branch, I can run git checkout --theirs filename
, rather than dealing with it manually. Likewise, if I want to accept all the changes from master
, the branch with which I am rebasing, I can use git checkout --ours filename
.
It is important to note that the meaning of ours
and theirs
is reversed from its normal meaning when being used for a rebase. This is because rebasing replays the current branch's commits one at a time on top of the branch we want to rebase with. In our case, branch1
's commits are being replayed on top of master
. This makes master
the "base" branch in this case, which is the reason that ours
will take the changes from master
instead of branch1
.
Resolving conflicts in the middle of a merge
As noted above, the semantics of ours
and theirs
change when being used in a rebase. If we are trying to resolve conflicts in the middle of a merge, we can use ours
to accept changes from the branch we are currently on and theirs
to accept changes from the branch we are merging in.
Let's assume that we are trying to perform a merge as follows.
git checkout master
git merge branch1
git diff
# ++<<<<<<< HEAD
# + Master change
# ++=======
# + Branch1 change
# ++>>>>>>> Branch1 branch
This time, the HEAD
is our current branch, master
. If we want to accept all the changes for a particular file from our current branch we can use git checkout --ours filename
. Otherwise, I can accept all the changes from the branch I am merging in using git checkout --theirs filename
.
Choosing a merge strategy beforehand
You may have noticed that resolving merge conflicts with ours
and theirs
in the middle of a rebase or merge is the same, except that the semantics of what ours
and theirs
refer to are different. Both use a flag on git checkout
to choose what must be done per file. This is very useful if you were not planning on having merge conflicts and they pop up in the middle of a rebase/merge or if you want to use a different strategy depending on the file. This means for one file you could use ours
, another theirs
, and another could be done manually.
In instances that you know that you always want to resolve merge conflicts in the same way, you can choose a merge strategy (such as ours
or theirs
) before performing the rebase or merge. The default merge strategy is a recursive merge. You can also specify the algorithm to use for a recursive merge (patience, minimal, histogram, or myers), but we will not cover those in this post.
You can choose the merge strategy with the --strategy <strategy-name>
option, or -s <strategy-name>
for short.
For example:
##########
# REBASING
##########
# a rebase that wants to resolve all conflicts
# by taking the current branch's changes
git rebase -s theirs rebase_branch
# a rebase that wants to resolve all conflicts
# with the rebase_branch changes
git rebase -s ours rebase_branch
#########
# MERGING
#########
# a merge that wants to resolve all conflicts
# by taking the current branch's changes
git merge -s ours merge_branch
# a merge that wants to resolve all conflicts
# with the merge_branch changes
git merge -s theirs merge_branch
Now you should be able to add the ours
and theirs
options to your Git merge resolution arsenal. Whenever you find yourself taking all of the changes from a single branch, that should be your queue to use ours
or theirs
. And don't forget that the meaning of ours
and theirs
changes within a rebase.