Topic Solution
The correct command to answer the posted question could be any of the following (assuming branch topic
is already checked out):
git rebase --onto B master
git rebase --onto master~1 master
git rebase --onto B A
git rebase --onto B C
git rebase --onto B
If topic
is not checked out, you simply append topic
to the command (except the last one) like so:
git rebase --onto B master topic
Alternatively, check out the branch first with:
git checkout topic
Rebase Any String of Commits to a Target Commit
The basic form of the command we need, cribbed from the documentation, is:
git rebase --onto <Target> [<Upstream> [<Branch>]]
<Branch>
is optional and all it does is checks out the branch specified before executing the rest of the command. If you've already checked out the branch you want to rebase, then you don't need this. Note that you must have specified <Upstream>
in order to specify <Branch>
or git will think you are specifying <Upstream>
.
<Target>
is the commit we will attach our string of commits to. When providing a branch name, you are simply specifying the head commit of that branch. <Target>
can be any commit that won't be contained in the string of commits being moved. For example:
A --- B --- C --- D master
\
\-- X --- Y --- Z feature
To move the entire feature branch, you can not select X
, Y
, Z
, or feature
as the <Target>
since those all are commits inside the group being moved.
<Upstream>
is special because it can mean two different things. If it is a commit that is an ancestor of the checked out branch, then it serves as the cut point. In the example I provided, this would be anything that isn't C
, D
, or master
. All commits after <Upstream>
until the head of the checked out branch are the ones that will be moved.
However, if <Upstream>
is not an ancestor, then git backs up the chain from the specified commit until if finds a common ancestor with the checked out branch (and aborts if it can't find one). In our case, an <Upstream>
of B
, C
, D
, or master
will all result in commit B
serving as the cut point. <Upstream>
is itself an optional command and if it is not specified, then git looks at the parent of the checked out branch which is the equivalent of entering master
.
Now that git has selected the commits it will cut and move, it applies them in order to <Target>
, skipping any that are already applied to target.
Interesting Examples and Results
Using this starting point:
A --- B --- C --- D --- E master
\
\-- X --- Y --- Z feature
git rebase --onto D A feature
Will apply commits B
, C
, X
, Y
, Z
to commit D
and end up skipping B
and C
because they already have been applied.
git rebase --onto C X feature
Will apply commits Y
and Z
to commit C
, effectively deleting commit X