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
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
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
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
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:
# 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
# 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]
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
A───B───C ◀── main
\
D───E ◀── feature-x
\
F ◀── feature-yfeature-x is merged into main. You want to ditch the D and E from feature-y’s history and put F directly on main:
git switch feature-y git rebase --onto main feature-x # Replays (feature-x..feature-y], which is F only, # onto main.
After
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
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
git log <old>..<branch> --oneline # These are the commits that will be rebased onto NEW
--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.