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:
- Create an initial commit on main:
echo "base" > file.txt && git add file.txt && git commit -m "Base commit"
- Create
feature-Aand add two commits:git checkout -b feature-Aecho "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"
- Create
feature-Boff offeature-Aand add two commits:git checkout -b feature-Becho "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"
- Check the log to see the full chain:
git log --oneline --all --graph
- Now transplant
feature-Bontomain, removing the dependency onfeature-A:git rebase --onto main feature-A feature-B
- Verify the result:
git log --oneline --all --graphfeature-Bcommits now sit directly on top ofmainls— you should seefile.txtandb.txt, but nota.txt
Key Points
git rebase --ontogives 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 --graphafter rebasing