The purpose of this article is to discuss the differences between 2 main Git operations: merge and rebase.
Each one is best for specific purposes, so learn when to use them efficiently, and why.
The common belief that Git Merge and Git Rebase serve the same purpose, since both “get commits from one branch to another branch” is, in fact, incorrect. They serve different purposes and should not be used interchangeably.
Before discussing when and why, we’ll first cover the specifics for each one. If you’re already familiarized with the concepts, feel free to jump directly to #4 below.
The common base represents the point where the feature branch diverged or “branched out” from the master branch. From there, the feature branch evolves separately with its own commits (the green circles) until it’s merged back into the master branch via a merge commit. At this point, the merge commit represents every change that has occurred on feature, since it branched-off from master. In this process, only the master branch is changed. The feature branch history remains the same.
The commands for achieving this are very simple:
git checkout feature git merge master
Merging has the advantage of being a non-destructive operation. The existing branches are not changed in any way. This avoids all of the potential pitfalls of rebasing (discussed below).
But this also means the feature branch will have an extraneous merge commit every time there’s a need to incorporate upstream changes. If master has a lot of activity, it can pollute the feature branch’s history. While it’s possible to mitigate this issue with advanced git-log options, it can make it hard for others to understand the history of the project.
3. Rebase and Cherry-Pick
As the picture above shows, the rebase commit stacks the new commits on top of the different commit, eliminating the unwanted history. Git accomplishes this by creating new commits and applying them to the master branch. It’s very important to understand that even though the branch looks the same, it’s composed of entirely new commits. This happened by rewriting the commits in the original branch into those new commits.
Rebase executes with these commands:
git checkout feature git rebase master
As the diagram above shows, the rebase generated a perfectly linear project history—so it’s easy to follow the tip of a feature all the way to the beginning of the project, without any ramifications.
Cherry-pick essentially pulls changes from a different branch into the current branch. Those changes can be from one commit or from a range of commits. Say I want to cherry-pick commit e9ec47ee952f4b3d726624efc0dbdc636c93c218 from a different branch into my feature branch. The command will be:
git checkout feature git cherry-pick e9ec47ee952f4b3d726624efc0dbdc636c93c218
With cherry-pick, the original commits/branch sticks around, and new commits are created.
With rebase, the whole branch is moved with the branch pointing to the replayed commits.
4. When to use them
In general, git users want a clean and usable history. To achieve this, the tools described above are typically used: merge, rebase, cherry-pick.
a. When to Merge
i. The best-case scenario for using merge is when a whole feature set from one branch needs to be incorporated into another one—typically the master branch. By doing this, the whole history is preserved correctly into the history graph, providing a lot of value to the development team.
ii. Besides features, other good candidates for merge are branches incorporating tasks or bug fixes. In this case, having the history preserved correctly helps teams understand all the steps in the product development.
b. When to Rebase
i. When the feature branch started from an obsolete branch
In this case, every time you try to push there’s going to be an error, since the remote branch is stale due to the updates of other collaborators. This could be mitigated with a merge, but that would create unnecessary merge commits in the history graph, and by doing so, increased noise in the graph. Being just timing issues in the collaboration on the same branch, the rebase would solve this noise problem much more elegantly.
ii. When starting a parallel unit of work—such as a future feature—an experiment or a spike
Say the work has gone stale on such a branch and later you’re catching up with the work on it. At that point, before resuming work, you’d like to have a more recent version of the base branch incorporated into your working branch. Merge won’t be advised, since it would introduce too much noise generated by the merge commits, so rebase is the clean way to go.
iii. When need to clean some commits in the branch
This case happens a lot in real life, especially in situations that take several commits to finalize a bug or a task, when there are several unrelated changes in the same commit, or when some commits were reverted. All these scenarios create a lot of noise and it would be not so nice to push all that to a remote branch, so rebase is the way to go here as well.
iv. When only certain features or fixes need to go into a release branch.
This is another real-life example. Say the main development branch contains more features and/or fixes approved to go into a certain release branch. This is a typical scenario when cherry-picking gets in handy. You need to pick and choose the commits that need to go into that specific release branch. Submitting the PRs that needed to go into the release branch via a rebase would have eliminated the clutter generated by a merge and offered better visibility into the commits that need to be cherry-picked.
More information on Git merge, rebase and cherry-pick—as well as Git in general—can be found here:
Lastly, if you’d like help with any aspect of Git, please don’t hesitate to reach out to us. We’d love to help you get started.