Git rebase and children branches
Solution 1:
You are correct: running git rebase Master
while on Beta
will not affect Feature
. (Aside: why the uppercase letters?)
The fundamental issue here is that git rebase
"means" copy some commits. The trick is seeing which commits get copied, to where, and what happens to the branch names afterward. If the commits that were copied, are also reachable from some other branch, the originals—before copying—remain reachable from that other branch.
Remember that all branch names are merely pointers, pointing to the most recent commit on the branch. All earlier parent commits are on that branch, even if those earlier commits are also on other branches too. So "all Beta
commits" includes M1
through M3
initially.
So, how does the first git rebase
know to copy only B1
, B2
, B3
, and B4
? I think one key item is to draw the graph a bit differently:
M1----M2----M3----M4----M5 <-- Master
\
B1----B2----B3---B4 <-- Beta
\
F1---F2---F3 <-- Feature
To see what will get copied, take a green highlighter to the tip commit of the branch, i.e., B4
as pointed-to by Beta
, and color all commits green as you follow the lines towards the left. That includes commits M3
and earlier. Then, take a red highlighter to the tip commit of Master
(that's M5), and color all commits red as you follow the lines to the left. The red over-paints the green, so that M3
and earlier are not considered for copying. This leaves exactly the right set of commits to copy.
The copies themselves land after the tip commit of the argument. That's Master
, so the copies come after M5
.
After Git does the copying, Git moves the name Beta
to point to the copy of B4
, which we will call B4'
. That leaves the original Bn
commits dangling ... except that B3
is reachable from F1
:
B1'---B2'---B3'--B4' <-- Beta
/
M1----M2----M3----M4----M5 <-- Master
\
B1----B2----B3---B4 [no name]
\
F1---F2---F3 <-- Feature
So that's all fine for Beta
, but now you would like to copy Feature
's commits. If you:
git checkout Feature
git rebase Beta
Git will color F3
green, then F2
and F1
... but then go on to mark B3
back through B1
green as well. Only the copies B1'
, B2'
, B3'
, B4'
, and the five M
commits, get colored or overwritten with red. So Git will copy too many commits.
The solution is to use git rebase --onto <name>
. Adding --onto
tells Git where to put the copies: you want them to go after B4'
, so you can say --onto Beta
to say that the copies go after Beta, i.e., B4'
.
That doesn't actually fix anything ... yet. But it frees up the other argument, the one that was Beta
, to be, well, something else.
What you want is to tell Git where to start marking commits red. That's B3
, or if it's easier, B4
. That will mark B3
and all its earlier commits (including M3
and earlier too) red: do not copy.
You can use the raw ID of B3
, if you save it. Or you can easily have Git look up the previous tip of Beta
using Beta@{1}
:
git rebase --onto Beta Beta@{1}
This finds the hash ID of commit B4
using the reflog for Beta
.
Solution 2:
Actually it would end up with something like this:
Master M1----M2----M3----M4----M5
\ \
\ Beta B1----B2----B3---B4
\
\--B1'---B2'---B3'----F1---F2---F3
^
feature
Basically, your rebase for Beta
will reapply the commits on Beta on top of the current tip of master. However, the original commits will still exist and if anything else, such as another branch, are referring to those commits, they will still persist.
You would need to first rebase Beta
and then rebase feature
in order to move everything "into the correct place".