This blogpost investigates the advantages of --rebase-merges option in rebase command. This option is introduced in git 2.18.

TL;DR:

Use git rebase -r if you want to preserve the merge commits.

Git has two different methods to sync branches: rebase and merge. Rebase offers a cleaner way to maintain the repository, while merge offers a one-click solution. Rebase is powerful, but it comes with a price.

One problem I face with rebase is, it removes merge commits. Suppose we have a common feature branch shared by multiple developers, we are merging commits to this branch first, and to keep atomic commits properly we are using no-fast-forward merge commits. After merging multiple branches to this branch, we merge this big branch to master. What happens when we need to sync this branch with master? The good way is to use rebase, but once we rebase this branch onto master, all merge commits are gone. Following GIF shows how such a rebase operation omits all merge commits:

The new option --rebase-merges prevents this problem. With this option, the rebase command successfully includes all merge commits. Following screenshot shows the interactive rebase screen with --rebase-merges option:

The rebase operation itself combines resets, labels, merges to preserve the same structure. The tool itself rewinds before each merge tree, picks commits, then creates a merge commit. The very same steps can be done manually to achieve the same result. The whole operation is summarized below:

The comparison between the two states is obvious:

Another problem I face with rebase is, when we have a feature branch and we had to merge master into this feature branch somehow, we cannot rebase the feature branch onto master anymore. This --rebase-merges option also solves this problem as well.

Merge strategy

In 2.18, rebase-merges had only one merge strategy: recursive. Starting from v2.24, --rebase-merges supports the option of --strategy as well.

Final words

The cases I stated here do not employ best practices, in fact, they can be considered as anti-patterns. I am a huge fan of a clean repository & git history. However, as developers, we face these problems in our daily life and this new option eases dealing with it.