Conceptual Overview

The first thing to understand about git rebase is that it solves the same problem as git merge. Both of these commands are designed to integrate changes from one branch into another branch – they just do it in very different ways.

Consider what happens when you start working on a new feature in a dedicated branch, then another team member updates the master branch with new commits. The results in a forked history which should be familiar to anyone who has used Git as a collaboration tool.

Now, let’s say that the new commits in master are relevant to the feature that you’re working on. To incorporate the new commits into your feature branch, you have two options: merginor rebasing.

The Merge Option

The easiest option is to merge the master branch into the feature branch using something like the following:

1
2
git checkout feature
git merge master

Or you can condense this to a one-liner:

1
git merge master feature

This creates a new merge commit in the feature branch that ties together the histories of the both branches, giving you a branch structure that looks like this:

Merging is nice because it’s a non-destructive operation. The existing branches are not changed in any way. This avoids all of the potential pitfalls of rebasing.

On the other hand, this also means that the feature branch will have an extraneous merge commit every time you need to incorporate upstream changes. If master is very active, this can pollute your feature branch history quite a bit. While it’s possible to migrate this issue with advanced git log options, it can make it hard to other developers to understand the history of the project.

The Rebase Option

As an alternative to merge, you can rebase the feature branch onto master branch using the following commands:

1
2
git checkout feature
git rebase master

This moves the entire feature branch to begin on the top of the master branch, effectively incorporating all of the new commits in master. But, instead of using a merge commit, rebasing re-writes the project history by creating brand new commits for each commit in the original branch.

The major benefit of rebasing is that you get a much cleaner project history. First, it eliminates the unnecessary merge commits required by git merge. Second, as you can see in the above diagram, rebasing also results in a perfectly linear project history – you can follow the top of feature all the way to the beginning of the project without any forks. This makes it easier to navigate your project with commands like git log.

Interactive Rebasing

Interactive rebasing gives you the opportunity to alter commits as they are moved to the new branch. This is even more powerful than an automated rebase, since it offers complete control over the branch’s commit history. Typically, this is used to clean up a messy history before merging a feature branch into master.

To begin an interactive rebasing session, pass the -i option to the git rebase command.

1
2
git checkout feature
git rebase -i master

This will open a text editor listing all of the commits that are about to be moved:

1
2
3
pick 33d5b7a Message for commit #1
pick 9480b3d Message for commit #2
pick 5c67e61 Message for commit #3

This listing defines exactly what the branch will look like after the rebase is performed. By changing the pick command and/or reordering the entries, you can make the branch’s history look like whatever you want.

For example, if the 2nd commit fixes a small problem in the 1st commit, you can condense them into a single comit with the fixup command:

1
2
3
pick 33d5b7a Message for commit #1
fixup 9480b3d Message for commit #2
pick 5c67e61 Message for commit #3

When you save and close the file, Git will perform the rebase according to your instructions, resulting in project history that looks like the following:

Eliminating insignificant commits like this makes your feature’s history much easier to understand. This is something that git merge simply cannot do.

The Golden Rule of Rebasing

The Golden Rule of git rebase is to never use it on public branches.

For example, think about what would happen if you rebased master onto your feature branch.

The rebase moves all of the commits in master onto the tip of feature. The problem is that only happened in your repo. All of the other developers are still working with the origin master. Since rebasing results in brand new commits, Git will think that your master branch’s history has diverged from everybody else’s.

The only way to synchronize the two master branches is to merge them back together, resulting in an extra merge commit and two sets of commits that contain the same changes.