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:
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 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 <firstname.lastname@example.org> 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.
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 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:
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.
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.