Rebase — One of the Most Powerful Git Commands

Robert Cooper
Osedea
7 min readMay 1, 2018

--

W hen a programmer is first learning git the typical commands that are picked up include add, commit, push, pull, status, branch, checkout and merge. After those foundational commands are learned, I think that the rebase command should be understood.

Rebasing is often used as an alternative to merging. Rebasing a branch updates one branch with another by applying the commits of one branch on top of the commits of another branch. For example, if working on a feature branch that is out of date with a dev branch, rebasing the feature branch onto dev will allow all the new commits from dev to be included in feature. Here’s what this looks like visually:

A feature branch prior to being rebased onto dev
A feature branch after being rebased onto dev

For the above example, this is what it would look like from the command line:

git rebase feature dev

However, it is more common to first checkout a branch and then run the rebase command with the name of the branch you wish to rebase on to:

git checkout feature
git rebase dev

Typical Rebase Use Cases

Updating a Feature Branch

Lets say you’re working away on a feature branch, minding your own business.

Look at all those commits you’ve been adding to your feature branch. Good job!

Then you notice some new commits on dev that you’d like to have in your feature branch, since the new commits may affect how you implement the feature.

Oh man, your feature branch is now out of date with dev.

You decide to run git rebase dev from your feature branch to get up-to-date with dev.

However when you run the rebase command, there are some conflicts between the changes you made on feature and the new commits on dev. Thankfully, the rebase process goes through each commit one at a time and so as soon as it notices a conflict on a commit, git will provide a message in the terminal outlining what files need to be resolved. Once you’ve resolved the conflict, you git add your changes to the commit and run git rebase --continue to continue the rebase process. If there are no more conflicts, you will have successfully rebased your feature branch onto dev.

Now you can continue working on your feature with the latest commits from dev included in feature and all is well again in the world. This process can repeat itself if the dev branch is updated with additional commits.

Updating a Feature Branch Prior to Merge

Another popular use for rebasing is to rebase a feature branch, just prior to merging into a dev branch. Let’s say that the current state of a feature and dev branch is as follows:

Initial state of a feature and dev branch

Once thefeature is complete, it should be merged into the dev branch. First, thefeature branch should be updated with dev using git rebase dev.

State of a feature and dev branch after a rebase and just prior to a merge

Next, merge feature into dev. This is usually done through a Pull Request, so others can review the work done in the feature branch. Once this is done, the result is as follows:

The result of merging the feature branch into dev immediately after a rebase

Notice how all the commits from the feature branch are added to the end of the dev branch. This will always be the case if rebasing is immediately done prior to merging. The reason this happens is that rebasing rewrites the git history and so the timestamp of the commits on the rebased branch will all be the moment at which the rebase command was run. To be clear, rewriting history with rebase recreates commits that contain the same changes and commit message, but with a new hash and timestamp. Therefore, when merging a recently rebased feature branch into dev, all the feature branch commits will be added at the end of dev since merging orders commits in chronological order.

Github actually has an option on Pull Requests to rebase a branch prior to merging.

Github’s allows to rebase and merge branches through their Pull Request interface

Renaming & Consolidating Commits in Feature Branches

Odds are, when nearing the completion of a feature in a feature branch, the commit history could be improved upon by renaming some commits to something more appropriate, combining closely related commits, and/or reordering commits in a more logical order. Rebasing allows for all of this!

Since rebasing rewrites the git history, it provides some tools to specify exactly how to rewrite the history. The best way to take advantage of these extra rebase features is by running rebase in interactive mode by passing the -i flag with the command (i.e. git rebase -i feature dev).

When running an interactive rebase, a list of commits that will be rebased along with the word pick at the beginning of each commit message is presented in the default git editor configured on your machine (in my case it’s Visual Studio Code). The word pick can be changed with any of the following options (all of which are listed when running an interactive rebase):

pick = use commit
reword = use commit, but edit the commit message
edit = use commit, but stop for amending
squash = use commit, but meld into previous commit
fixup = like "squash", but discard this commit's log message
exec = run command (the rest of the line) using shell
drop = remove commit

For the examples mentioned earlier here’s how you would tackle them:

  • A commit message can be reworded using the reword option for a commit.
  • Combining commits is done with the squash or fixup option on a commit that should be combined with another commit. Ensure that the commit specified with squash/fixup immediately follows the commit with which it should be combined.
  • Reordering commits is as simple as moving around the commit messages in the desired order.

What’s So Great About Rebasing?

No Merge Commits

Merging two branches together always requires a merge commit. If a feature branch is continually being updated with a dev branch using a merge, there will be several merge commits resulting in a less clear git history.

Here is a feature branch out of date with a dev branch
Updating the feature branch with dev using a merge results in a merge commit
Here, there are additional new commits to dev after the first merge has occured on the feature branch
A second merge between feature and dev is performed to update the feature branch. Now, there are 2 merge commits on the feature branch.

These merge commits can be completely mitigated if rebase is used to update the feature branch instead of a merge.

Linear & Sequential Git History

When rebasing a branch prior to a merge, all the the feature branch commits are grouped together at the end of the dev branch whereas the feature branch commits are interspersed in the dev branch when a rebase is not used prior to merge. This is because merging orders commits chronologically. Grouping feature commits together, as is the case with a rebase, makes it simple to understand/analyze the git history afterwards.

The result of merging a feature branch into dev without rebasing prior to merging. Notice how the feature commits are scattered among the dev commits. The red commit is the merge commit.
The results of rebasing prior to merging a feature branch into dev. Notice how all the feature commits follow the dev commits. The red commit is the merge commit.

Simpler Time Resolving Conflicts

When rebasing, git applies each commit one at a time and so conflicts can be resolved progressively. When resolving conflicts for a merge, all conflicts must be resolved at once which can make it a bit more difficult to handle.

If a conflict is encountered while rebasing, git will indicate which files are conflicting and need to be modified. After changes have been made, the changes need to be staged to the commit and then the rebase can resume using git rebase --continue. There is also the option of running git rebase --abort while resolving conflicts in a rebase, which will cancel the rebase and leave the branch unchanged.

Well Organized and Clean Git History

With all the benefits above in addition to the ability to change commit messages, combine commits, and reorder commits, rebasing makes for a very clean git history that is easy to understand. Having an understandable git history is great when trying to pinpoint when a certain feature or bug was introduced in your codebase.

When Not To Rebase

Ok, rebasing is pretty sweet, but there are certainly cases where you should not rebase. The golden rule of rebasing is to not rebase public branches. The reason you shouldn’t rebase a public branch is that you are rewriting the git history for that branch and this will result in your version of the public branch to differ from the version other users are working with. This will result in a bunch of conflicts and can be a tedious problem to resolve once it’s done, so make sure to only rebase branches you, and only you, are working on.

Adding git rebase to your git workflow can be an extremely valuable way of cleaning up your git history and making the overall git workflow easier to work with. The way rebase works may not be completely intuitive at first, but after using the command a few times on feature branches to better familiarize yourself with it, you’ll hopefully end up seeing some of the benefits mentioned in this article.

Related Git Rebase Resources & Readings

Git Rebase Documentation

Merging vs. Rebasing — Bitbucket

Git Time Travel Magic — Gant Laborde

--

--