Of course there is official and perfectly good documentation.
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.
[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.
$ hg status -A # Show status of all tracked files.
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@xalab.example.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
Cloning And Updating A Repository To Another Location
Although these decentralized version control systems have a lot of flexibility, the normal thing is that you have a central storage location and several people work on the same code in several different locations. That is what was just previously described.
But what if you’re working on the code mostly in one location but want to use the source control to distribute it — and of course changes — to multiple hosts. For example, if I have a repo of my unix configuration files, I may want to push that out to various hosts when I’m setting them up. Since that will be constantly being improved in arbitrary places (any host) the system needs to be flexible. This can be done in the following way. Start by creating the remote copy of the repo like this.
cd .. # From inside repo skelx
hg clone skelx ssh://testuser@192.168.1.250//home/testuser/X/skelx
It can then be updated from within the repo to the remote location like this.
hg push ssh://testuser@192.168.1.250//home/testuser/skelx
Obviously there are topology problems if I make different changes to this repo from two remote systems and never coordinate.
Once the remote repo is in action, you can merge any changes made there with a pull.
hg pull ssh://$HOST:$PORT//home/testuser/X/skelx
This prevents the need to log in to the secure central machine from a potentially insecure situation.
What Version Is This
You may want to know what version you’re up to.
hg log
You may want to even slip this into source code somehow. I’ve used this to generate a that information the way I wanted it.
hg log -l1 --template '{date|shortdate} - Version: {rev}'
More details about how you can format such things here.
What Files Changed
Sometimes you see evidence of changes when you pull in a repository that someone else (or you elsewhere) is working on.
adding file changes
added 2 changesets with 4 changes to 3 files
new changesets d8d47651e7a3:1d1218fa8546
...
3 files updated, 0 files merged, 0 files removed, 0 files unresolved
It is clear that some files changed, but which ones? To find out, use this command.
hg status --change .
Reorganizing Things
The worst thing about all of the version control systems is that they are philosophically self-defeating in the sense that if you knew the final organizational structure of all your project’s files, you probably would also know the final exact syntax of the entire project. But the whole point of a version control system is that it manages your lack of this foresight. However, renaming and moving files into completely new directory trees can be a pain.
Simple Renaming
For a simple mistaken filename, this works fine.
hg rename xt2png.c xy2png.c
Note that apparently on some platforms there can be issues with simply changing case. As described here you may need to do something like this.
hg rename xy2png.c tmp
hg rename tmp XY2png.c
This sequence of events should preserve history.
Changing Directory Layout
Let’s say I had a program called foo that was being tracked. It was a
minor thing designed to be a proof of concept. Now we want to rewrite
foo from scratch with all the right things done from the beginning. We
don’t want to lose our earlier work, but we want to move existing foo
work into a directory called foo-prototype
to refer to it. Here is
what can work.
mkdir foo-prototype
hg mv foo.c foo-prototype/foo.c
touch foo.c # Starting the new one.
hg add foo.c
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.
What if you just want to take a look at a previous version to get an idea what you might have messed up?
hg cat sourcecode.cxx -r 117 > sourcecode-117.cxx
Push Creates New Remote Head
Sometimes you do a hg push
and you get this mysterious message
telling you something is wrong.
abort: push creates new remote head c473eca09ada!
(merge or see 'hg help push' for details about pushing new heads)
This probably means that you and the remote team did some changes at the same time. The answer is to merge them.
hg pull
hg merge
hg commit -m "= merge"
hg push
And it should be fine. Obviously if your merge conflicts, that needs to be sorted out.
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.
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".