Bare-bones basic Mercurial for Subversion users
Created 19 June 2009
Mercurial is a distributed version control system. If you’re used to using Subversion, a DVCS can seem exotic and bewildering. But they aren’t so different, and you can use Mercurial with a simple workflow similar to your Subversion workflow. This will get you started using Mercurial, and you can adopt DVCS techniques slowly, as you need them.
This is an introduction to Mercurial for developers already using Subversion. I’ll cover the basics of duplicating your Subversion workflow with Mercurial. Many things are the same between the two, but there are important differences.
In a hurry? These are equivalents:
|SVN way||HG way|
|svn checkout||hg clone|
|svn commit||hg commit|
then: hg push
|svn status||hg status|
|svn diff||hg diff|
better: hg ci -A
|svn update||hg pull -u|
|svnadmin create||hg init|
Want more info? Read on...
In both Subversion and Mercurial, a repository stores changes made to a set of files over time. You can make a local copy of a shared repository, edit files, and share them back with the central repository.
But how this is accomplished is very different in the two systems. Subversion is a centralized system: there is a single repository. Developers check out the project into a local working tree. When a change is ready, it’s checked in to the central repository where other users can see it. This is a star topology with the repository at the center and developers’ working trees at the spokes.
In contrast, Mercurial is a distributed system. There can be many repositories, and none is “the real” repository, all are peers. When you get a copy of a repository to work on, you actually create a repository on your own machine, paired with a working tree in which to edit files. Your private repository is technically no different than a shared repository. The only difference is that the shared repository is used by many developers, and your private repository is used by only you.
After installing Mercurial, you need to make one configuration setting, your identity. Edit ~/.hgrc to add your username:
username = Your Name <email@example.com>
Like Subversion, Mercurial’s command-line interface is a single command with a short name: hg (from the chemical symbol for mercury). You can use Mercurial through other interfaces, but I’ll just be talking about the command line in this tutorial.
“hg help” works just like “svn help”, showing you commands and options, with details on each when needed.
To get your own copy of a project, you use the “hg clone” command. It’s called clone because you are actually making a new repository as a copy of the project’s. The project will give you an address for its repository, in the form of a URL. You use that with clone to make your own repository:
$ hg clone http://path.to/repo.for/coolproject
destination directory: coolproject
requesting all changes
adding file changes
added 259 changesets with 591 changes to 125 files
updating working directory
112 files updated, 0 files merged, 0 files removed, 0 files unresolved
Now you have your own working tree named for the last component of the project URL. In Subversion, every directory in the tree has a hidden directory called .svn containing clean copies of the files, and other bookkeeping information. In Mercurial, there’s only a single .hg directory at the root of the working tree, and it contains an entire repository, including the complete history of the project.
One big different between Mercurial and Subversion is hinted at by this difference in the .svn and .hg directories. In Subversion when you checkout a working tree, you can root it at any directory in the repository. You can check out only part of a repository if you want.
With Mercurial, it’s all or nothing. Where Subversion works directory by directory, Mercurial is always an entire repository at a time. You cannot clone only part of a repository, you have to take the entire thing.
As with Subversion, once you have your working tree, you use it, and edit files until you have a change that you like. You commit your change in Mercurial just as you do with Subversion, with the commit command (often abbreviated ci). Like svn, it will launch an editor to collect a log message, or you can provide the message with a -m argument:
.. edit my_first_file.txt ..
$ hg ci -m "Wow! I edited a Mercurial file!"
committed changeset 1:367cbd55abdb
At this point, you’ve committed your change to your local repository. With Subversion, commit takes the change you’ve made in your working tree and sends it to the central repository where everyone else can see it. Not so with Mercurial.
If you want to see what changes you’re about to make, the “hg status” and “hg diff” commands work similarly to their svn counterparts.
A quick word about changeset numbering: with Subversion, a single central repository means that all changes are serialized, and so can be given sequential numbers. With Mercurial’s distributed repositories, this isn’t possible. Many developers can be making changes in their own repositories at the same time, and eventually those changes will all flow together, so a sequential numbering system won’t work.
Instead, Mercurial gives changesets hashed identifiers (the 367cbd55abdb in the sample above). These are globally unique, and can be used to refer to this changeset no matter which repository it ends up in. But for convenience, the changeset is also given a local sequential number (the 1 above). This number is only meaningful in this repository.
With Mercurial, commit simply applies the changes in the working tree to your local repository. To share those changes with others, you have to push them from your repository to another with the “hg push” command.
Remember that Mercurial imposes no relationship among repositories. You can push changes from your repository to any other cloned from the same project. But when you cloned your repository originally, Mercurial recorded the location of the source repository so that it would be the default “other repository” for commands like push. (You can see this with the “hg paths” command.)
When you are ready to share your changes with the world, the push command will compare your repository with the destination, and send all the changesets needed to bring them up to date:
$ hg push
pushing to http://path.to/repo.for/coolproject
searching for changes
remote: adding changesets
remote: adding manifests
remote: adding file changes
remote: added 2 changesets with 3 changes to 3 files
remote: bb/acl: ned is allowed. accepted payload.
remote: quota: 533.9 KB in use, 150.0 MB available (0.35% used)
(The actual messages will vary depending on the remote repository.)
You can see what changes you would push by using the “hg outgoing” command. It compares the local and remote repositories to show you what the next push will do.
As with Subversion, you can add and remove files to the repository:
$ hg add my_new_file.txt
$ hg rm that_old_junk.cob
But with Mercurial there’s also an easier way: when you commit a change with “hg ci”, you can add the -A flag, which means to automatically add any new files, and remove any missing files:
$ hg ci -A -m "Lots of changes"
committed changeset 25:84398acef4f4
With -A, you simply make your working tree look the way you want the repository to look, creating, editing and removing files, then Mercurial makes it all happen in one step. You have to be careful, though: if you have files that you didn’t mean to check in, Mercurial won’t know, and will happily add them to the repository.
While you’re working in your local tree, others will be pushing changes to the shared repository, and you’ll need to get them. In Subversion, you use the “update” command to pull changes from the repository into your working tree. Just as “svn ci” became “hg ci” and “hg push”, the process of getting updates from the shared repository is a two-step process in Mercurial.
You pull changes from the remote repository with “hg pull”, and then bring those changes from your local repository into your working tree with “hg update”. Luckily, Mercurial provides a shortcut to do both steps at once:
$ hg pull -u
pulling from http://path.to/repo.for/coolproject
searching for changes
adding file changes
added 21 changesets with 55 changes to 33 files
33 files updated, 0 files merged, 0 files removed, 0 files unresolved
This pulls changes from your default remote repository into your local repository, and then updates your working tree from your repository.
$ hg init my_new_repository
You’ll have a brand new empty repository that isn’t a clone of any other project. You can add files to it and maintain revision histories locally. Of course, cloning works on this repository, so you can make other local clones if you want.
When your project is mature enough to need a shared repository, you can push from your local repository to a newly created server repository to move the history up to the server.
Have you ever issued a commit command, and then immediately realized you shouldn’t have? Mercurial has a great solution for times like this: “hg rollback”. It undoes the last transaction in your repository. Not only does it remove the last commit from the history, but it restores the files in your working tree to their state before that commit. It’s perfect for fixing a bad commit, because you’re put right back where you were before the commit, and can make whatever fix you need before committing again:
$ hg st
$ hg ci -m "I'm sure this is perfect!"
committed changeset 259:84398acef4f4
$ .. OH CRAP ..
$ hg rollback
rolling back last transaction
$ hg st
$ hg ci -m "Tweak the authors list" README.txt
committed changeset 259:05dfe4c03d2d
Notice that the second commit got the same serial number as the first one, since the rollback completely removed the first one from the repository.
Finally, an interesting trick Mercurial can perform is to act as a local web server to give you a web interface to browsing your code:
$ hg serve
then open http://localhost:8000/ in your browser to explore your local repository.
Of course, Mercurial is more than a Subversion look-alike, but this is enough to get you started. As a distributed version control system, Mercurial offers much more flexibility in how changesets flow among your co-workers, and branching and merging is the norm rather than the exception. There’s even an extension system offering more functionality.
- Intro to Distributed Version Control (Illustrated) gives an overview of distributed version control concepts.
- Bitbucket and Google Code offer Mercurial hosting for your project.
- Mercurial’s Working With Subversion page which details options for using Mercurial in conjunction with your existing Subversion repositories.
- My blog, where other topics of interest to developers appear every few days.