Rebase only part of a branch
I've got two branches (and master). Branch 2 is based on Branch 1 is based on master. I've submitted Branch 1 for review, it had some changes, I rebased some of those changes into history and merged the result into master.
Now I need to rebase Branch 2 on top of master to prepare it for review/merge.
The problem is that Branch 2 still contains the original commits of Branch 1, which don't exist anymore, so git gets confused. I tried rebase -i to drop the original commits of Branch 1, but the commits of Branch 2 don't base on top of master-before-branch-1.
What I need to do is take branch 2, drop some commits, and rebase just the remaining commits on top of master in a single operation. But I only know how to do these two operations in two distinct steps.
How can I rebase part of my branch onto another branch, dropping all commits that are not in common ancestry, except the ones I specify (e.g. from HEAD~2 up)?
Here's the current state:
master new branch 1
- - - - - - - - - - - | - - - - - - - - -
\
\ branch 1
\ _ _ _ _ _ _ _
\
\ branch 2
\ _ _ _ _ _ _ _
What I want to end up with:
master new branch 1
- - - - - - - | - - - - - - - - - -
\
\
\
\ branch 2
- - - - - - - - -
Solution 1:
The actual command would be:
git rebase --onto newbranch1 branch1 branch2
That will replay on top of new_branch1
all commits after branch1
up to branch2
HEAD.
As Joshua Goldberg puts it in the comments:
git rebase --onto <place-to-put-it> <last-change-that-should-NOT-move> <change to move>
As Denis Sivtsov illustrates in the comments:
If you need only replay the last commit only from branch, in this case work:
git rebase --onto newbranch1 HEAD~1
Solution 2:
The solution is considerably simpler than I expected. It turns out that you can supply -i
to a much larger variety of rebase commands (I thought it was only for rebasing a branch to itself for changing history). So I simply ran git rebase -i master
and dropped those extra commits.
Solution 3:
git rebase --onto master HEAD~2
-
master
- the branch you're rebasing onto -
2
- the last n commits from the current branch you need rebased
Source
Solution 4:
I find your ASCII graph a bit ambiguous, as branches don't really represent a range of commits - a branch points to a specific commit. I take it you mean something like
H (new-branch-1)
G
| F (HEAD -> branch-2)
| E
| D (branch-1)
| C
|/
B (master)
A
in which case the goal, and result of VonC's answer git rebase --onto new-branch-1 branch-1 branch-2
, is
F' (HEAD -> branch-2)
E'
H (new-branch-1)
G
| D (branch-1)
| C
|/
B (master)
A
But your answer git rebase -i master
doesn't make sense. Surely you would mean git rebase -i new-branch-1
and in the editor write
drop C
drop D
pick E
pick F
which would achieve the goal above.
(Your answer would result in):
F' (HEAD -> branch-2)
E'
| H (new-branch-1)
| G
|/
| D (branch-1)
| C
|/
B (master)
A
Solution 5:
As answered, you can do this using --onto
.
I find the git rebase --onto
syntax quite confusing. So I created this script for rebasing "nested" branches: Github Gist
In your example, you would call:
moveBranch newBranch2 from newBranch1 to master
#!/bin/bash
## Places a branch to a new base.
## Useful when splitting a long branch to multiple pull requests.
##
## ---+--------master
## \
## --- A ---- B
##
## git-moveBranch.sh B from A to master
##
## ---+-------- master ---- B
## \
## --- A
function printUsageAndExit() {
echo "Usage: moveBranch <branch> from <previous-base> to <new-base>";
exit 1;
}
if [ 5 != $# ] ; then printUsageAndExit; fi
if [ "$2" != "from" ] ; then printUsageAndExit; fi
if [ "$4" != "to" ] ; then printUsageAndExit; fi
WHAT="$1"
FROM="$3"
ONTO="$5"
echo "Running: git rebase —-onto=\"$ONTO\" \"$FROM\" \"$WHAT\""
# git rebase —-onto <place-to-put-it> <last-change-that-should-NOT-move> <change to move>
git rebase --onto "$ONTO" "$FROM" "$WHAT"