7

I've used Git in the past and I'm a Hg noob:

I have following repository structure:

o [> default] commit A
|
o commit B
.
.
.
o <a-tag]
|

I've updated to the commit with the a-tag and committed a few other commits. Now I have

o [> default] commit C
|
o commit D
|
|  o [default] commit A
|  |
|  o commit B
|  .
|  .
|  .
| /
o <a-tag]
|

Now (before pushing) I realize that I had my commits commit C and commit D based on the wrong commit. How can I go back to the initial state (without having to re-clone the repository) dropping these commits commit C and commit D (pendant to git reset --hard a-tag)?

Mot
  • 28,248
  • 23
  • 84
  • 121

4 Answers4

8

You can use 'strip' to permanently delete commits and all it's descendants. In your case you need to specify the id of "D" revision:

hg strip -r D

Note: mq extension must be turned on:

[extensions]
mq=

Mercurial backups bundles of the stripped changesets in .hg/strip-backup so this operation is rather safe.

Ruslan Yushchenko
  • 636
  • 1
  • 8
  • 8
4

You say without cloning, and I'll get to that but first let me point out that doing this:

cd ..
hg clone -r -2 yourrepo yournewrepo

is an instantaneous action that gets you a new clone, locally, without the last two commits in your old repo. Because it's a local clone it uses hardlinks (even on Windows) so the repository takes up no additional diskspace.

That is the classic Mercurial solution. Mercurial was built with the idea of an immutable history. If there's something in the history you regret you commit its inverse (which is what backout does), so the history shows the error and its correction -- like a scientists log book. If you can't/couldn't abide having it in history you'd do a clone that excludes it like I showed above.

Not everyone can be quite so... hardcore... about their history, so lots of extensions have shown up that will modify history but they have to be specifically enabled. In your case the rebase extension, which you already have installed (it comes with Mercurial now), will do exactly what you want. You just need to enable it in your ~/.hgrc and then reparent D onto A. If you really just want C gone the strip command from the mq extension will do that. It also ships with Mercurial.

Martin Geisler
  • 72,968
  • 25
  • 171
  • 229
Ry4an Brase
  • 78,112
  • 7
  • 148
  • 169
1

I would just clone from the appropriate point and delete the old repo. Without cloning consider hg backout to undo first C and then D, or, if this is your ultimate goal hg rebase to move both C and D to the commit A point.

chill
  • 16,470
  • 2
  • 40
  • 44
1

Backout C + backout D will remove these 2 commits, but add additional 3 (backout+backout+merge). "Clean" remove from history may be

If you want only change wrong parent to correct, you have to use rebase, as @chill mentioned

Lazy Badger
  • 94,711
  • 9
  • 78
  • 110