Git merge: the different types

You know what a merge does conceptually and how to merge in Git. What you may not know are the different types of merges. That’s what this piece is about.

License

This post is a slightly modified version of the Git merge section in Pro Git, which I would highly recommend reading. The Git merge section in Pro Git is licensed under the Creative Commons Attribution Non Commercial Share Alike 3.0 license, as is this post.

Fast-forward merge

Figure 1. Linear history

There are a few commits already and your HEAD pointer is currently at commit c2. Say you now decide to create a new branch:

$ git checkout -b feature-x
Switched to a new branch 'feature-x'

This is what our workflow looks like now:

Figure 2. New branch, feature-x

After adding a LICENSE file, the feature-x branch moves ahead of the master branch:

$ vim LICENSE
$ git commit -a -m "add license"
Figure 3. feature-x ahead of master

Let’s say you now get told that you need to fix an important bug that takes precedence over the new feature you’re working on. You decide to base this new branch off master:

$ git checkout master
Switched to branch 'master'

$ git checkout -b fix-login-bug
Switched to new branch 'fix-login-bug'
$ vim login.php
$ git commit -a -m "fixed whatever was wrong"
[fix-login-bug 1ga2879] fixed whatever was wrong
 1 file changed, 11 insertions(+)
Figure 4. New fix-login-bug branch made and now ahead of master

Now it’s time to merge fix-login-bug into master. To do this, you first need to switch to the branch that you want to merge into – master in this case.

$ git checkout master
$ git merge fix-login-bug
Updating k91n234..9bU9365c
Fast-forward
  login.php | 11++
  1 file changed, 11 insertions(++)

Notice where it says fast-forward. Since master was behind fix-login-bug (see figure 4: master was on commit c3 and fix-login-bug on commit c5), Git has to move the pointer forward.

Figure 5. Current workflow after the fast-forward merge

Fast-forward merge

After completing your work on the new feature, you’re now ready to merge it back in.

$ git add -a -m "add apple sign-in"
$ git checkout master
Switched to branch 'master'
$ git merge feature-x
Merge made by the 'recursive' strategy.
login.php | 44 +
1 file changed, 44 insertions(+)

Instead of fast-forward, it’s now saying that it merged it in using the recursive strategy. This is because the commit on the branch you’re on (feature-x) was not an ancestor of the branch we’re merging into (master). Git does a three-way merge using the tips of the branches (master and feature-x) and the last common ancestor.

Figure 6. Three snapshots.

From figure 6, you may now be able to see the three snapshots better. Git has made a new snapshot that is the result of the three-way merge, labelled as c6 in figure 6. This is known as the merge commit. It is unique in that it has more than one parent: c3 and c4.

Unlike older VCS systems like CVS or Subversion (pre v1.5), Git automatically finds the best common ancestor to use for the merge for us. In this regard, Git is a lot easier.

Featured image credit: Caleb Jones