When is it recommended to use Git rebase vs. Git merge?
Do I still need to merge after a successful rebase?
Git rebase is used to make the branching paths in history cleaner and repository structure linear.
It is also used to keep the branches created by you private, as after rebasing and pushing the changes to the server, if you delete your branch, there will be no evidence of branch you have worked on. So your branch is now your local concern.
After doing rebase we also get rid of an extra commit which we used to see if we do a normal merge.
And yes, one still needs to do merge after a successful rebase as the rebase command just puts your work on top of the branch you mentioned during rebase, say master, and makes the first commit of your branch as a direct descendant of the master branch. This means we can now do a fast forward merge to bring changes from this branch to the master branch.
This sentence gets it:
In general, the way to get the best of both worlds is to rebase local changes you’ve made, but haven’t shared yet, before you push them in order to clean up your story, but never rebase anything you’ve pushed somewhere.
Source: 3.6 Git Branching - Rebasing, Rebase vs. Merge
So when do you use either one?
The Pro Git book has a really good explanation on the rebasing page.
Basically a merge will take two commits and combine them.
A rebase will go to the common ancestor on the two and incrementally apply the changes on top of each other. This makes for a 'cleaner' and more linear history.
But when you rebase, you abandon previous commits and create new ones. So you should never rebase a repository that is public. The other people working on the repository will hate you.
For that reason alone I almost exclusively merge. 99% of the time my branches don’t differ that much, so if there are conflicts it's only in one or two places.
It's simple. With rebase you say to use another branch as the new base for your work.
If you have, for example, a branch master
, you create a branch to implement a new feature, and say you name it cool-feature
, of course the master branch is the base for your new feature.
Now at a certain point you want to add the new feature you implemented in the master
branch. You could just switch to master
and merge the cool-feature
branch:
$ git checkout master
$ git merge cool-feature
But this way a new dummy commit is added. If you want to avoid spaghetti-history you can rebase:
$ git checkout cool-feature
$ git rebase master
And then merge it in master
:
$ git checkout master
$ git merge cool-feature
This time, since the topic branch has the same commits of master plus the commits with the new feature, the merge will be just a fast-forward.
TLDR: It depends on what is most important - a tidy history or a true representation of the sequence of development
If a tidy history is the most important, then you would rebase first and then merge your changes, so it is clear exactly what the new code is. If you have already pushed your branch, don't rebase unless you can deal with the consequences.
If true representation of sequence is the most important, you would merge without rebasing.
Merge means: Create a single new commit that merges my changes into the destination. Note: This new commit will have two parents - the latest commit from your string of commits and the latest commit of the other branch you're merging.
Rebase means: Create a whole new series of commits, using my current set of commits as hints. In other words, calculate what my changes would have looked like if I had started making them from the point I'm rebasing on to. After the rebase, therefore, you might need to re-test your changes and during the rebase, you would possibly have a few conflicts.
Given this, why would you rebase? Just to keep the development history clear. Let's say you're working on feature X and when you're done, you merge your changes in. The destination will now have a single commit that would say something along the lines of "Added feature X". Now, instead of merging, if you rebased and then merged, the destination development history would contain all the individual commits in a single logical progression. This makes reviewing changes later on much easier. Imagine how hard you'd find it to review the development history if 50 developers were merging various features all the time.
That said, if you have already pushed the branch you're working on upstream, you should not rebase, but merge instead. For branches that have not been pushed upstream, rebase, test and merge.
Another time you might want to rebase is when you want to get rid of commits from your branch before pushing upstream. For example: Commits that introduce some debugging code early on and other commits further on that clean that code up. The only way to do this is by performing an interactive rebase: git rebase -i <branch/commit/tag>
UPDATE: You also want to use rebase when you're using Git to interface to a version control system that doesn't support non-linear history (Subversion for example). When using the git-svn bridge, it is very important that the changes you merge back into Subversion are a sequential list of changes on top of the most recent changes in trunk. There are only two ways to do that: (1) Manually re-create the changes and (2) Using the rebase command, which is a lot faster.
UPDATE 2: One additional way to think of a rebase is that it enables a sort of mapping from your development style to the style accepted in the repository you're committing to. Let's say you like to commit in small, tiny chunks. You have one commit to fix a typo, one commit to get rid of unused code and so on. By the time you've finished what you need to do, you have a long series of commits. Now let's say the repository you're committing to encourages large commits, so for the work you're doing, one would expect one or maybe two commits. How do you take your string of commits and compress them to what is expected? You would use an interactive rebase and squash your tiny commits into fewer larger chunks. The same is true if the reverse was needed - if your style was a few large commits, but the repository demanded long strings of small commits. You would use a rebase to do that as well. If you had merged instead, you have now grafted your commit style onto the main repository. If there are a lot of developers, you can imagine how hard it would be to follow a history with several different commit styles after some time.
UPDATE 3: Does one still need to merge after a successful rebase?
Yes, you do. The reason is that a rebase essentially involves a "shifting" of commits. As I've said above, these commits are calculated, but if you had 14 commits from the point of branching, then assuming nothing goes wrong with your rebase, you will be 14 commits ahead (of the point you're rebasing onto) after the rebase is done. You had a branch before a rebase. You will have a branch of the same length after. You still need to merge before you publish your changes. In other words, rebase as many times as you want (again, only if you have not pushed your changes upstream). Merge only after you rebase.