Git Rebase

Written by
Published
Updated
Typical Read
8 minutes
Find your next web developer job
Drupal Web Developer at On Fire Media (San Antonio, TX)

The git rebase command has a reputation for being magical Git voodoo that beginners should stay away from. That's far from the truth & in this article I'll show you how it can actually make life much easier by making your git history tidy.

Git Rebase is not nearly as complicated as it sounds — or as confusing as the documentation or other explanations make it out to be. It’s a powerful tool that’ll make your git history easier to follow.

Git Rebase

What is Git Rebasing?

git rebase is the process of moving or combining a sequence of commits to a new base commit. Rebasing changes the base of your branch from one commit to another making it appear as if you’d created your branch from a different commit.

Git accomplishes this by creating new commits and applying them to the specified base. It’s very important to understand that even though the branch looks the same, it’s composed of entirely new commits.

Git Rebasing vs. Merging

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

  • When you do rebase a feature branch onto master, you move the base of the feature branch to master branch’s ending point.
  • Merging takes the contents of the feature branch and integrates it with the master branch. As a result, only the master branch is changed. The feature branch history remains same.
  • Merging adds a new commit to your history.

There’s also a special kind of merge called fast-forward, done when a branch being merged is just a continuation of the branch you’re merging into—so the new commits are just pasted on top of the target branch (ie. it is “fast-forwarded”).

Let’s say you start working on a new feature in a dedicated branch, then another developer updates the master branch with new commits resulting in a forked history.

Git forked commit history
A forked commit history.

The new commits in master are needed to the feature you’re working on so needs to be incorporated into your feature branch — there’s two options, merge or rebase.

Option 1 — Merge the Branch

The simplest option would be to merge the master branch into the feature branch using git merge:

git checkout feature
git merge master

or as a one-liner:

git merge feature master

This will create a new “merge commit” in the feature branch that ties the histories of both branches which looks like this:

Git merge commit
* Merge commit

This option is non-destructive, the existing branches are not changed in any way which avoids all the potential pitfalls of rebasing (see below).

Option 2 — Rebase the Branch

The other option is to rebase the feature branch onto the master branch:

git checkout feature
git rebase master

This operation moves the entire feature branch to begin on the tip of the master branch which incorporates all new commits in master. Instead of merging, git rebasing re-writes the project history by creating brand new commits for each commit in the original branch.

Brand new git commit
* Brand new commit

Benefits to Rebasing — two trade-offs.

  • Streamlines a potentially complex history
  • Avoids merge commit “noise” in busy repos with busy branches
  • Cleans intermediate commits by making them a single commit

The major benefit to git rebasing is a much cleaner project history. It eliminates unnecessary merge commits required by git merge and results in a perfectly linear project history — shown in the diagram above. You’ll be able to follow the top of feature all the way to the beginning of the project with git log, git bisect and gitk.

The two-trade offs are safety & traceability. If you don’t follow the golden rule of rebasing, never use it on public branches, re-writing project history can be catastrophic for collaboration. Rebasing loses the context provided by a merge commit so unable to see when upstream changes were incorporated into the feature.

How to Git Rebase

git rebase [base]

The Git command above will rebase the current branch onto [base], which can be any kind of commit reference (an ID, a branch name, a tag, or a relative reference to HEAD). When ran, Git performs the following steps:

  1. Identifies each commit that is an ancestor of the current commit but not of [base]. This can be thought of as a two-step process: first, find the common ancestor of [base] and the current commit; call this the ancestor commit. Second, collect all the commits between the ancestor commit and the current commit.
  2. Determines what changed for each of those commits, and puts those changes aside.
  3. Sets the current head to point to [base].
  4. For each of the changes set aside, replays that change onto the current head and creates a new commit.

Once completed, HEAD (the current commit), is a descendant of [base], but it contains all the changes as if it had been merged with [base].

Git Rebase — behind the scenes.

Let’s take 2 branches for example:

  • Branch you: the branch you are rebasing
  • Branch johnny: the branch from which you get the new commits

Johnny made some commits and you want to pull those into your branch while keeping the commits and history clean. To do so:

git checkout you
git rebase johnny
Git Rebase

When you rebase you on johnny, git creates a temporary branch that is a copy of branch johnny, and tries to apply the new commits of you on it one by one.

For each commit to apply, if there are conflicts, they will be resolved inside of the commit.

After a rebase, the new commits from you (in blue) are not exactly the same as they were:

  • If there were conflicts, those conflicts are integrated in each commit
  • They have a new hash

But they keep their original date which might be confusing since in the final branch, commits in blue were created before the two last commits in purple.

Git Rebase Golden Rule

Never rebase while you’re on a public branch — only rebase a branch if you are the only one using it.

Rebase has the advantage that there is no merge commit created, but HEAD is not a descendant of the pre-rebase HEAD commit which means rebasing can be problematic.

This means that a rebased head cannot be pushed to a remote server, because it does not result in a fast-forward merge. Moreover, it results in a loss of information. It is no longer known that the branch your rebasing was once on its current HEAD. This changes history and could confuse someone who already knows about the commit.

When should you rebase vs. merge?

  • Use merge in cases where you want a set of commits to be clearly grouped together in history
  • Use rebase when you want to keep a linear commit history
  • Don’t use rebase on a public/shared branch

If the feature branch you are getting changes from is shared with other developers, rebasing is not recommended, because the rebasing process will create inconsistent repositories. For individuals, rebasing makes a lot of sense.

If you want to see the history completely same as it happened, you should use merge. Merge preserves history whereas rebase rewrites it.

Rebasing is better to streamline a complex history, you are able to change the commit history by interactive rebase. You can remove undesired commits, squash two or more commits into one or edit the commit message.

Rebase will present conflicts one commit at a time whereas merge will present them all at once. It is better and much easier to handle the conflicts but you shouldn’t forget that reverting a rebase is much more difficult than reverting a merge if there are many conflicts.

Here’s some examples of when you should use git rebase:

Situation 1: You’re using a private branch.

By public branches are branches that other people might have checked out. If you’re developing a branch on your own and not sharing it with anyone, you could rebase it to keep the branch up to date with respect to the main branch. Then, when you finally merge your developed branch into the main branch, it will be free of merge commits, because it will appear that your development branch was a descendant of the main head. Moreover, the main branch can move forward with a fast-forward merge rather than a regular merge commit.

Rebasing rewrites history, and anyone having branches that were checked out of the history you just unmade will be sad, angry or worse. That’s one reason you can’t just push rebased branch on GitHub (unless you force it and sacrifice a kitten). So just say no.

Rebasing private branches is perfectly fine, and in fact often done when squashing or rearranging commits, cleaning up a branch before going public with it, or just updating long-running feature branch (go easy on the last one, though).

Situation 2: A remote branch changes at the same time.

If you commit to a branch, but that branch changes at the same time on a remote machine, you can use rebase to shift your own commits, allowing you to push your commits to the remote repository.

Git Rebasing Examples

The example below combines git rebase with git merge to maintain a linear project history. This is a quick and easy way to ensure that your merges will be fast-forwarded.

# Start a new feature
git checkout -b new-feature master
# Edit files
git commit -a -m "Start developing a feature"

In the middle of our feature, we realize there’s a security hole in our project:

# Create a hotfix branch based off of master
git checkout -b hotfix master
# Edit files
git commit -a -m "Fix security hole"
# Merge back into master
git checkout master
git merge hotfix
git branch -d hotfix

After merging the hotfix into master, we have a forked project history. Instead of a plain git merge, we’ll integrate the feature branch with a rebase to maintain a linear history:

git checkout new-feature
git rebase master

This moves new-feature to the tip of master, which lets us do a standard fast-forward merge from master:

git checkout master
git merge new-feature

Did you find Git Rebase useful? Get articles in your inbox.

…and don’t worry, I hate spam as much as you. Expect to hear from me at most once a week.

Share on facebook
Share on twitter
Share on linkedin
Share on reddit
Share on facebook

Stay updated.

Get a weekly email with the latest trends in web development & SEO.

Write a guest post.

Have an interesting article or idea? Become a guest blogger & pitch me your concept today.

2 comments on “Git Rebase”.

Lukas

# Oct 22, 2019

Rule One: Never Rebase Public Branches
It means that you shouldn’t do this rebase command while beeing on master branch.

Putra

# Aug 18, 2017

Can you please give example with step by step picture regarding Rule One: Never Rebase Public Branches, I don’t get it.

Maybe in real example of Centralized Workflow for 2/3 Developer.

Join the conversation.

Your email address will not be published. Required fields are marked *

All comments posted on 'Git Rebase' are held for moderation and only published when on topic and not rude. Get a gold star if you actually read & follow these rules.

You may write comments in Markdown. This is the best way to post any code, inline like `<div>this</div>` or multiline blocks within triple backtick fences (```) with double new lines before and after.

Want to tell me something privately, like pointing out a typo or stuff like that? Contact Me.