Delete all local changesets and revert to tree - version-control

I'm using Mercurial and I've got into a terrible mess locally, with three heads. I can't push, and I just want to delete all my local changes and commits and start again with totally clean code and a clean history.
In other words, I want to end up with (a) exactly the same code locally as exists in the tip of the remote branch and (b) no history of any local commits.
I know hg update -C overwrites any local changes. But how do I delete any local commits?
To be clear, I have no interest in preserving any of the work I've done locally. I just want the simplest way to revert back to a totally clean local checkout.

When the simplest way (a new hg clone) isn't practical, I use hg strip:
% hg outgoing -l 1
% hg strip $rev # replace $rev with the revision number from outgoing
Repeat until hg outgoing stays quiet. Note that hg strip $rev obliterates $rev and all its descendants.
Note that you may have to first enable strip in your Mercurial settings.
PS: an even smarter approach is to use the revset language, and do:
% hg strip 'roots(outgoing())'

You'll want to make a local clone where you preserve only the changesets that are also present in the remote repository. Use TortoiseHg, hg log or similar to figure out which of your revisions is that lastest revision you didn't make (the one before the mess started). Using hg outgoing can help here -- it will list all the changesets you made -- pick a revision number earlier than any of those.
If the target revision is called good and your clone is called foo, then do:
hg clone -r good foo foo-clean
This will be a fast, local operation -- there is no reason to download everything again. The foo-clean clone will only contain changesets up to revision good. You can now replace foo-clean/.hg/hgrc with foo/.hg/hgrc in order to preserve your repository-local settings such as the default push/pull path.
When you are satisfied that foo-clean has everything you need from foo, then simply delete foo and rename foo-clean to foo. Do a hg pull to get any new changesets from the remote repository into your clone and continue like normal.
If nobody has pushed new changesets to the remote repository, then it is very simple to determine which revision you want to use as good above: hg id default will tell you the ID of the tip in the remote repository.

Ok. So just delete all the local stuff, hg init the new local repository and hg pull the latest tip you have. Don't forget to hg update after this.

You may use
hg strip revision
to kill any revision and its subtree in your local repository.
https://www.mercurial-scm.org/wiki/Strip
But don't try to use it for anything that has been already pushed.

Just delete everything you have on your local system and re-clone the remote repo.

hg strip `hg out --template "{rev} {author}\n" | grep YOUR_AUTHOR_NAME | cut -d " " -f 1`
does the trick for me.
It strips all revisions that aren't pushed to the default repository which are created with your author name.
You can also use this style to make it not checking with the default repository but with another Repository
hg strip `hg out OTHER_REPO_ALIAS --template "{rev} {author}\n" | grep YOUR_AUTHOR_NAME | cut -d " " -f 1`

If you are using TortoiseHg, one simple way to get out of a (small) mess is to first update to the latest revision, then select your changesets and initiate "merge with local". When the merge dialogue appears, simply click the little '+' icon to reveal some extra options, one of which is "discard changesets from merge target (other) revision". Doing this will mean your changesets will still be in the repo and get pushed, but will have no effect, because they will be discarded in the merge. If you have a lot of changesets spanning many heads, you might not want to pollute the repo this way, but it's a simple fix and worth considering if the changesets you are discarding contain data that you may later want to reference.

Related

How to abort an Hg merge without losing working copy changes?

Last night I started a merge; and forgot to commit it.
Later on I made some changes to the working copy.
Today I no longer want that merge at all (as I'll merge on a newer revision), but I want to keep the local working changes. The changes are independent of any merge resolution.
How can the local changes be kept (and/or reapplied later) while aborting the current merge?
Using shelve on the local changes was not allowed:
$ hg shelve foo/bar
abort: cannot shelve while merging
Using an hg up -C, the normal way to 'abort a merge', would eliminate the local changes.
This is not like How to 'hg merge' without affecting the working directory? because a merge has already been started, just not committed. Answers that involve finishing the commit first, and then picking changes is suitable if such can be shown simply, although the question is focused about 'abort without the commit'.
The easiest solution is probably to record the changes temporarily in a secret commit and then to revert to that commit, e.g.:
hg resolve -m -a # mark all files as resolved
hg commit -s -m "Savepoint." # Temporary commit.
hg update .^ # Back to original revision.
# (Use ".^" in cmd.exe on Windows.)
hg revert -r tip --all # Revert files to saved commit.
hg diff # Verify that you've got all the changes.
hg strip -r tip --keep # And discard the temporary commit.
We're using a secret commit here so that it doesn't accidentally get pushed if you forget to strip it (or if you plan to keep it around afterwards).
If you're using the evolve extension, hg prune -r tip is to be preferred over hg strip -r tip --keep, as it still keeps the temporary commit around (hidden) in case you need to refer to it later.

What commands do you use to refresh your development environment with Mercurial?

I guess I'm learning somewhat backwards. I'm very comfortable with git and never used mercurial until my most recent project.
One of the things that bothers me is that sometimes I can't seem to refresh my development environment because of un-tracked file errors. I really don't care whether files are tracked/untracked on the development server. I'd just like to be able to pull the most recent state of the repo from bitbucket.
Unfortunately, I sometimes end up resorting to nuking the app and re-cloning. Normally this wouldn't be that big of a deal but there are dependencies that I need to add back to the app each time I do this because they are not stored in the repo.
With git I would run...
git reset --hard; git checkout master -f; git pull; git checkout origin/master -f
What's the mercurial equivalent? I've tried...
hg revert --all; hg pull; hg update;
Which seems to work as I would expect it sometimes. When it doesn't work it aborts due to the untracked file errors. I'm looking for something that works all the time.
hg up --clean
That's all there is to it. (hg up rather than hg update because hg is cooler than git and allows unique abbreviations. I dislike the way when I'm forced to use git it doesn't accept git ci like a sane version control system. I know I could make an alias... but I haven't ever got round to it partially as I don't use it very often at all)
hg help [command] (or hg [command] --help) is useful. The help for revert mentions that you probably want to use hg update -r rev or hg update --clean . instead.
This will only change tracked files. Untracked files will be left alone, which I think is what you want.

Hg (Mercurial): any way to "set aside" the working copy for later?

Scenario: After your last commit, you decided to do some extensive refactoring of the codebase. After a time, you realize it is taking longer than expected, and you'd really rather put off the refactoring for another time, and work on more pressing tasks. But you don't want to lose all of the refactoring work you've done so far.
So, is there a way to "archive" or "branch" the working copy (essentially, set it aside but keep it in the repository for later access), and then revert to the last good commit and resume from there, without fear of creating multiple heads or getting the two mixed up?
Don't worry about "the fear of two heads". Two heads is a very normal state. It's called anonymous branches, and it's one of the ways people do temporary branches in Mercurial.
Just commit, and then update to tip-1 and you're ready to go:
hg commit -m "working on XXX"
hg update -r "tip-1"
and away you go. If you want to drop a bookmark (less permanent than a tag) on that head you can, but there's no need to worry about it.
You can always push one head without pushing another using hg push -r HEAD where that can even be hg push -r .
Don't fear heads -- they're what makes a DAG based VCS powerful.
You can do this with the mq, attic or shelve extensions.
Assign a tag to your refactor revision
Commit the tag
Clone the repository again
Revert to the stable version
Work from the stable version
Don't worry about multiple heads, you can easily merge later
Since mercurial uses hard links, you can keep both repositories on your local machine with minimal space used.
commands:
$hg tag Refactor
$cd ..
$hg clone Refactor Stable
$cd Stable
$hg revert -r REVISION_NUMBER
extra help:
http://hgbook.red-bean.com/
http://kiln.stackexchange.com/
You can do it the simple way:
$ hg diff -g > tmp
$ hg revert --all
Your changes will now be stored in tmp. You can restore them with
$ hg patch --no-commit tmp
and you'll be back where you were. There are extensions like shelve that automates the above for you.
In git you would do a 'stash'. According to This hg has 'shelve', but it requires an extension.

Use case for private changes

Supposing I have following scenario: I cloned some open-source project, say from URL X. Now I have local clone of it. I made some changes to local clone to try things out and commited them locally. Now what I want is following:
I want to get update from the open-source project X. Just get all its latest code, without my changes at all. But I want my changes to live somewhere in tag in history so I can get them later. And I don't want to separate clone for this, want it all in my one repo.
For now I did following:
Tag my changes with hg tag
Pull & merge latest code from URL X
Revert repository to latest revision of URL X
But I feel this isn't good way and it's roundabout. I think there's better way. Could you please suggest?
Instead of tags, I would use a bookmark. If you use Mercurial 1.8 or later, you already have the bookmark functionality built-in. Otherwise, you first have enable the extension by putting the following in your ~/.hgrc file:
[extensions]
bookmarks =
[bookmarks]
track.current = True
Now get the clone of your project:
hg clone http://bitbucket.org/user/X
cd X
and hack away:
# edit, edit, edit...
hg commit -m 'Great new feature!'
Now put a bookmark on this changeset
hg bookmark mywork
This is like a tag, but the advantage of a bookmark is that is moves along when you make new commits. This is just like when you're reading a book and move the bookmark along with you. When the bookmark is created, you can do
hg update mywork
to get back to the bookmarked changeset.
When there has been changes made in the upstream repository, then you pull and merge them into your own branch:
hg update mywork # if necessary
hg pull
hg merge
hg commit -m 'Merged new upstream changes.'
The bookmark will have moved forward and is now pointing to the merge changeset you just created. If you want to update to the version in X, then
hg update --rev -2
will do it after you pulled in changes -- this updates to the old tip changeset from before the merge, which was the tip of X.

Fastest way to "reset" Mercurial repository to Version X (without cloning)

Let's say I clone a remote Mercurial repository (over the local network or even over the Internet) to try something out.
I work in my clone, make a few commits...and then I realize that my changes don't make sense and I have to start over again.
So I want to have a "fresh" clone again, from the same source repository.
Basically, I want to "reset" my local repo to the point before I started experimenting.
What's the best / fastest way to do this?
The simplest way would be to just make a new clone, but then HG copies the whole repo and the whole history over the network again.
If the repo is really big, this will take some time and/or block the network.
I tried to make a new clone into the same folder (hoping that HG would recognize this and update only the files which have changed and the history) but that seems to copy the whole repo as well.
I could "hg rollback", but this rollbacks only the last commit. If I made several commits, I can only undo the last one. So I can't reset the repo to the point before I started committing.
Any ideas?
Is there really no other way than to clone the whole thing again?
(note: a solution with TortoiseHg would be nice...I prefer this over the command line)
You'll end us using hg strip as gizmo suggests, but the traditional way to do this would be to clone again -- not from the remote repo, but from your own local repo. For example, if you checkout is 'repository' and you've added changesets 99 and 100 that you don't like you'd do:
cd ..
hg clone -r 98 respository repository-scrubbed
mv repository respository-with-crap-I-do-not-want
mv repository-scrubbed repository
That should be near instantaneous.
If you enable the Strip Extension, you can use the "hg strip" command that will remove the history you don't want anymore.
More information is available on the Strip command wiki page.
hg update -r <changeset number>
eg hg update -r 1 for the second version. You can use hg log to see what version you want