Undo a Git merge, but keep later changes, and rewrite history
I have a bunch of branches, each with different features. Usually I'll have some extra branch开发者_如何学运维 "not_master" which contains master+feature A like so:
(not_master) a--b--c--d--e---M--x--y--z
(feature A) --h--i--j-/
Sometimes I want to unmerge feature A, but keep commits x,y,z
in "not_master".
In other words, I would like this:
(not_master) a--b--c--d--e--x--y--z
I see that I can do a git revert -m 1 M
which will add a commit to the end that reverts my changes, but I don't really want to do that since these commits haven't been published yet so adding more commits makes the history even harder to read.
Others suggest just doing a git reset --hard M
, but that will dump the changes of x,y,z
. Am I just thinking about this the completely wrong way? Should I just git reset --hard M
and cherry pick x,y,z?
git rebase
will do what you want. git rebase -i <commit e>
should work: it will open an editor, and you delete the merge commit and save.
You should also be able to directly specify rebasing x..z onto e, but sorting out the semantics of the command-line is a bit hairy. If I'm reading the man page right, It should be git rebase --onto <commit e> <commit M> not_master
.
EDIT: Tested and appears to work:
mkdir foo; cd foo
git init
touch initial
git add initial
git commit -m 'initial'
git checkout -b topic
touch topic
git add topic
git commit -m 'topic'
git checkout master
touch master
git add master
git commit -m 'master'
git tag pre_merge
git merge topic
git tag merge
touch post_topic
git add post_topic
git commit -m 'post topic'
git rebase --onto pre_merge merge master
results in a history of
initial -- master -- post topic (master)
\
\-- topic (topic)
精彩评论