1.2 Git Basics: Merge and Rebase
In this lesson, I’ll show you how to integrate source code changes from one branch to another using either
git merge or
git rebase. There are some subtle differences between them—for instance, merging preserves the branch history, while rebasing doesn’t. Follow along and I’ll explain when to use one or the other.
The following snippet will rebase the contents of the branch
branch to master, without adding an extra commit message for the merge.
git checkout branch git rebase master git checkout master git merge branch
1.2 Git Basics: Merge and Rebase
Integrating changes from one branch into another can happen either through a merge, or a rebase. A merge preserves the branch history, a rebase doesn't. A merge is useful for combining branches that are already public. A rebase is for combining private branches, never for public ones. What should be communicated clearly to beginners is the simple fact that both merging and rebasing are about integrating new work, new commits that are on separate branches, that's it. In all of this, there will always be at least two branches in play. Merging is probably most commonly used to integrate changes into other branches. This is the easiest approach. It is also called a three way merge. This involves the latest snapshots on each branch and their common ancestor, where the branch is split off. It takes the endpoints and merges them into a new commit. This merge commit is comprised of the information from the three commits it is based upon, it has more than one parent. This is the exact thing that a rebase lets you avoid. Merging creates a new commit object, rebase doesn't. Merging works like this, you check out the branch that should be the target of your merge. Most of the time, this is master. After that, you merge the desired changes from the feature branch into this checkout target branch. You sort of pull them in. Since a merge creates a new snapshot, a new commit, head automatically moves forward and takes its position. The position of the topic branch, the pointer to its latest commit, does not change. A rebase allows it to rewrite history. Many people prefer this approach in order to have a cleaner timeline of commits. Merging can be seen as polluting the history of a project because an additional merge commit is created in the process. Rebase is pretending that the work on the feature branch was directly done on the base branch you rebase onto. It takes all the commits from a particular feature branch and places them onto the base branch, not only the last commit. Git rewinds the changes from the feature branch and moves back to its common ancestry point. From there, it moves forward to the position of head in the base branch. Git reapplies the commits, one at a time, from the feature branch on top of it. No additional commit gets created, but the existing commits that you want to move get recreated. Just like these commits have always been there. You can observe that by the simple fact that their hashes will change. Since the history now involves another timeline, the hashes need to be recalculated. It works like this. You check that the feature branch has the changes you want to rebase. Then you do a rebase onto your targeted base branch, which is often simply master. After that, you check out the base branch that was the target of your new commits. What is left to do is merge in these changes. This will result in a fast forward merge. What is a fast forward merge? It means that the branch that accepted the rebased commits needs to catch up with the position of the feature branch, because these commits get placed on top of it. It basically only moves head to the newest commit, the tip of the spear, so to speak. A place where the newest commit from the other feature branch was placed. Compared to a merge, you saved one commit in the process, but in both cases the latest commits represent the same snapshot. The only difference is a cleaner timeline, a cleaner history of commits. That way your timeline tells a story, if you will. One that is not interrupted by merge commit noise. The resulting history looks like it was all done in a linear fashion, while in reality the work was created in parallel.