Tour of Git
History & Undoing Changes / Lesson 3.10

git rebase --onto — Advanced Rebasing

Sometimes a regular git rebase is not enough. When you need to transplant a branch to a completely different base, or remove a range of commits from the middle of a branch, git rebase --onto gives you precise control over where commits are replayed.

The Three-Argument Form

git rebase --onto <newbase> <upstream> <branch>

This means: take commits from <branch> that are not in <upstream>, and replay them onto <newbase>.

  • newbase — where you want the commits to land
  • upstream — the starting point (exclusive) of the commits you want to move
  • branch — the branch whose tip contains the commits you want to move

Use Case 1: Moving a Branch Based on the Wrong Branch

Suppose you accidentally created feature-B off of feature-A instead of main:

Before:
A — B — C                  (main)
         \
          D — E             (feature-A)
               \
                F — G       (feature-B)

You want feature-B (commits F and G) to be based on main instead of feature-A:

git rebase --onto main feature-A feature-B
After:
A — B — C                  (main)
        |\
        | D — E             (feature-A)
         \
          F' — G'           (feature-B)

Commits F' and G' are replayed directly onto main, as if feature-A never existed in the chain.

Use Case 2: Removing a Range of Commits

Suppose you have a branch with some commits in the middle that you want to drop:

Before:
A — B — C — D — E — F      (feature)
        ^           ^
        |           |
     keep these    keep this
     (but remove C, D)

You want to remove commits C and D, keeping only B, E, and F:

git rebase --onto B D feature

This says: take commits after D on feature (that is E and F), and replay them onto B:

After:
A — B — E' — F'            (feature)

Two-Argument Form

You can also use --onto with just two arguments. Git will assume the current branch:

git checkout feature-B
git rebase --onto main feature-A

This is equivalent to:

git rebase --onto main feature-A feature-B

Try it!

Practice transplanting a branch with git rebase --onto:

  1. Create an initial commit on main:
    • echo "base" > file.txt && git add file.txt && git commit -m "Base commit"
  2. Create feature-A and add two commits:
    • git checkout -b feature-A
    • echo "feature-A work" > a.txt && git add a.txt && git commit -m "feature-A: first"
    • echo "more A work" >> a.txt && git add a.txt && git commit -m "feature-A: second"
  3. Create feature-B off of feature-A and add two commits:
    • git checkout -b feature-B
    • echo "feature-B work" > b.txt && git add b.txt && git commit -m "feature-B: first"
    • echo "more B work" >> b.txt && git add b.txt && git commit -m "feature-B: second"
  4. Check the log to see the full chain:
    • git log --oneline --all --graph
  5. Now transplant feature-B onto main, removing the dependency on feature-A:
    • git rebase --onto main feature-A feature-B
  6. Verify the result:
    • git log --oneline --all --graph
    • feature-B commits now sit directly on top of main
    • ls — you should see file.txt and b.txt, but not a.txt

Key Points

  • git rebase --onto gives you precise control over which commits are replayed and where
  • The three-argument form is: git rebase --onto <newbase> <upstream> <branch>
  • Use it to transplant a branch to a different base or to remove a range of commits
  • Like regular rebase, it rewrites history — never use it on shared/public branches
  • Always check the result with git log --oneline --all --graph after rebasing
🎯

Goal

Use git rebase --onto to transplant a branch onto a different base

Terminal
$

No commits yet. Run `git init` and create your first commit.