Mercurial_ The Definitive Guide - Bryan O'Sullivan [112]
Tidying Up the Tree
Not all projects have pristine history. There may be a directory that should never have been checked in, a file that is too big, or a whole hierarchy that needs to be refactored.
The convert extension supports the idea of a “file map” that can reorganize the files and directories in a project as it imports the project’s history. This is useful not only when importing history from other revision control systems, but also to prune or refactor a Mercurial tree.
To specify a file map, use the --filemap option and supply a filename. A file map contains lines of the following forms.
# This is a comment.
# Empty lines are ignored.
include path/to/file
exclude path/to/file
rename from/some/path to/some/other/place
The include directive causes a file, or all files under a directory, to be included in the destination repository. This also excludes all other files and directories not explicitly included. The exclude directive causes files or directories to be omitted, and others not explicitly mentioned to be included.
To move a file or directory from one location to another, use the rename directive. If you need to move a file or directory from a subdirectory into the root of the repository, use . as the second argument to the rename directive.
Improving Subversion Conversion Performance
You will often need several attempts before you hit the perfect combination of user map, file map, and other conversion parameters. Converting a Subversion repository over an access protocol like ssh or http can proceed thousands of times slower than Mercurial is capable of operating due to network delays. This can make tuning that perfect conversion recipe very painful.
The svnsync command can greatly speed up the conversion of a Subversion repository. It is a read-only mirroring program for Subversion repositories. The idea is that you create a local mirror of your Subversion tree, then convert the mirror into a Mercurial repository.
Suppose we want to convert the Subversion repository for the popular Memcached project into a Mercurial tree. First, we create a local Subversion repository.
$ svnadmin create memcached-mirror
Next, we set up a Subversion hook that svnsync needs.
$ echo '#!/bin/sh' > memcached-mirror/hooks/pre-revprop-change
$ chmod +x memcached-mirror/hooks/pre-revprop-change
We then initialize svnsync in this repository.
$ svnsync --init file://`pwd`/memcached-mirror \
http://code.sixapart.com/svn/memcached
Our next step is to begin the svnsync mirroring process.
$ svnsync sync file://`pwd`/memcached-mirror
Finally, we import the history of our local Subversion mirror into Mercurial.
$ hg convert memcached-mirror
We can use this process incrementally if the Subversion repository is still in use. We run svnsync to pull new changes into our mirror, then hg convert to import them into our Mercurial tree.
There are two advantages to doing a two-stage import with svnsync. The first is that it uses more efficient Subversion network syncing code than hg convert, so it transfers less data over the network. The second is that the import from a local Subversion tree is so fast that you can tweak your conversion setup repeatedly without having to sit through a painfully slow network-based conversion process each time.
Migrating from Subversion
Subversion is currently the most popular open source revision control system. Although there are many differences between Mercurial and Subversion, making the transition from Subversion to Mercurial is not particularly difficult. The two have similar command sets and generally uniform interfaces.
Philosophical Differences
The fundamental difference between Subversion and Mercurial is of course that Subversion is centralized, while Mercurial is distributed. Since Mercurial stores all of a project’s history on your local drive, it only needs to perform a network access when you want to explicitly communicate with another