Break big merges to smaller pieces 2020.04.22

Merges with many conflicts are horrifying.

As the chance for a conflict resolution mistake increases, we can't run the tests to verify correctness until all of the conflicts are resolved.

Often, however, we can break the merge process down to smaller pieces, where we can check and save our work after each step!

Git merge

The simplest way to break a merge down is to apply "sub-merges" which merge a single commit at a time.

Git merge with sub-merges

Each sub-merge involves less conflicts and we can run our test-suite to verify ourselves.

A down-side of this simple approach is that it may be tedious to do manually and it will result in a very complicated git history tree.

One way to resolve the history issue is to rewrite it, which one can do with git rebase.

If we rebase rather than merge, the following script makes the process easy by automating it:


while true
    # Find next commit to rebase to
    COMMON_ANCESTOR=$(git merge-base HEAD $BASE)
    for COMMIT in $(git rev-list ..$BASE --reverse)
        if [ $(git merge-base HEAD $COMMIT) == $COMMON_ANCESTOR ]
            # Rebasing on this commit will strictly progress towards our goal
        # The commit is not strictly ahead of BASE
        echo Skipping $COMMIT as it is not strictly ahead of $BASE

    [ "$NEXT_COMMIT" == "" ] && echo "Done" && exit
    echo Rebasing over $NEXT_COMMIT
    git rebase $NEXT_COMMIT || exit 1

It rebases up to the first parent of the base branch which has any merge conflicts to address (so it doesn't accumulate conflicts from multiple commits).

Apply it to advance towards your complete merge in smaller, testable pieces.

Update: I learned about the git-imerge tool which aims to do exactly what I suggest here. I will give it a try and will update this post subsequently!