1

I have a mercurial repo with the following history (most recent commit at the top) on a feature branch:

mergeDefaultA
|
mergeDefaultB
|
C
|
mergeDefaultD

mergeDefaultXXXX are merge commits that came as the result of merging the default branch into the feature branch.

What has happened is commit C is screwed, but this was not noticed until after I had pushed mergeDefaultA to Bitbucket. What I want is the following picture:

exactlyWhatIsInMergeDefaultD
| 
mergeDefaultA
|
mergeDefaultB
|
C
|
mergeDefaultD

Where exactlyWhatIsInMergeDefaultD is literally exactly what was the state of the code in mergeDefaultD. However, everything I'm reading seems to indicate either you can't undo a series of commits like this (only a single commit back) and even then many of the options aren't available once you've pushed "into the wild".

How do I achieve this?

If this was git, I'd do:

git revert mergeDefaultD

How do I do the same in Mercurial?

Adam Parkin
  • 17,891
  • 17
  • 66
  • 87

2 Answers2

4

Here's what I think you want:

hg revert -r GOOD_REVISION_NUMBER --all
hg commit -A -m "reverting back to revision GOOD_REVISION_NUMBER"

Once that is committed, as soon as someone pulls from you (or you push to them) they will get the most recent revision containing only the good stuff. If they ever do want to go back to the bad stuff, you could always update to that revision:

hg update -r BAD_REVISION_NUMBER
Harvtronix
  • 854
  • 6
  • 16
  • It still will leave 2 heads will not it? If so, it will not be possible to `push` it (without `force` which shouldn't be used ever) – zerkms Mar 09 '15 at 23:39
  • see this post for reference: http://stackoverflow.com/questions/3688263/mercurial-beheading-a-head – Harvtronix Mar 09 '15 at 23:43
  • It states exactly what I just said :-) – zerkms Mar 09 '15 at 23:57
  • Indeed! It will require a force in order to create that second branch of development (and immediately close it), but to my knowledge, this is the only practical way to basically "start over" from a particular commit, without performing a pull/merge combination. This is, of course, assuming the bad changes/commits are beyond the point of attempting a merge. – Harvtronix Mar 10 '15 at 00:02
  • I personally just merge with discard in such cases, as I think a dummy merge is better than `--force` – zerkms Mar 10 '15 at 00:02
  • Could you post the steps for that as an alternate answer? I'm not actually familiar with the mercurial equivalent of (for example) `svn merge --accept mine-full`. – Harvtronix Mar 10 '15 at 00:04
  • It's `hg merge --tool 'internal:local'`, just add it to yours :) http://www.selenic.com/mercurial/hg.1.html#merge-tools – zerkms Mar 10 '15 at 00:08
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/72623/discussion-between-harvtronix-and-zerkms). – Harvtronix Mar 10 '15 at 00:26
  • I think we may have all just been thinking too hard on this one. Updated my answer to basically do exactly what was originally desired. It just takes a couple extra flags. – Harvtronix Mar 10 '15 at 00:50
1

To expand a bit on Harvtronix' answer (which is fine, by the way):

One simple way is to revert to the old revision number ('GOOD') and commit. Note: reverting means that you set the files to the same content as in revision 'GOOD', you don't go back down the tree to that commit. If you did, you would indeed branch off and have two heads.

hg revert -r GOOD --all
hg commit -m "all is good now"

Another way can be to only throw out revision C (if I read your explanation correctly, it's actually just C that is causing the issue). 'hg backout'will introduce the reverse of C in your working directory, so you can then commit it.

hg backout -r C
hg commit -m "Backed out C"

Finally, one last option is to close the bad branch, update to the last commit that was fine and commit further there:

hg up -r BAD
hg commit --close-branch -m "This head is bad"
hg up -r GOOD
... continue here ...
Mathiasdm
  • 1,791
  • 14
  • 26
  • Given that merges were done after the bad commit C, using backout or commiting a revert to C seems the much better option. He could subsequently simply do another merge and thus merge the reversal of changeset C to the branches. That's easier in this case than when going back to before C and re-attempting a merge from there (not sure whether such merge would actually give the result one would want due to the non-linear nature of the DAG). – planetmaker Mar 10 '15 at 12:25
  • Agreed, very good point. I mentioned revert because Adam mentioned wanting to go back exactly to the old commit, but maybe I shouldn't have added it. – Mathiasdm Mar 10 '15 at 12:31