Git merge and rebase – the simple explanation
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.