سؤال

I have the following minimal example:

---M---A-----D1---D2---D3
   |\       /|
   | B1---B2 |
   \         / 
    -C1---C2-

Here,

  • M is master at the moment,
  • there are features
    • A,
    • 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)?

هل كانت مفيدة؟

المحلول

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'
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top