{"thread":{"id":"26632","subject":"got myself into trouble; now what? - how to revert once you've pushed","startedAt":"2011-03-01T19:37:19Z","lastAt":"2011-03-02T15:52:40Z","messageCount":5,"participants":["Robert Buck","Jeff King","Jon Seymour"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"162573","messageId":"AANLkTi=RGhGMcoDEL4q2pnnZ97tdswYG7OkjNS3wF7jn@mail.gmail.com","threadId":"26632","inReplyTo":null,"subject":"got myself into trouble; now what? - how to revert once you've pushed","fromName":"Robert Buck","fromEmail":"buck.robert.j@gmail.com","sentAt":"2011-03-01T19:37:19Z","receivedAt":"2011-03-01T19:37:19Z","isPatch":false,"sender":{"key":"buck.robert.j@gmail.com","avatar":"https://gravatar.com/avatar/1686742e8ac2595378aac67f26fd638ddaf494194f9af0cb6082c4a7eca1a366?d=mp&s=160"},"body":"I have a problem where a unexpected merge occurred and got pushed to\nour Gitolite repository.\n\nWe have two branches: master, feature/wixinstall\n\nApparently a merge happened from the branch to master (and I am pretty\nsure I never typed `git merge...`). But alas, a merge somehow happened\nand got pushed.\n\nThen I followed the Git Pro documentation, which said to do this...\n\n    git revert -m 1 [sha_of_C8]\n\nNow I am left with a bigger mess. When I merge master to the branch,\nall the newly added files on the branch got deleted (not what I\nwanted). Somehow git is interpreting the revert literally as a\nsequence of deletes which it incorrectly then applies to the work on\nthe branch.\n\nWhat I really wanted the revert to do is restore the history of the\nworld immediately prior to the merge. But now I have a branch I can't\nmerge into at all without losing a weeks work.\n\nHow can I get out of this mess?\n\nBob\n"},{"id":"162575","messageId":"20110301195027.GE10082@sigill.intra.peff.net","threadId":"26632","inReplyTo":"AANLkTi=RGhGMcoDEL4q2pnnZ97tdswYG7OkjNS3wF7jn@mail.gmail.com","subject":"Re: got myself into trouble; now what? - how to revert once you've pushed","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-03-01T19:50:28Z","receivedAt":"2011-03-01T19:50:28Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Mar 01, 2011 at 02:37:19PM -0500, Robert Buck wrote:\n\n> We have two branches: master, feature/wixinstall\n> \n> Apparently a merge happened from the branch to master (and I am pretty\n> sure I never typed `git merge...`). But alas, a merge somehow happened\n> and got pushed.\n\nDid you run \"git pull\", which is basically fetch+merge?\n\n> Then I followed the Git Pro documentation, which said to do this...\n> \n>     git revert -m 1 [sha_of_C8]\n> \n> Now I am left with a bigger mess. When I merge master to the branch,\n> all the newly added files on the branch got deleted (not what I\n> wanted). Somehow git is interpreting the revert literally as a\n> sequence of deletes which it incorrectly then applies to the work on\n> the branch.\n\nYeah. That reverts the merge, in essence creating a new tree built on\ntop of the merge without the results of the merge. But when you try to\nre-merge between those two branches, it sees that history has already\ncombined, and then afterwards eliminated the result. Which is not what\nyou wanted.\n\nRead the section \"reverting the revert\" directly below the advice you\nfollowed:\n\n  http://progit.org/2010/03/02/undoing-merges.html\n\n> What I really wanted the revert to do is restore the history of the\n> world immediately prior to the merge. But now I have a branch I can't\n> merge into at all without losing a weeks work.\n> \n> How can I get out of this mess?\n\nIf you can accept that history will be rewritten (which is a problem if\npeople have built on top of your bogus merge), then what you want is:\n\n  git checkout master\n  git reset --hard $SHA1_OF_MERGE^\n\nand then re-push.\n\n-Peff\n"},{"id":"162636","messageId":"AANLkTi==_zmSy4j-JwyCuYouV-J3shSObJe2y942PjCn@mail.gmail.com","threadId":"26632","inReplyTo":"20110301195027.GE10082@sigill.intra.peff.net","subject":"Re: got myself into trouble; now what? - how to revert once you've pushed","fromName":"Robert Buck","fromEmail":"buck.robert.j@gmail.com","sentAt":"2011-03-02T13:10:38Z","receivedAt":"2011-03-02T13:10:38Z","isPatch":false,"sender":{"key":"buck.robert.j@gmail.com","avatar":"https://gravatar.com/avatar/1686742e8ac2595378aac67f26fd638ddaf494194f9af0cb6082c4a7eca1a366?d=mp&s=160"},"body":"On Tue, Mar 1, 2011 at 2:50 PM, Jeff King <peff@peff.net> wrote:\n> On Tue, Mar 01, 2011 at 02:37:19PM -0500, Robert Buck wrote:\n>\n>> We have two branches: master, feature/wixinstall\n>>\n>> Apparently a merge happened from the branch to master (and I am pretty\n>> sure I never typed `git merge...`). But alas, a merge somehow happened\n>> and got pushed.\n>\n> Did you run \"git pull\", which is basically fetch+merge?\n>\n>> Then I followed the Git Pro documentation, which said to do this...\n>>\n>>     git revert -m 1 [sha_of_C8]\n>>\n>> Now I am left with a bigger mess. When I merge master to the branch,\n>> all the newly added files on the branch got deleted (not what I\n>> wanted). Somehow git is interpreting the revert literally as a\n>> sequence of deletes which it incorrectly then applies to the work on\n>> the branch.\n>\n> Yeah. That reverts the merge, in essence creating a new tree built on\n> top of the merge without the results of the merge. But when you try to\n> re-merge between those two branches, it sees that history has already\n> combined, and then afterwards eliminated the result. Which is not what\n> you wanted.\n>\n> Read the section \"reverting the revert\" directly below the advice you\n> followed:\n>\n>  http://progit.org/2010/03/02/undoing-merges.html\n>\n>> What I really wanted the revert to do is restore the history of the\n>> world immediately prior to the merge. But now I have a branch I can't\n>> merge into at all without losing a weeks work.\n>>\n>> How can I get out of this mess?\n>\n> If you can accept that history will be rewritten (which is a problem if\n> people have built on top of your bogus merge), then what you want is:\n>\n>  git checkout master\n>  git reset --hard $SHA1_OF_MERGE^\n>\n> and then re-push.\n\nThat does not work; the central server rejects the commit. Now there\nare two other commits after mine, and the problem is getting worse.\n\nDoes anyone have a detailed guide of how to obliterate a range of\ncommits and replay subsequent history on top of that?\n\n-Bob\n"},{"id":"162638","messageId":"20110302133720.GA26989@sigill.intra.peff.net","threadId":"26632","inReplyTo":"AANLkTi==_zmSy4j-JwyCuYouV-J3shSObJe2y942PjCn@mail.gmail.com","subject":"Re: got myself into trouble; now what? - how to revert once you've pushed","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-03-02T13:37:20Z","receivedAt":"2011-03-02T13:37:20Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Mar 02, 2011 at 08:10:38AM -0500, Robert Buck wrote:\n\n> > If you can accept that history will be rewritten (which is a problem if\n> > people have built on top of your bogus merge), then what you want is:\n> >\n> >  git checkout master\n> >  git reset --hard $SHA1_OF_MERGE^\n> >\n> > and then re-push.\n> \n> That does not work; the central server rejects the commit. Now there\n> are two other commits after mine, and the problem is getting worse.\n\nYeah, you would need \"git push -f\" to force push the rewrite of history.\nBut if people are building on top, then you would be removing their\nhistory.\n\nIt's also possible that your server is configured to disallow pushing\nhistory rewrites entirely, in which case all of the advice below will be\nuseless to you.\n\n> Does anyone have a detailed guide of how to obliterate a range of\n> commits and replay subsequent history on top of that?\n\nYou can do what you want with rebase. But note that this is also\nrewriting history, so people building on top of what you rewrite will be\ninconvenienced. If you are working a small-ish team where you can tell\neverybody \"stop what you're doing, let me fix this, and then we'll\nproceed with working on top of my new history\", then you can do\nsomething like this.\n\nYour history presumably looks something like this:\n\n         T1--T2--T3\n         /         \\\n  ...A--B--C--D--E--M--N1--N2 <-- master\n\nwhere A..E are commits on master, T1..T3 are commits on the topic branch\nthat accidentally got merged, M is the merge commit, and N1..N2 are\ncommits built on top. Presumably your master points at N2. Obviously the\nnumbers of commits I just made up, but you should be able to identify\nthe sha1 id of the merge commit, \"M\".\n\nThough the reflogs will provide a safety net for reversing the changes\nwe're about to make, it may be simpler to experiment on a new branch,\njust in case we screw things up. Then when we have it looking good, we\ncan put our changes onto the master and topic branches.\n\nSo the first thing I would do is:\n\n  git checkout -b new-master master\n\nto make a new branch and check it out. We can also give a name to the\nbogus merge commit to make it easier to refer to:\n\n  git tag M <commit sha1 of M>\n\nSo now we want to go back to \"E\", and replay N1 and N2 on top of that.\nBecause M was a merge of topic to master, we know that E is the first\nparent of M, which we can refer to as \"M^1\". So we can use rebase like:\n\n  git rebase --onto M^1 M\n\nwhich will take all commits between the merge and the current branch tip\n(which should be N1 and N2), and replay them on top of the commit just\nprior to the merge. Check the result in \"git log\" or \"gitk\", or checking\nit out, or whatever makes sense to you. If you're happy, you can force\nit into master with:\n\n  git branch -f master new-master\n\nI think you also said you ended up merging the bogus merge back onto the\ntopic branch. To undo that, probably you want to just move the topic\nbranch back to T3, where it was just prior to the merge. T3 is the\nsecond parent of the merge, so you can use \"M^2\".\n\n  git branch -f new-topic M^2\n\nand then check that new-topic looks good, and install it with:\n\n  git branch -f topic new-topic\n\nNow you can push it all upstream with:\n\n  git push -f origin master topic\n\nEverybody else on your team will then want to fetch the new history and\nreset their branch pointers to match:\n\n  git fetch origin\n  git branch -f master origin/master\n  git branch -f topic origin/topic\n\nNote that this will _throw away_ any work they had done that was not in\nthe rewritten history. If they had more commits that weren't pushed,\nthey will need to do a rebase. I think \"git pull --rebase\" will do what\nthey want, but I've never actually used it myself.\n\nI hope that helps. Let me know if you try it and run into complications,\nor if some of my assumptions don't match your situation.\n\n-Peff\n"},{"id":"162642","messageId":"AANLkTi=Oiu19R8+hX16gWDghkPkYf12731KkYctwQgEG@mail.gmail.com","threadId":"26632","inReplyTo":"20110302133720.GA26989@sigill.intra.peff.net","subject":"Re: got myself into trouble; now what? - how to revert once you've pushed","fromName":"Jon Seymour","fromEmail":"jon.seymour@gmail.com","sentAt":"2011-03-02T15:52:40Z","receivedAt":"2011-03-02T15:52:40Z","isPatch":false,"sender":{"key":"jon.seymour@gmail.com","avatar":"https://avatars.githubusercontent.com/u/207131?v=4"},"body":"Here's the approach I take to backout a merge with a bogus topic\nbranch. I use this in a large team environment where backtracking the\nshared integration branch is simply not an option.\n\nSuppose a topic branch 'topic' was merged with master to produce a\nmerge and then it was decided that topic was a little half-baked\n\ne.g.\n\n$> git merge topic #1\n$> git tag M\n\n$> git checkout -b deliver-topic M^2\n$> git diff --full-index M M^1 | git apply --index   # should work if\n#1 did not produce a conflict\n$> git git commit -m \"backout premature delivery of topic\"\n$> git checkout master\n$> git merge deliver-topic  # backouts changes contributed by #1\n\nThis assumes that neither the original merge with bogus or the merge\nwith deliver-topic produce any conflicts.\n\nThen, suppose I fix the original problem with the topic branch by\nmaking additional commits to the original topic branch\nthat fix the problem.\n\nI then revert the revert on the deliver-topic branch\n\n$> git checkout deliver-topic\n$> git revert # revert the backout to restore the deliver-topic to the\nsame state as the original topic\n$> git merge topic # this is the fixed topic\n$> git checkout master\n$> git merge deliver-topic\n\nThe nice thing about using a separate delivery branch to manage the\nbackouts of prematurely merged topics is that the topic branch\nitself stays clean. All the revert and apply logic is confined to a\ndelivery branch which can be forgotten about once the history moves\non. Yes, the integration branch itself looks a little messy, but\nintegration branches tend to a look a little messy anyway.\n\njon.\n"}]}