17

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 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?

2 Answers 2

16

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.

1
  • Awesome, thanks! I'll use this in future (if being more careful with my merges fails to work). See @terminus's answer for what I did. I think it achieved pretty much the same result as your answer.
    – Jake
    Commented Dec 15, 2010 at 0:53
6

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.

3
  • Thanks, After reading this I looked into patches and ended up here: gitready.com/intermediate/2009/03/04/… So I Branched off A and cherry-picked D and F, then merged the result into the original branch to bring it up to date.
    – Jake
    Commented Dec 15, 2010 at 0:52
  • Did you really cherry-pick F? I thought F was only to reverse B and C, so it had nothing to do after C'?
    – Gauthier
    Commented Dec 15, 2010 at 10:03
  • Sorry, now I'm not sure. Perhaps I did but didn't really need to.
    – Jake
    Commented Jan 5, 2011 at 7:29

Not the answer you're looking for? Browse other questions tagged or ask your own question.