How to rebase a branch off a rebased branch?
Solution 1
Short answer to How can I effectively rebase B off A so that it looks like B started from A? Assuming you want to move exactly one commit:
git rebase --onto A B~ B
If you want to move more then one commit use:
git rebase --onto A old_A B
The rest of the answer.
Your branch of B is still around (you can check it out), but its parent is still the exact commit object that A
was before.
to see a graphical representation of this I use:
git log --graph --decorate --all
to see all branches and where they are with respect to each other.
What you originally had:
o---o---o---o master
\
o---o---o A
\
o B
What you have now:
o---o---o-----------o master
\ \
o---o---o(B~) o---o---o A
\
o B
In terms of using --onto
, you need to have a starting point and an ending point.
use:
git rebase --onto [target] [rebasing stops] [rebasing head]
git rebase --onto A B~ B
And what you get:
o---o---o----------o master
\ \
o---o---o o---o---o A
(old_A) \
o B
[branch_name]~
indicates the parent commit of the branch.
The B~
is the branch that you do not want to change. (It happens to be the old A
)
Alternatively, if B was the only commit that had A as a parent, (i.e., B is the end of a chain of commits that branch off master) you could do
git checkout B
git rebase master
git checkout B~ # this is the commit before B (the A commit)
git branch -d A # remove the old A branch (it was rebased, and so is now invalid
git branch A # recreate the A branch on the commit that is based on the original A
Solution 2
I have the same issue of my git flow, and I found a best and fast way to do it.
(1) Project history in the beginning:
master ---A---B---C
\
D---E---F feature1
\
G---H feature2
(2) Rebase feature1 onto master and force pushed:
master ---A---B------------------------C
\ \
D---E---F feature1(old) D---E---F feature1
\
G---H feature2
(3) Rebase feature2 onto featrue1 (the new one)
master ---A---B------------------------C
\
D---E---F feature1
\
G---H feature2
The most confused part is how to do (3) .. but no one has a clear answer of doing it.
I believe many people encountered the same issue as I did, when we were trying to do "rebase --onto", we found that feature1(old) is actually not existing!
git rebase --onto feature1 feature1(old) feature2
Solution is to use below instead:
git rebase --onto feature1 feature1@{1} feature2
The syntax feature1@{1} means "the last known state of feature1 before the rebase", answer is refereed from https://coderwall.com/p/xzsr9g/rebasing-dependent-branches-with-git
Solution 3
If you have already re-based A. It should be the case that B is exactly where you left it. The branch (a pointer) that was A has simply moved to it's new location.
What I would recommend to effectively rebase B onto A is, as you suggested, to use 'cherry-pick'. This command attempts to apply the changes made in a commit to the branch on which you run it.
So if the commit IDs of the commit to which B originally pointed was '123456' then I would recommend moving your current 'B' to the same place as the new 'A' with git branch -f B A
then run git cherry-pick 123456
which will apply the changes onto A.
I believe the --onto
flag is used to set the target location from which to apply the commits.It defaults to "upstream" (source: http://git-scm.com/docs/git-rebase).
The way I like to think of the rebase command is as follows:
git rebase --onto <Starting here> <Apply all commits from HERE> <TO HERE>
Using this, it would probably have been simpler to rebase B onto master, then point A to the commit preceding B.
git rebase master B
(as the start point (--onto) is implicitly 'master')
then to use git branch -f A B^
(the ^ means 'the parent of')
Radu Murzea
I'm a backend PHP developer working for Pentalog, where I build awesome applications using the amazing Symfony framework. My current location is Cluj-Napoca (Romania), one of Eastern Europe's main IT outsourcing center. I thrive in challenging environments and am never afraid to get my hands dirty. My passions include software development, psychology and poker.
Updated on June 07, 2022Comments
-
Radu Murzea almost 2 years
So my history looks like this:
o---o---o---o master \ o---o---o A \ o B
So, to explain:
- I have branch
A
which was started frommaster
- I have branch
B
(with only 1 commit) which was started fromA
What I want is this:
o---o---o---o master \ o---o---o A \ o B
What I did was:
1).
git checkout A git rebase master
This resulted in a lot of conflicts which, after some significant time spent fixing, the following history emerged:
o---o---o---o master \ o---o---o A
Which is exactly what I wanted.
(I don't know where
B
is right now)
2).
After this I did a lot of squashes and changed the order of commits on
A
, to make the history look like I want.
3).
Now, what I also want to do is:
git checkout B git rebase A
However this doesn't seem to work and I don't know why. If I do
git log
I see the commits which were there before I did step 1.Also, I get the same huge number of conflicts which I already solved at step 1. I spent significant time doing it, don't want to do it again.
This example suggested to use
--onto
, which I did:git checkout B git rebase --onto A
But this deletes the commit on
B
entirely and makesA
andB
point to the same commit i.e. the last one onA
.
My question is: How can I effectively rebase B off A so that it looks like B started from A ? (which was actually true in the beginning).
My best guess is that I'm using
--onto
wrong. Or that I should use something else (likecherry-pick
). - I have branch
-
Radu Murzea over 8 yearsThank you.
git rebase --onto A B~ B
worked PERFECTLY. Now all I have to figure out is why :) :D -
Sam about 7 yearsNote for those blindly copy-pasting (as I did): the second argument needs to point to
old A
, soB~
only works ifB
has a single commit - which here, it does. I like to think of the syntax asgit rebase --onto <new base> <old base> <head>
;<old base>
is where<head>
currently branches from, and<new base>
is where you want it to branch from. -
Radu Murzea over 5 yearsHmmm, interesting, I'll look more into this part, thanks.