Course contents

Rebase a feature branch onto main

Sign in to run this lab and save your progress

Learn

Every merge you've done so far ended with a merge commit and a diamond shape in the graph. There's another way to combine work from two branches that produces a straight line instead. It's called rebase, and it's one of the most powerful (and most misused) commands in Git.

What rebase actually does

Say you're on feature, which has one commit on top of a common ancestor with main. Meanwhile main has its own new commit. You have a diverged shape.

Instead of merging, you can rebase:

git rebase main

Git does this:

  1. Sets aside your feature commits temporarily.
  2. Fast-forwards feature to point at main's tip.
  3. Re-applies your feature commits, one at a time, on top of that.

The result is a straight line: main's commits followed by your feature's commits, no diamond, no merge commit. It looks like you did all your feature work AFTER main had already been updated.

The commits are new commits

The re-applied commits have the same author, message, and file changes as the originals. But they have different parent commits, and therefore different SHA hashes. Git treats them as brand new commits.

The original commits still exist in Git's storage for a while (recoverable via git reflog), but they become unreachable and will be garbage-collected eventually. As far as your branch is concerned, the old commits are gone and new ones have taken their place.

This is why rebase is sometimes described as "rewriting history". It literally is.

Merge vs rebase: pick your style

Both merge and rebase get feature's work onto main. They produce different histories:

  • Merge preserves the fact that development happened in parallel. The graph forks and rejoins. Merge commits act as markers.
  • Rebase hides the parallelism. The graph is a straight line. Every commit looks like it built on the one before it, in order.

Neither is objectively better. Some teams love merge because it records the actual history of who worked on what and when. Some teams love rebase because the log is cleaner and easier to read. Most teams pick one style and stick to it. Some do both: git pull --rebase to keep your local branch clean, git merge when landing features.

The one rule you cannot break

Never rebase commits that other people have based work on.

Because rebase creates new commits, anyone who had a copy of the old commits now has stale ones. Their work is anchored to commits that no longer exist on your branch. When they try to pull, Git gets confused, they get confused, and someone spends an afternoon untangling it.

Safe places to rebase:

  • Your own local feature branch, before you push it anywhere.
  • A remote branch that only you have touched.

Unsafe places to rebase:

  • Any branch other people have pulled from and built on.
  • main, develop, or any long-lived shared branch. Ever.

If you follow that one rule, rebase is a great tool. If you break it, you'll learn why the rule exists the hard way.

What if there are conflicts?

Rebase re-applies your commits one at a time. If any of them conflicts with what's now on main, Git pauses, hands you the conflicted file, and waits for you to resolve. Same conflict markers as a merge. Once you've fixed the file:

git add <file>
git rebase --continue

Git moves on to the next commit in the sequence. If you want to bail out completely:

git rebase --abort

Puts everything back the way it was before you started.

Your task

Same starting point as the merge lesson: main and feature have each moved, and you're on feature. Instead of merging — which creates a merge commit with two parents — you want a linear history. Rebase feature so that its commit sits on top of main's latest commit. After this, git log feature should be a straight line: Initial → Main work → Feature work. The graph panel should show one column, no Y-shape.