问题
Consider following scenario:
- I checked out a branch from master
- I made some commits
- I merged updated master
- I made some more commits
- Now I want rebase commits from point 4 so that commits from point 2 are not affected.
So if I have initially:
(1) (2)
x--x--x--x--x--x--x master
\ \
y--y--Y--y--y dev
(2)(3) (4)
I want to get:
(1) (2)
x--x--x--x--x--x--x master
\ \
y--y--------Y'--y'--y' dev
(2) (5) (5)
If I just do git rebase master
it will rebase commits both from 2 and from 4 and delete merge from 3. It's not what I want.
There is also option to do git merge master
, then git rebase -i -p
before the merge commit from 3 and move the last merge after the merge from 3 and do fixup/squash it into the merge from 3. Update: it does not work that easy. Git refuses to squash two merges. This problem: git rebase interactive: squash merge commits together .
回答1:
You start from:
(1)
x--x--x--x--x--x--x master
\ \
y--y--Y--y--y dev
(2)(3) (4)
Do a git rebase --onto:
git branch dev1 Y^
git rebase --onto master Y^ dev
Y^
references the first parent of the merge commit Y
: here 'y
', and not 'x
'.
See "Ancestry References":
The first parent is the branch you were on when you merged, and the second is the commit on the branch that you merged in.
You would end up with:
(1)
x--x--x--x--x--x--x master
\ \
y--y Y'--y'--y' dev
(2) (5)
(dev1)
That would split your initial dev
branch in two, and apply only the last dev
commits on top of master
, while keeping the first dev
commits unchanged, now referenced by the branch dev1
.
You can try a:
git rebase -p --onto master `Y^` dev
to see if that preserve the relationship between between y
(that is Y^
) and the newly rebased Y'
. But I doubt that is possible.
-p
is for --preserve-merge
.
回答2:
Using my and VonC's answers made more automate-able solution:
git checkout -b tmp Y
git merge master
git reset --soft HEAD^^
git rev-parse master > .git/MERGE_HEAD
git commit -C Y
git checkout -
git rebase --onto tmp Y
git branch -d tmp
Y - is the merge commit to be extended.
And it works like this:
x--x--x--x--x--x--x master
\ \
y--y--Y--y--y dev
x--x--x--x--x--x--x master
| \
\ Y tmp
\ / \
y--y y--y dev
x--x--x--x--x--x--x master
| \ \
\ Y-----Y' tmp
\ / \
y--y y--y dev
x--x--x--x--x--x--x master
| \
| -------Y' tmp
\ /
y--y--Y--y--y dev
x--x--x--x--x--x--x master
| \
| -------Y' tmp
\ / \
y--y y--y dev
x--x--x--x--x--x--x master
\ \
y--y--------Y'--y--y dev
回答3:
I end up doing the following:
git rebase -i -p Y^
In the file add the following line after line with the merge (presumably after the first line):
exec sh -c "git merge master; git reset --soft HEAD^^; git rev-parse master > .git/MERGE_HEAD; git commit -C `git rev-parse HEAD`"
来源:https://stackoverflow.com/questions/18978494/how-to-rebase-only-the-commits-after-the-latest-merge