boltup_im_coding
boltup_im_coding

Reputation: 6665

Rebasing a branch with sub-branches all at once

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:

  1. 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.

  2. 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

Answers (4)

hlovdal
hlovdal

Reputation: 28268

Is there a command that I want that will rebase a branch and bring it's sub-branches with it?

Yes, there now is!

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

user2987828
user2987828

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

twalberg
twalberg

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

hlovdal
hlovdal

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

Related Questions