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...
Unlike a merge, which merges two branches in one go, rebasing applies the changes from one branch one by one.
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.
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.
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.
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With