Git Rebase

Replay your commits on top of another branch with rebase, compare it with merge, tidy commits with interactive rebase and follow the golden rule.

Lesson 13 of 30Advanced17 min read

When you work on a feature branch for a few days, main usually moves on without you. To bring those new commits into your branch, you've learned to merge, which joins the two histories with a merge commit. Git offers a second way to combine work: rebase.

Rebasing takes the commits on your branch and replays them, one by one, on top of the latest main, as if you'd started your work from there. The result is a straight, linear history with no merge commits, which many teams find easier to read and review.

Rebase is powerful, and it rewrites history, which brings one very important rule. In this lesson you'll rebase a branch, compare the result with merging, resolve conflicts during a rebase, use git pull --rebase, tidy your commits with interactive rebase, and learn the golden rule that keeps teammates safe.

What rebase does

Imagine main has commits A, B and C, and your branch feature started at B and added commits X and Y. Meanwhile, C was added to main.

Terminal
git switch feature
git rebase main

Git sets X and Y aside, moves feature to the tip of main (C), then re-applies X and Y on top. The re-applied commits have the same changes and messages but new hashes, because their parent changed. Afterwards, feature contains A, B, C, X', Y' in a straight line, and merging it into main is a simple fast-forward.

Rebase or merge?

MergeRebase
HistoryShows exactly what happened, including when branches joinedA clean, straight line
Extra commitsA merge commitNone
Rewrites commitsNoYes, gives commits new hashes
Safe on shared branchesYesNo, only on your own local or private branches

Both are correct tools. A common team habit is: rebase your own feature branch onto main to stay up to date, then merge it into main through a pull request.

Conflicts during a rebase

Because commits are replayed one at a time, a conflict pauses the rebase at the commit that caused it:

  1. Open the conflicted files, fix them and remove the markers, just as in the merge lesson.
  2. git add the fixed files.
  3. git rebase --continue to move on to the next commit.

git rebase --skip drops the current commit, and git rebase --abort cancels everything and returns your branch to how it was before the rebase. You can always abort if things get confusing.

Interactive rebase

git rebase -i HEAD~3 opens a list of your last three commits in your editor, oldest first, each with a command word:

Text
pick a1b2c3d Add search box
pick d4e5f6a Fix typo
pick 9f8e7d6 Fix another typo

Change the words to rewrite history before sharing it:

  • pick: keep the commit as it is.
  • reword: keep it but change its message.
  • squash or fixup: combine it into the commit above (squash keeps both messages, fixup discards this one's).
  • drop: remove the commit entirely.

Save and close, and Git rebuilds the commits as instructed. It's the standard way to turn a messy series of "WIP" commits into a few clean ones before opening a pull request.

Git Rebase Syntax

Rebase commands

git switch feature
git rebase main
git rebase --continue
git rebase --abort
git pull --rebase
git rebase -i HEAD~3
git push --force-with-lease     # after rebasing your own pushed branch

Git Rebase Summary

  • git rebase main replays your branch's commits on top of main, giving them new hashes.
  • Rebase gives a linear history; merge preserves the exact history with merge commits.
  • Resolve rebase conflicts, git add, then git rebase --continue; --abort cancels.
  • git rebase -i lets you reword, squash, fixup and drop commits.
  • Only rebase commits that haven't been shared with others.

Git Rebase Examples

Each example shows the code, the output it produces and what each part does.

Example 1

Updating a feature branch with rebase

Terminal
git log --oneline --graph --all
git switch search-box
git rebase main
git log --oneline --graph --all
Output
* 7e1c0d2 (main) Fix footer link
| * 4b9a8c3 (HEAD -> search-box) Style search box
| * 2d6f1e4 Add search box
|/
* 9d41e07 Add contact form
Successfully rebased and updated refs/heads/search-box.
* 8a3b2f7 (HEAD -> search-box) Style search box
* 5c1e9d0 Add search box
* 7e1c0d2 (main) Fix footer link
* 9d41e07 Add contact form
Line-by-line explanation
  1. Line 1Before: main gained "Fix footer link" after search-box branched off.
  2. Line 3Replay the two search-box commits on top of main.
  3. Line 4After: one straight line. The commits have new hashes because their parent changed.
Example 2

Pulling with rebase instead of merge

Terminal
git status
git pull --rebase
git log --oneline -3
Output
On branch main
Your branch and 'origin/main' have diverged,
and have 1 and 1 different commits each, respectively.
Successfully rebased and updated refs/heads/main.
c3d9e8f (HEAD -> main) Add FAQ section
b38e0f5 (origin/main) Update README with screenshots
9d41e07 Add contact form
Line-by-line explanation
  1. Line 1Your main and the remote main each have a commit the other doesn't.
  2. Line 2Instead of creating a merge commit, your local commit is replayed on top of the remote one.
  3. Line 3The history stays linear, and your commit is now ready to push normally.
Example 3

Squashing commits before a pull request

The editor opened by git rebase -i HEAD~3 was changed to this, then saved.

Text
pick 2d6f1e4 Add search box
fixup 6a7b8c9 Fix typo in placeholder
fixup 3e4f5a6 Fix typo again
Output
Successfully rebased and updated refs/heads/search-box.

$ git log --oneline -1
1f2e3d4 (HEAD -> search-box) Add search box
Line-by-line explanation
  1. Line 1Keep the main commit.
  2. Lines 2 to 3fixup folds both typo fixes into it and discards their messages.

Common Git Rebase Mistakes

Rebasing a shared branch

Don't
git switch main
git rebase feature
git push --force        # rewrites main for everyone
Do
git switch main
git merge feature
git push

Forgetting to continue after fixing a conflict

Don't
# conflict fixed and files saved...
git commit -m "Fix conflict"     # creates an extra commit mid-rebase
Do
git add styles.css
git rebase --continue

Using --force instead of --force-with-lease

Don't
git push --force
Do
git push --force-with-lease

After rebasing your own pushed branch, --force-with-lease refuses to overwrite commits someone else added.

Git Rebase in Real Projects

Rebase in professional teams

Many teams ask contributors to rebase their pull requests on the latest main and squash fix-up commits before review, which keeps history readable. Large open-source projects such as the Linux kernel rely heavily on rebasing patch series, and GitHub's "Rebase and merge" button applies the same idea when merging a pull request.

Git Rebase FAQ

How do I undo a rebase after it has finished?

Git saves your branch's previous position in ORIG_HEAD, so git reset --hard ORIG_HEAD straight after the rebase puts it back. If you've run other commands since, find the entry from before the rebase in git reflog and reset to that instead. Commit or stash any uncommitted work first, because --hard discards it.

How do I squash my last three commits into one?

Run git rebase -i HEAD~3, keep pick on the first line and change the other two to squash (or fixup to drop their messages). Save, edit the combined message, and you have one commit. A quick alternative is git reset --soft HEAD~3 followed by git commit.

What does git pull --rebase do?

It fetches from the remote and then rebases your local commits on top of what it downloaded, instead of creating a merge commit. Your history stays a straight line. You can make it the default with git config --global pull.rebase true.

What does git rebase --onto do?

It moves a range of commits onto a different base. git rebase --onto main old-base feature takes the commits on feature that come after old-base and replays them on top of main. It's useful when you branched from another feature branch and now want your work based on main alone.

What is a fixup commit?

git commit --fixup=3f9c2ab makes a commit whose message starts with fixup! and names the commit it corrects. Later, git rebase -i --autosquash main moves it next to that commit and merges them automatically. It's a tidy way to fix an earlier commit on your branch before opening a pull request.

Git Rebase Exercises

Answer each one and check it instantly. If you get stuck, open the hint before the answer.

Fill in the blankseasy

Complete the commands that replay your feature branch onto main.

git switch feature
git  main
Multiple choiceeasy

What happens to the hashes of rebased commits?

Multiple choicemedium

After fixing a conflict during a rebase, what do you run?

Predict the outputmedium

In an interactive rebase, a commit is marked fixup. What happens to it?

Multiple choicehard

What does the golden rule of rebasing say?

Git Rebase Quiz

5 questions to check what you learned.

  1. What does rebasing produce compared with merging?

    • More merge commits
    • A deleted branch
    • A linear history without merge commits
    • A new remote
  2. How do you cancel a rebase that's going badly?

    • git rebase --stop
    • git rebase --abort
    • git reset --rebase
    • Delete the .git folder
  3. What does git pull --rebase do?

    • Fetches, then replays your local commits on top of the remote branch
    • Merges the remote with a merge commit
    • Rebases the remote onto your branch
    • Deletes local commits
  4. Which interactive rebase command changes only a commit's message?

    • pick
    • drop
    • squash
    • reword
  5. Why push with --force-with-lease after rebasing your own branch?

    • It's faster than a normal push
    • Normal push is disabled after a rebase
    • The remote has your old commits, and --force-with-lease only overwrites them if nobody else has pushed since
    • It creates a backup branch