📝
This post is part of my “Shorts” series, where each post is concise and hyper-focused on a single concept.

If you have worked with Git, you must have come across merge commits. These commits are not created every time you merge, but only on some special scenarios. In this post, we will learn about merge commits and when are they created. At the end of the post, I will also provide a way to avoid them.

First, the simple fast-forward merge

Consider that you have a branch named featureX which diverges from the main branch as shown below.

If you try to merge featureX into main using git merge featureX, you will see the text Fast-forward in the merge output. Git uses this merge strategy when the commit pointed to by the branch that is being merged into - main in this case - is a direct ancestor of the branch that is being merged - featureX in this case.

In other words, if you start following the parent starting from the commit pointed to by featureX and you reach the commit pointed to by main after some jumps, Git will simply move (fast-forward) the main branch pointer to the commit pointed to by featureX.

⚠️
I have used the main branch as an example. I don’t mean to convey that merges can only happen into the main branch. Any Git branch can be merged into any Git branch.

When the main branch is NOT an ancestor of your feature branch

Consider the scenario below where the main branch has moved ahead from the point where featureX diverged.

In this case, the commit pointed to by main is not an ancestor of the featureX branch. So, Git tries to find the common ancestor of the main and featureX. Then, Git performs a three-way merge between the common ancestor commit, the commit pointed to by main, and the commit pointed to by featureX. It creates a new snapshot that results from this merge and creates a “merge commit” on the main branch (or the branch being merged into).

📝
A merge commit has more than one parent.

Avoiding merge commits

To avoid “merge commits”, you can rebase the featureX branch on the main branch. After the rebase, the commit pointed to by main will become an ancestor of featureX. To learn more about rebasing, I suggest you read my post introducing git-rebase.

References