Git: How to "undo" a merge
The situation:
Starting with the Master at A
I branched and made some changes at B
then merged that branch back in (C)
. After making some more changes I was at D
but found I needed to deploy the code without the changes that happened in the branch. If I hand't merged it that would have been fine.
A_______C___D
\ /
\_B_/
Firstly I'd like to know what I should have done from here to deploy the code as if the merge never happened. Note: none of the same files that were edited in the branch have been edited in the master.
Secondly...
I didn't have time to work out the best method to deal with this, so I deleted the开发者_C百科 files which the branch added, and manually reverted a few edits made in the branch then commited the result for deployment (F
)
A_______C___D___F
\ /
\_B_/
I want to be able to keep developing the branch and merge any changes from the master into it to keep it up to date, but if I do that the stuff I did to create F
will be merged in and cause the files to be deleted and the edits to be reverted. What is the best way to deal with this?
You can use rebase to do that in one step:
git rebase --onto A C D
I just tested this, with appropriate results:
$ edit test.txt
$ git add .
$ git commit -mA
$ git checkout -b the_branch
$ edit test.txt
$ git commit -a -mB
$ git checkout master
$ git merge master the_branch --no-ff
$ edit test.txt
$ git commit -a -mD
From here you have the situation you described. Then:
$ git rebase --onto <SHA1-for-A> <SHA1-for-C> master
rebases commits from C (excluded) to master, onto A. I needed to fix some conflicts since I modified at the same places in B and D, but I think you won't.
_D'
/
/
A_______C___D
\ /
\_B_/
Doc about git rebase --onto
, which is more or less your situation:
http://git-scm.com/docs/git-rebase
If you had:
A_______C___D___F
\ /
\_B_/
, then you have now:
_D'___F'_(master)
/
/
A_______C___D___F
\ /
\_B_/(the_branch)
From here, merging the changes in master into the branch is easy. Discard the commit F'
altogether.
$ git checkout master # if you were not here already
$ git branch old_fix # if you want to be able to return to F' later
$ git reset --hard <SHA1-to-D'>
After the commands above you have:
(master)
/
_D'___F'_(old_fix)
/
/
A_______C___D___F
\ /
\_B_/(the_branch)
To merge updates of master into the_branch:
$ git checkout the_branch
$ git merge master
... and fix the conflicts.
The obvious solution is to reset to A
, reapply all patches manually and resolve conflicts (which you won't have).
Alternatively you can just git revert
patch B
but that will create a new commit.
Although Gauthier's answer is better.
精彩评论