Here is a brilliant article about distributed source control systems in general with an emphasis on Git and a clear look at the pros and cons of different approaches.

Set Up

Before starting make sure this is setup.

$HOME/.hgrc
[ui]
username = Chris X Edwards <cxe-hg@xed.ch>
editor = /usr/bin/vim

Starting A Project With Some Files To Track

$ cd coolware # Be in the directory you want to manage.
$ hg init     # Creates .hg for this directory.
$ hg status   # Show all non-ignored files.
$ hg add      # Add all 'unknown' files.
$ hg add coolfile1 coolfile2  # Or add specific files.
$ hg ci -u xed -m "Initial coolness" # 1st commit.
$ hg parents  # Show currently checked out revision.

Complete Example Of General Use

$ mkdir coolware
$ cd coolware
$ echo "/* The coolware main program */" > coolware.c
$ hg init
$ hg add coolware.c
$ hg ci -u xed -m "Initial coolness." coolware.c
$ cd ..
$ hg clone coolware coolware-dev
$ cd coolware-dev
$ echo "/* A very cool program. */" >> coolware.c
$ hg ci -u xed -m "Writing cool software." coolware.c
$ cd ../coolware
$ hg pull ../coolware-dev/
pulling from ../coolware-dev/
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
(run 'hg update' to get a working copy)
$ cat coolware.c
/* The coolware main program */
$ hg up
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ cat coolware.c
/* The coolware main program */
/* A very cool program. */

Cloning A Repository

If a project lives somewhere and you want it somewhere else, this is a possible technique for doing that:

hg clone ssh://xed@xablab.ucsd.edu/../sysadmin/safe/chemmgr/

Note the weird ssh URL format, the host is separated from the path by the path separator (/). Also note that the path is relative to the home directory. In this example, I’m showing how to lift a repository out of someone else’s home directory as an example of how to get around this overly helpful feature.

Here is how to specify absolute paths.

hg clone ssh://user@server//home/projects/alpha/

If you need to use a non-standard port. Here SSH listens to 2020.

hg clone ssh://xed@70.59.33.247:2020/pathfromhome/myproject/

If you started the project behind a firewall and want to establish it on your main well-connected server, do something like this from inside the project’s local directory (which will have been set up for hg with hg init etc):

hg clone . ssh://xed@remote.xed.ch//home/xed/project/goodtimes_project/
ssh xed@remote.xed.ch
cd ~/project/goodtimes_project
hg up

Updating Changes From Elsewhere

Say you made some changes on a work machine called w and then you came home to a machine called h that you wanted the changes to also be on. First you have to pull the work repository (or you could have pushed before you left).

hg pull ssh://xed@w/path/aproject

But that’s not all. Nothing will seem different. The h repository will now be aware that changes have been made, but to actually apply them to the local repository, you need to update that with:

hg up

What Files Are Being Tracked

Sometimes I lose track of which files are being tracked. Check with:

hg manifest

Where Did This Stuff Come From?

Sometimes I have something on a fancy server somewhere and I pull it in and that’s all well and good. Mercurial makes pushes automatic so it’s easy to forget where that originally was being stored. If I need to check it out into a different place how can I figure out where it came from in a place I’m currently using it?

$ hg paths
default = ssh://xed@myisp.com/hg/mycoolproject

What Went Wrong?

Sometimes something is done, often to fix a bug, and you wind up making something else not work. You want to go back to the place you "fixed" and revisit that but you can’t remember where it was or what you did. First thing to do is to check the commit logs. I like to reverse them so the newest is last.

hg log | tac

This produces a lot of stuff, but if you can find the commit that was around the problem, look for it’s "changeset" id which should look something like: 87:c472394a44cc. The 87 is important here. To see the changes that were made on this commit:

hg diff -r 87

To see just what files were worked on use:

hg log --template '{files}\n' -r 87

Oops - Revert To Previous

The best summary I have seen is here.

Basically hg revert --all will undo whatever mess you’ve just made, but you can also use --rev to specify a particular revision number.

A good sequence of actions is something like this.

hg log somecode.py # Useful for seeing what's been going on with the file.
hg annotate somecode.py # Lists currently tracked code with rev # that caused it.
hg diff somecode.py # Show only additions/deletions between previous version and current.
hg revert --rev 2 somecode.py # Resets current code back to change set #2.
vi somecode.py # Try some better strategy with the file.
hg ci somecode.py # Check it back in heading in a new direction.

Magic Web Server

Despite the mania for Github, Mercurial is really easy to get on the web and it always has been. The good thing is that you do not need to entrust management of your code to a proprietary company. You can easily host your own repositories. To do so, just be in the tracked directory and do this.

hg serve

That’s it. Note that this automatically starts its own web server on the spot. It is not daemonized but a process that displays all connection attempts. It can also be put into a cgi-bin directory but that’s a different topic. Now point a web browser to your host like this.

http://host.xed.ch:8000/

And you can browse away at the change history and the tracked files. The default permissions are read only. To get the whole project, just do something like this from the command line of the receiving system.

hg clone http://host.xed.ch:8000 project

Using One SSH Hosting Account For Multiple Contributors

Let’s say you have a small group working on a project. They would all like a place which is on 24/7 which can be the main coordinating repository for the group. By renting a $5/month SSH host (or use AWS for free if you’re brave) you can give people personalized access to the repository using SSH keys. Basically the way it works is that all the participants generate an SSH key pair. The public keys are rounded up and put into the hosting service account’s ~/.ssh/authorized_keys file. Instead of giving everyone complete access you can limit the other participants to just being able to work with mercurial. You do this by using the command= directive on the SSH key. Here is an example from the hosting service account’s authorized_keys file.

hosting.service.com:/home/mainaccount/.ssh/authorized_keys
command="hg -R hg/ourproject serve --stdio",no-port-forwarding,\
no-X11-forwarding,no-agent-forwarding \
ssh-rsa AAAAB3NzaC...full/public/key...zYFiidCx amigo@amigoshost

This is all a one line entry, i.e. replace the \ and returns with nothing. Note that the main repo lives in ourproject in the directory ~/hg.

To use this key from a client somewhere, you’ll need the corresponding private key and the password to decrypt it. Then you must tell mercurial that you don’t want ordinary SSH, you want special key SSH. Like this.

hg clone --ssh "ssh -i /home/amigo/.ssh/ourproject_rsa" \
ssh://mainaccount@hosting.service.com/hg/ourproject

If there are problems check my SSH notes especially the part about "Specifying Commands".