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".