github email
Prefer the other branch when merging
Apr 19, 2017
2 minutes read

Sometimes it’s useful to always prefer the contents of another branch when merging. Endymion keeps its Python 2 and Python 3 code in separate branches, and new features are usually implemented in master and then merged to the python3 branch. Due to the changes in the standard library, merging often causes merge conflicts that I have to solve manually.

On two occasions, the automatic conflict resolution produced unexpected results: it chose the correct lines, but with the wrong indentation level (which is bad in Python, where indentation determines the logical structure of the code). When this happens, I’ve found it easier to start with the complete Python 2 version of the code in master, use 2to3 to convert it, fix the remaining problems and then commit in the python3 branch. git offers the “ours” merge strategy, which will always take the contents of the current branch over the one from the branch being merged. At least since git 1.8, there’s no “theirs” merge strategy. Fortunately, it’s possible to do this ourselves by using git reset.

First, change to the destination branch and perform a merge whose result we will overwrite later:

git checkout python3
git merge -s ours master

We can now create a temporary branch to point to the merge commit (we could also use the revlog to find the merge commit again, but having a branch pointing to it is much simpler):

git branch temp_branch

A hard reset will set HEAD, the index and the working directory to the version in master. We can then set HEAD back to where it should be, in the python3 branch, thorough a soft reset, which will leave the index and working tree populated with the files from master:

git reset --hard master
git reset --soft temp_branch

We can now run 2to3 to convert the code to Python 3 and manually fix any Python 2 left-overs (mostly interface changes not handled by 2to3, like urllib2’s get_type method being replaced by a type property in urllib.request). When everything is working, overwrite the original merge commit and delete the temporary branch:

git commit --amend
git branch -D temp_branch

It is actually pretty simple once you understand how git reset works (for in-depth explanations, please see “Git Tools – Reset Demystified” in the Pro Git book).

Back to posts