Gitgit rebase --onto

git rebase --onto

git rebase --onto is the scalpel version of rebase. Where normal git rebase target says “take all my commits onto target”, --onto lets you say “take this specific range of commits and put them on top of that branch”. It is invaluable for surgical history rewrites and for moving commits between branches that share no obvious base.

The syntax

The general form

Bash
git rebase --onto <new-base> <old-base> [<branch>]
# Replays commits in the range (old-base..branch] onto new-base
# If <branch> is omitted, the current branch is used
Why this exists

Imagine you branched off the wrong branch. Or you have a feature branched off another feature branched off main, and the parent feature got merged. You need to move just some commits to a new base — without dragging along everything underneath.

Example 1: Moving a sub-branch

Setup

Text
        A───B───C        ◀── main
                 \
                  D───E         ◀── feature-x
                       \
                        F───G   ◀── feature-y (built on top of feature-x)

feature-x got merged into main. You now want feature-y to be based on main directly (since feature-x no longer exists on its own line):

Move feature-y from feature-x to main

Bash
git switch feature-y
git rebase --onto main feature-x

# This says: take commits in (feature-x..feature-y], which is F and G,
# and replay them onto main.

Result

Text
        A───B───C───F'───G'   ◀── feature-y
                 \
                  D───E              ◀── (old feature-x, now orphaned)
Example 2: Skip a commit

Imagine your branch has commits A, B, C, D, and you want to keep A, C, D but drop B. You could use interactive rebase — or you can use --onto:

Bash
# Replay (B..HEAD] onto A — skipping B
git rebase --onto A B
# Branch is now A → C' → D'
Example 3: Move commits to a different branch

Move recent work from feature-a to feature-b

Bash
# I made the last 3 commits on the wrong branch.
git switch feature-a
git log -3 --oneline
# 1f9ab2c Wrong branch, oops
# d4b1e0c Also wrong branch
# c204c1d And another

git switch feature-b
git rebase --onto feature-b HEAD~3 feature-a
# Replays the last 3 commits of feature-a onto feature-b
Visualising the three arguments

git rebase --onto NEW OLD [BRANCH]

Text

NEW = where the commits should END UP
OLD = the commit JUST BEFORE the range you want to move
BRANCH = which branch to operate on (defaults to current)

Range moved: (OLD ... BRANCH-tip]   ← OLD is EXCLUSIVE, tip INCLUSIVE
The classic “feature on top of feature” case

Before

Text
        A───B───C   ◀── main
                 \
                  D───E   ◀── feature-x
                       \
                        F   ◀── feature-y

feature-x is merged into main. You want to ditch the D and E from feature-y’s history and put F directly on main:

Bash
git switch feature-y
git rebase --onto main feature-x
# Replays (feature-x..feature-y], which is F only,
# onto main.

After

Text
        A───B───C───F'   ◀── feature-y
                 \
                  D───E         ◀── (old feature-x, orphaned)
When to reach for --onto
  • You branched off the wrong base and want to fix it without redoing the work.

  • A parent feature branch was squashed or rebased and you need to follow.

  • You want to extract a contiguous range of commits and move them to a different branch.

  • You want to drop one or more “lead-in” commits and rebase the rest.

Conflict and abort handling

Conflicts work the same as any rebase: resolve, git add, then git rebase --continue. To bail out: git rebase --abort.

The trick to remembering it
A useful sentence
“Replay commits **after** OLD, **onto** NEW.”
OLD is the line in the sand. Everything past it goes onto NEW.
Verifying before you do it

See exactly which commits will be replayed

Bash
git log <old>..<branch> --oneline
# These are the commits that will be rebased onto NEW
Tip
--onto is the rebase form you’ll use once a month, but it saves the day every time. When normal git rebase would drag along commits you don’t want, reach for --onto.