Reputation: 6665
I often have sub-branches on a branch that I want to rebase onto the mainline. Consider this:
* (Mainline)
*
*
| * (topicA_Branch3)
| *
| *
| * (topicA_Branch2)
| *
| *
| * (topicA_Branch1)
| *
| *
|/
*
*
I want to move all three of these topicA
branches onto mainline. Currently, I know two ways to do this:
While on topicA_Branch3
, execute the command, git rebase Mainline
.
a. At this point, I would have to delete topicA_Branch1
and 2
and manually re-create the branches on the correct commits on the now rebased topicA_Branch3
.
Another way would be to do three separate commands:
a. While on topicA_Branch1
, do git rebase Mainline
.
b. git rebase --onto topicABranch1 <topicA_Branch1-old-SHA> topicABranch2
c. git rebase --onto topicABranch2 <topicA_Branch2-old-SHA> topicABranch3
d. This is kind of cumbersome...
Is there a command that I want that will rebase a branch and bring it's sub-branches with it?
To be clear, I want to end up with this:
* (topicA_Branch3)
*
*
* (topicA_Branch2)
*
*
* (topicA_Branch1)
*
*
* (Mainline)
*
*
*
*
Upvotes: 8
Views: 1268
Reputation: 28268
Is there a command that I want that will rebase a branch and bring it's sub-branches with it?
Stumbling upon this question again a decade later, there now exists the wonderful option --update-refs
that does exactly what you ask for:
... [main L|✔] >git log --oneline --graph --all
* 517711b (HEAD -> main) m4
* 1e39f07 m3
| * 9ea1b8a (topicA_Branch3) A6
| * 6f3fd41 A5
| * c2c1632 (topicA_Branch2) A4
| * bcbe7a9 A3
| * d807097 (topicA_Branch1) A2
| * 5570ac2 A1
|/
* 709d93d m2
* e3dd1f6 m1
* 6df6959 .gitignore
... [main L|✔] >git rebase --update-refs main topicA_Branch3
Successfully rebased and updated refs/heads/topicA_Branch3.
Updated the following refs with --update-refs:
refs/heads/topicA_Branch1
refs/heads/topicA_Branch2
... [topicA_Branch3 L|✔] >git log --oneline --graph --all
* 6f13f5e (HEAD -> topicA_Branch3) A6
* ca3fccc A5
* 5909128 (topicA_Branch2) A4
* 88baa8c A3
* 204986f (topicA_Branch1) A2
* 2253d3b A1
* 517711b (main) m4
* 1e39f07 m3
* 709d93d m2
* e3dd1f6 m1
* 6df6959 .gitignore
... [topicA_Branch3 L|✔] >
This option was added to git two years ago in version 2.38.0 .
I use it all the time and all my rebase aliases includes it when applicable:
$ git config --list | grep rebase
alias.ri=rebase -i --rebase-merges --update-refs
alias.rc=rebase --continue
alias.rur=rebase --rebase-merges --update-refs
$
Upvotes: 2
Reputation: 1137
What about that:
a. While on `topicA_Branch1`, do `git rebase Mainline`.
b. `git rebase --onto topicABranch1 topicABranch1@{1} topicABranch2`
c. `git rebase --onto topicABranch2 topicABranch2@{1} topicABranch3`
d. ...
This might easily be automated. The syntax topicABranch1@{1} means "the last known state of topicABranch1 before the rebase"
Upvotes: 1
Reputation: 62519
You could use git filter-branch
with an appropriate --parent-filter
. Something like this:
git filter-branch --parent-filter 'sed -e "s/X/Y/"' --tag-name-filter cat -- branchA branchB branchC
Here X
should be the hash of the first commit that is not on mainline but is on the other branches, and Y
could just be HEAD
or Mainline
or the hash of the current head of Mainline
...
Upvotes: 0
Reputation: 28268
I am afraid this is cumbersome, I am not aware of any existing do it all command. But it is scriptable. The commands to get from the first to second illustration are
for i in topicA_Branch1 topicA_Branch2 topicA_Branch3
do
git branch $i._OrIg_ $i
done
# First branch directly
git rebase --onto Mainline topicA_Branch1
# Remaining branches
git rebase --onto topicA_Branch1 topicA_Branch1._OrIg_ topicA_Branch2
git rebase --onto topicA_Branch2 topicA_Branch2._OrIg_ topicA_Branch3
After you have verified things are correct you can delete the *._OrIg_
branches. With this you only have to keep the script up to date with the names and sequence of the branches.
Update: You can create a list of all the branches, in sequence, with
git rev-list --reverse --simplify-by-decoration Mainline..topicA_BranchN \
| git name-rev --stdin --name-only
Here you are only dependent on knowing the name of the last topicA_BranchN
branch, e.g. topicA_Branch3 in your example.
Upvotes: 0