How do I rebase a chain of local git branches?

Viewed 4182

Suppose I have a chain of local git branches, like this:

       master    branch1   branch2
          |         |         |
o----o----o----A----B----C----D

I pull in an upstream change onto the master branch:

              branch1   branch2
                 |         |
            A----B----C----D
           /
o----o----o----o
               |
            master

Now I rebase branch1, giving me this:

                        branch2
                           |
            A----B----C----D
           /          
o----o----o----o----A'---B'
               |         |
            master    branch1

Note that because of rebasing branch1, commits A and B have been rewritten as A' and B'.

Here's my problem: now I want to rebase branch2. The obvious syntax is git rebase branch1 branch2, but that definitely does not work. What I want it to do is just reapply C and D on top of branch1, but instead it tries to reconcile A and A' and it considers them conflicting.

This does work:

git rebase --onto branch1 branch2^^ branch2

This assumes I know that branch2 has exactly 2 commits beyond the previous branch1 ref.

Since git rebase --onto works, is there a 1-line git command that will rebase branch2 on top of a newly-rebased branch1, in a way that I don't have to know exactly how many commits were part of branch2? (I want to specify some magic ref instead of branch2^^ for the middle argument.)

Or is there some other approach I'm overlooking?

I would be most interested in a solution that scales well to extreme cases, not just two branches - suppose I've got something more like 5 local branches, all chained on one another, and I want to rebase all of them together.

5 Answers
git rebase master branch1
git rebase --onto HEAD ORIG_HEAD branch2
git rebase --onto HEAD ORIG_HEAD branch3
# ...
git rebase --onto HEAD ORIG_HEAD branchN

I have a git alias script to do this:

rebase-chain = "!f() { \
  for i in ${@}; do \
    git rebase --onto HEAD ORIG_HEAD $i; \
  done; \
}; f"

which can make the workflow like:

git rebase master branch1 # start with a normal rebase
git rebase-chain branch2 branch3 branch4 ... branchN

bonus

assuming you have bash-completion for git:

__git_complete "git rebase-chain" _git_branch

This question is a subset of Modify base branch and rebase all children at once

I recently started using git-chain which is a tool to solve this problem.

Basically you specify a chain

git chain setup -c myfeature master branch1 branch2

Once this chain is set up, you can pull in commits from master, then you can run git chain rebase -c myfeature and the tool figures out all the refs and rebases everything nicely for you.

As an added benefit, it also calculates and handles any amendments or new commits to branch1 and branch2.

The git-branchless suite of tools can neatly solve this problem:

$ git move -s A -d master

Disclaimer: I'm the author.

This will rebase A, as well as all of its descendants, and any branches pointing to any of those commits. See the documentation for git move.

Related