Git merge and rebase have the same purpose – to converge multiple branches of development. Although the final goal is the same, those two methods get to it walking different paths.

Here is a sample repository that has two diverging branches: master and feature. Commit hashes will be represented with integers to help comprehension. They are also representing timestamps – smaller number means earlier commit.

      +--3--5   master
      |
1--2--+
      |
      +--4--6   feature

Merge

Merge is a new commit. That is very important thing to remember and one that is elusive to the newcomers. It is a simple commit with one difference – it has two parents. All other regular commits have only one. How do you check that? Fire up terminal and type git status. See that first two lines for merge?

commit 7777777777777777777777777777777777777777
Merge: 5555555 6666666
Author: Merlin <no.spam@for.me>
Date:   Thu Nov 3 10:11:27 2011 +0100

    Merge branch 'feature' into master.

Merge in ASCII art.

      +--3--5--+
      |        |
1--2--+        +--7
      |        |
      +--4--6--+

If you type git log on master branch, you’ll get a linear output: 7 6 5 4 3 2 1, sorted by date. But be mindful that is just eye-candy. The history is not linear under the hood. If you checkout at the commit 5, and type git log you’ll get: 5 3 2 1. Commit 4 is not a child of 5 or a parent of 3, so it’s not in the output.

Fast-forward merge

The only time a merge creates no new commits is the fast-forward merge. It happens in a situation when there are no commits in an another branch. Than it just updates the branch pointer to the last commit (number 4 in the graph).

Before

1--2--+         master
      |
      +--3--4   feature

After

1--2--3--4   master/feature

Rebase

Rebase is recreating your work of one branch onto another. For every commit that you have on the feature branch and not in master, new commit will be created on top of the master. Read this again, slowly: new commit for every old one, with the same changes.

When you checkout to feature branch and then rebase onto master, you will get this:

      +--3--5   master
      |
1--2--+
      |
      +--3--5--7--8   feature
              (4)(6)

Rebase has removed changes 4 and 6, synced with master changes 3 and 5, and then – remember the above statement – created new commits for old ones. It added commit 7 with the changes of commit 4 and commit 8 with the changes of commit 6. That way the feature branch has all changes from the master plus its own.

After you do fast-forward merge, you will have:

1--2--3--5--7--8   master/feature

git log will output: 8 7 5 3 2 1. And it’s important to notice that the history is linear under the hood too.

Conclusion

So, when to use merge and when rebase? As you may have guessed, the answer is “it depends”. And it depends mostly on the agreed workflow. But there are a few good guidelines.

Use rebase when:
● You have a need to merge local changes and don’t need an exact history. Why litter it with merge commits?
● You prefer a linear history and use git bisect very often (it can get confused with a non-linear history).

Use merge when:
● You have shared some of the changes with others and it’s important not to break their repositories. git rebase changes a lot of history so a normal merge is much safer and cleaner for others.
● You care about history and development tracks.

Picture credits

0 comments