git rebase a branch which is based on several branches
I have the following minimal example:
---M---A-----D1---D2---D3 |\ /| | B1---B2 | \ / -C1---C2-
- Rebasing a Git merge commit
- Rebasing remote branches in Git
- git pull --rebase on public branches
- Git rebase failure with auto-generated file
- How can I reorder/combine commits using Git rebase?
- How to rebase git submodule preserving references to submodule commits from git repository containing the submodule?
- M is master at the moment,
- there are features
- B (consisting of B1, B2), and
- C (consisting of C1, C2)
under development and on top of all those a feature
- D (consisting of a series D1, D2, D3).
Now feature A was accepted to go into the master branch, therefore I have to rebase everything to A. This means, I want
---M---A-----------D1'---D2'---D3' |\ /| | B1'---B2' | \ / -C1'---C2'-
Of course, it is easy to rebase B (B2) at A, and also C, alone/separately.
But how do I rebase my branch D (including B and C), keeping the merge D1 (as shown above)?
2 Solutions collect form web for “git rebase a branch which is based on several branches”
You’ll want to pass the flag
--preserve-merges into your rebase command. This looks like:
git checkout D git rebase A --preserve-merges
I’m far from an expert in the algorithm used by git to preserve merges, so I don’t know what sort of conflicts you may or may not run into, but this will cause git to attempt to reconstruct your merge commit
D1 during the rebase.
You could rebase branches B and C individually and then use grafts (or git-replace) to re-attach the new rebased branches to the merge commit. using grafts I would do
# rebase the individual branches git rebase M B2 --onto A git rebase M C2 --onto A # replace old branch heads with rebased branch heads echo $(git rev-parse D1) $(git rev-parse B2') $(git rev-parse C2') > .git/info/grafts
The grafts will make your git history appear as if D1 has parents B2′ and C2′. If you remove .git/info/grafts, D1 will have its original parents again.
To make this permanent, use filter branch to rewrite your history:
#make it permanent git filter-branch -f --tag-name-filter cat D1'
A more elaborate explanation can be found in this answer on prepending the past to a git repository. It also explains how you should use git replace instead of grafts. I gave the example with grafts because I have a bit more experience with those.
git replace would rather be along the lines:
# rebase the individual branches git rebase M B2 --onto A git rebase M C2 --onto A # replace old branch heads with rebased branch heads git replace B2 B2' git replace C2 C2' #make it permanent git filter-branch -f --tag-name-filter cat D1'