Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Git rebase and children branches

Tags:

git

branch

rebase

I have the following situation, on my project

Master M1----M2----M3----M4----M5
                     \
                 Beta B1----B2----B3---B4
                                   \
                          Feature   F1---F2---F3

I am developing in Feature, but a really important update was released on commit M5, and I don't want to detach Feature from B3 (Feature depends on B1 and B2), and Beta can have the change (no difference for Beta).

If I make a git rebase Master on Beta, it would only move the Beta branch, right (no changes applied on Feature)? Or it would end up like this (Below - changes also applied on Feature)?

Master M1----M2----M3----M4----M5
                                 \
                             Beta B1----B2----B3---B4
                                               \
                                      Feature   F1---F2---F3

And, to be like this (changes applied on Feature), what should I do? That is my desired state...

like image 737
Leonardo Alves Machado Avatar asked Jul 17 '17 21:07

Leonardo Alves Machado


People also ask

Does git rebase change both branches?

Unlike a merge, which merges two branches in one go, rebasing applies the changes from one branch one by one.

Should you rebase feature branches?

If the feature branch you are getting changes from is shared with other developers, rebasing is not recommended, because the rebasing process will create inconsistent repositories. For individuals, rebasing makes a lot of sense. If you want to see the history completely same as it happened, you should use merge.

What happens when I rebase a branch?

From a content perspective, rebasing is changing the base of your branch from one commit to another making it appear as if you'd created your branch from a different commit. Internally, Git accomplishes this by creating new commits and applying them to the specified base.

Does rebase create new branch?

The Rebase Option This moves the entire feature branch to begin on the tip of the main branch, effectively incorporating all of the new commits in main . But, instead of using a merge commit, rebasing re-writes the project history by creating brand new commits for each commit in the original branch.


1 Answers

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.

like image 158
torek Avatar answered Oct 25 '22 20:10

torek