Suppose I have the following scenario:
o (master)
/ o--o (WIP1)
/ /
o--o--o--o--o--o (WIP2)
(X) \
o--o (WIP3)
Is there a git command which creates a new branch so that it contains the subtree after branch X? I want to perform a "large rebase", I want the three WIP branches rebased on master.
I know I can do that with some Bash scripting but I'd like to know how to do that using a git command.
There is no single git command for that. You will have to do some manual work. In your situation:
o (master)
/ o--o (WIP1)
/ /
X--o--o--B--o--o (WIP2)
\
o--o (WIP3)
You first rebase WIP1 onto master:
git rebase --onto master X WIP1
which will lead to this:
o--o (WIP1)
(master) /
o--o--o--B’
/
/
X--o--o--B--o--o (WIP2)
\
o--o (WIP3)
If you now run git rebase --onto master X WIP2
, you get this structure:
o--o (WIP1)
(master) /
o--o--o--B’
/ \
/ o--o--B’’--o--o (WIP2)
/
X--o--o--B--o--o (WIP3)
This is probably not what you want, so now you should rebase WIP2 and WIP3 on B’
:
git rebase --onto B’ B WIP2
git rebase --onto B’ B WIP3
which will lead to this:
o--o (WIP1)
(master) /
o--X--o--o--B’--o--o (WIP2)
\
o--o (WIP3)
I have flagged this question as duplicate. I will write what I explained the other answer but using your example.
The approach that I use for such use cases is to merge all the branches
to be moved into 1 common artificial node, and then use the rebase command
with the --preserve-merges
option. Merging all the branches will expose 1
end-point that will be used as the final input parameter for rebase --onto
. The
start point is usually obvious, the origin of the subtree to move.
When merging to get the subtree endpoint, conflicts should be explicity
avoided. Therefore the merge commands shall be instructed to solve them
automatically with the -Xours
option. The merging result is not important
since these artificial merge nodes will be discarded after the rebase.
It is recommended to create a new branch pack in order to not lose the original references. In the example above the following commands would be performed:
$ git checkout -b pack WIP1 # create new branch at 'WIP1'
$ git merge -s recursive -Xours WIP2 # merges WIP2 into pack (node p2)
$ git merge -s recursive -Xours WIP3 # merges WIP3 into pack
Below can be seen what the tree would become. Two new artificial nodes p2 and pack have been created with the merges.
o (master)
/
/ (WIP1) (p2)
/ o-----o-----o----o (pack)
/ / / /
o--o--o--o-----o-----o / (WIP2)
(X) \ /
o------------o (WIP3)
Now it's time to rebase. Since now there is a common endpoint for all the branches (pack), it's easy to move the whole subtree with:
$ git rebase --preserve-merges --onto master X pack
Which produces this:
(WIP1') (p2')
o-----o-----o----o (pack')
(master) / / /
o----o----o--o--o-----o-----o / (WIP2')
(X) \ /
o------------o (WIP3')
Now it's time to rearrange the references. I don't know why, in some cases the references are moved and in others are not. Type this for each reference WIP1, WIP2, WIP3 or whatever you need:
$ git checkout WIP1
$ git reset --hard <WIP1' hash>
And finally, get rid of the artificial commits that were created for generating a common subtree end node.
$ git branch -D pack
$ git branch -D p2 # if there is any
So the final tree would be:
(WIP1')
o-----o
(master) /
o----o----o--o--o-----o-----o (WIP2')
(X) \
o------------o (WIP3')
o (master)
/ o--o (WIP1)
/ /
o--p--p--o--o--o (WIP2)
(X) (Y)
\
o--o (WIP3)
This should be a rebase --onto
(you can see one example in "How to move certain commits to another branch in git?"):
git rebase --onto master X WIP1
git rebase --onto master X WIP2
git rebase --onto master X WIP3
From Chronial's test, that would give:
p'--p'--o--o (WIP2)
/
o-----o-----p--p--o--o--o (WIP1)
(X) (master) (Y')
\
p''--p''--o--o (WIP3)
So the first rebase is ok, but you need to get Y SHA, and:
git rebase --onto Y' Y WIP2
git rebase --onto Y' Y WIP3
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