bos@559: bos@559: bos@686: bos@687: bos@686: Migrating to Mercurial bos@686: bos@691: A common way to test the waters with a new revision control bos@686: tool is to experiment with switching an existing project, rather bos@686: than starting a new project from scratch. bos@686: bos@691: In this appendix, we discuss how to import a project's history bos@686: into Mercurial, and what to look out for if you are used to a bos@686: different revision control system. bos@686: bos@686: bos@686: Importing history from another system bos@686: bos@691: Mercurial ships with an extension named bos@686: convert, which can import project history bos@686: from most popular revision control systems. At the time this bos@686: book was written, it could import history from the following bos@686: systems: bos@686: bos@686: bos@691: Subversion bos@691: bos@691: bos@691: CVS bos@691: bos@691: bos@691: git bos@691: bos@691: bos@691: Darcs bos@691: bos@691: bos@691: Bazaar bos@691: bos@691: bos@691: Monotone bos@691: bos@691: bos@691: GNU Arch bos@691: bos@691: bos@691: Mercurial bos@686: bos@686: bos@686: bos@691: (To see why Mercurial itself is supported as a source, see bos@686: .) bos@686: bos@691: You can enable the extension in the usual way, by editing bos@686: your ~/.hgrc file. bos@686: bos@686: [extensions] bos@686: convert = bos@686: bos@691: This will make a hg convert command bos@686: available. The command is easy to use. For instance, this bos@686: command will import the Subversion history for the Nose unit bos@686: testing framework into Mercurial. bos@686: bos@686: $ hg convert http://python-nose.googlecode.com/svn/trunk bos@686: bos@691: The convert extension operates bos@686: incrementally. In other words, after you have run hg bos@686: convert once, running it again will import any new bos@686: revisions committed after the first run began. Incremental bos@686: conversion will only work if you run hg bos@686: convert in the same Mercurial repository that you bos@686: originally used, because the convert bos@686: extension saves some private metadata in a bos@686: non-revision-controlled file named bos@686: .hg/shamap inside the target bos@686: repository. bos@686: bos@695: When you want to start making changes using Mercurial, it's bos@693: best to clone the tree in which you are doing your conversions, bos@693: and leave the original tree for future incremental conversions. bos@693: This is the safest way to let you pull and merge future commits bos@693: from the source revision control system into your newly active bos@693: Mercurial project. bos@693: bos@693: bos@693: Converting multiple branches bos@693: bos@695: The hg convert command given above bos@693: converts only the history of the trunk bos@693: branch of the Subversion repository. If we instead use the bos@693: URL http://python-nose.googlecode.com/svn, bos@693: Mercurial will automatically detect the bos@693: trunk, tags and bos@693: branches layout that Subversion projects bos@693: usually use, and it will import each as a separate Mercurial bos@693: branch. bos@693: bos@695: By default, each Subversion branch imported into Mercurial bos@693: is given a branch name. After the conversion completes, you bos@693: can get a list of the active branch names in the Mercurial bos@693: repository using hg branches -a. If you bos@693: would prefer to import the Subversion branches without names, bos@693: pass the option to bos@693: hg convert. bos@693: bos@695: Once you have converted your tree, if you want to follow bos@693: the usual Mercurial practice of working in a tree that bos@693: contains a single branch, you can clone that single branch bos@693: using hg clone -r mybranchname. bos@693: bos@693: bos@686: bos@686: Mapping user names bos@686: bos@691: Some revision control tools save only short usernames with bos@686: commits, and these can be difficult to interpret. The norm bos@686: with Mercurial is to save a committer's name and email bos@686: address, which is much more useful for talking to them after bos@686: the fact. bos@686: bos@691: If you are converting a tree from a revision control bos@686: system that uses short names, you can map those names to bos@686: longer equivalents by passing a bos@686: option to hg convert. This option accepts bos@686: a file name that should contain entries of the following bos@686: form. bos@686: bos@686: arist = Aristotle <aristotle@phil.example.gr> bos@686: soc = Socrates <socrates@phil.example.gr> bos@686: bos@691: Whenever convert encounters a commit bos@686: with the username arist in the source bos@686: repository, it will use the name Aristotle bos@686: <aristotle@phil.example.gr> in the converted bos@686: Mercurial revision. If no match is found for a name, it is bos@686: used verbatim. bos@686: bos@686: bos@686: bos@686: Tidying up the tree bos@686: bos@691: Not all projects have pristine history. There may be a bos@686: directory that should never have been checked in, a file that bos@686: is too big, or a whole hierarchy that needs to be bos@686: refactored. bos@686: bos@691: The convert extension supports the idea bos@686: of a file map that can reorganize the files and bos@686: directories in a project as it imports the project's history. bos@686: This is useful not only when importing history from other bos@686: revision control systems, but also to prune or refactor a bos@686: Mercurial tree. bos@686: bos@691: To specify a file map, use the bos@686: option and supply a file name. A file map contains lines of the bos@686: following forms. bos@686: bos@686: # This is a comment. bos@686: # Empty lines are ignored. bos@686: bos@686: include path/to/file bos@686: bos@686: exclude path/to/file bos@686: bos@686: rename from/some/path to/some/other/place bos@686: bos@686: bos@691: The include directive causes a file, or bos@686: all files under a directory, to be included in the destination bos@686: repository. This also excludes all other files and dirs not bos@686: explicitely included. The exclude bos@686: directive causes files or directories to be omitted, and bos@686: others not explicitly mentioned to be included. bos@686: bos@691: To move a file or directory from one location to another, bos@686: use the rename directive. If you need to bos@686: move a file or directory from a subdirectory into the root of bos@686: the repository, use . as the second bos@686: argument to the rename directive. bos@686: bos@693: bos@693: bos@693: Improving Subversion conversion performance bos@693: bos@695: You will often need several attempts before you hit the bos@693: perfect combination of user map, file map, and other bos@693: conversion parameters. Converting a Subversion repository bos@693: over an access protocol like ssh or bos@693: http can proceed thousands of times more bos@693: slowly than Mercurial is capable of actually operating, due to bos@693: network delays. This can make tuning that perfect conversion bos@693: recipe very painful. bos@693: bos@695: The svnsync bos@693: command can greatly speed up the conversion of a Subversion bos@693: repository. It is a read-only mirroring program for bos@693: Subversion repositories. The idea is that you create a local bos@693: mirror of your Subversion tree, then convert the mirror into a bos@693: Mercurial repository. bos@693: bos@695: Suppose we want to convert the Subversion repository for bos@693: the popular Memcached project into a Mercurial tree. First, bos@693: we create a local Subversion repository. bos@693: bos@693: $ svnadmin create memcached-mirror bos@693: bos@695: Next, we set up a Subversion hook that bos@693: svnsync needs. bos@693: bos@693: $ echo '#!/bin/sh' > memcached-mirror/hooks/pre-revprop-change bos@693: $ chmod +x memcached-mirror/hooks/pre-revprop-change bos@693: bos@695: We then initialize svnsync in this bos@693: repository. bos@693: bos@693: $ svnsync --init file://`pwd`/memcached-mirror \ bos@693: http://code.sixapart.com/svn/memcached bos@693: bos@695: Our next step is to begin the svnsync bos@693: mirroring process. bos@693: bos@693: $ svnsync sync file://`pwd`/memcached-mirror bos@693: bos@695: Finally, we import the history of our local Subversion bos@693: mirror into Mercurial. bos@693: bos@693: $ hg convert memcached-mirror bos@693: bos@695: We can use this process incrementally if the Subversion bos@693: repository is still in use. We run svnsync bos@693: to pull new changes into our mirror, then hg bos@693: convert to import them into our Mercurial bos@693: tree. bos@693: bos@695: There are two advantages to doing a two-stage import with bos@693: svnsync. The first is that it uses more bos@693: efficient Subversion network syncing code than hg bos@693: convert, so it transfers less data over the bos@693: network. The second is that the import from a local bos@693: Subversion tree is so fast that you can tweak your conversion bos@693: setup repeatedly without having to sit through a painfully bos@693: slow network-based conversion process each time. bos@693: bos@686: bos@686: bos@686: bos@686: Migrating from Subversion bos@686: bos@691: Subversion is currently the most popular open source bos@686: revision control system. Although there are many differences bos@686: between Mercurial and Subversion, making the transition from bos@686: Subversion to Mercurial is not particularly difficult. The two bos@686: have similar command sets and generally uniform bos@686: interfaces. bos@686: bos@686: bos@686: Philosophical differences bos@686: bos@691: The fundamental difference between Subversion and bos@686: Mercurial is of course that Subversion is centralized, while bos@686: Mercurial is distributed. Since Mercurial stores all of a bos@686: project's history on your local drive, it only needs to bos@686: perform a network access when you want to explicitly bos@686: communicate with another repository. In contrast, Subversion bos@686: stores very little information locally, and the client must bos@686: thus contact its server for many common operations. bos@686: bos@691: Subversion more or less gets away without a well-defined bos@686: notion of a branch: which portion of a server's namespace bos@686: qualifies as a branch is a matter of convention, with the bos@686: software providing no enforcement. Mercurial treats a bos@686: repository as the unit of branch management. bos@686: bos@686: bos@686: Scope of commands bos@686: bos@691: Since Subversion doesn't know what parts of its bos@686: namespace are really branches, it treats most commands as bos@686: requests to operate at and below whatever directory you are bos@686: currently visiting. For instance, if you run svn bos@686: log, you'll get the history of whatever part of bos@686: the tree you're looking at, not the tree as a whole. bos@686: bos@691: Mercurial's commands behave differently, by defaulting bos@686: to operating over an entire repository. Run hg bos@686: log and it will tell you the history of the bos@686: entire tree, no matter what part of the working directory bos@686: you're visiting at the time. If you want the history of bos@686: just a particular file or directory, simply supply it by bos@686: name, e.g. hg log src. bos@686: bos@691: From my own experience, this difference in default bos@686: behaviors is probably the most likely to trip you up if you bos@686: have to switch back and forth frequently between the two bos@686: tools. bos@686: bos@686: bos@686: bos@686: Multi-user operation and safety bos@686: bos@691: With Subversion, it is normal (though slightly frowned bos@686: upon) for multiple people to collaborate in a single branch. bos@686: If Alice and Bob are working together, and Alice commits bos@686: some changes to their shared branch, Bob must update his bos@686: client's view of the branch before he can commit. Since at bos@686: this time he has no permanent record of the changes he has bos@686: made, he can corrupt or lose his modifications during and bos@686: after his update. bos@686: bos@691: Mercurial encourages a commit-then-merge model instead. bos@686: Bob commits his changes locally before pulling changes from, bos@686: or pushing them to, the server that he shares with Alice. bos@686: If Alice pushed her changes before Bob tries to push his, he bos@686: will not be able to push his changes until he pulls hers, bos@686: merges with them, and commits the result of the merge. If bos@686: he makes a mistake during the merge, he still has the option bos@686: of reverting to the commit that recorded his changes. bos@686: bos@691: It is worth emphasizing that these are the common ways bos@686: of working with these tools. Subversion supports a safer bos@686: work-in-your-own-branch model, but it is cumbersome enough bos@686: in practice to not be widely used. Mercurial can support bos@686: the less safe mode of allowing changes to be pulled in and bos@686: merged on top of uncommitted edits, but this is considered bos@686: highly unusual. bos@686: bos@686: bos@686: bos@686: Published vs local changes bos@686: bos@691: A Subversion svn commit command bos@686: immediately publishes changes to a server, where they can be bos@686: seen by everyone who has read access. bos@686: bos@691: With Mercurial, commits are always local, and must be bos@686: published via a hg push command bos@686: afterwards. bos@686: bos@691: Each approach has its advantages and disadvantages. The bos@686: Subversion model means that changes are published, and hence bos@686: reviewable and usable, immediately. On the other hand, this bos@686: means that a user must have commit access to a repository in bos@686: order to use the software in a normal way, and commit access bos@686: is not lightly given out by most open source bos@686: projects. bos@686: bos@691: The Mercurial approach allows anyone who can clone a bos@686: repository to commit changes without the need for someone bos@686: else's permission, and they can then publish their changes bos@686: and continue to participate however they see fit. The bos@686: distinction between committing and pushing does open up the bos@686: possibility of someone committing changes to their laptop bos@686: and walking away for a few days having forgotten to push bos@686: them, which in rare cases might leave collaborators bos@686: temporarily stuck. bos@686: bos@686: bos@686: bos@686: bos@686: Quick reference bos@686: bos@686: bos@686: Subversion commands and Mercurial equivalents bos@686: bos@686: bos@686: bos@686: Subversion bos@686: Mercurial bos@686: Notes bos@686: bos@686: bos@686: bos@686: bos@686: svn add bos@686: hg add bos@686: bos@686: bos@686: bos@686: svn blame bos@686: hg annotate bos@686: bos@686: bos@686: bos@686: svn cat bos@686: hg cat bos@686: bos@686: bos@686: bos@686: svn checkout bos@686: hg clone bos@686: bos@686: bos@686: bos@686: svn cleanup bos@686: n/a bos@686: No cleanup needed bos@686: bos@686: bos@686: svn commit bos@686: hg commit; hg bos@686: push bos@686: hg push publishes after bos@686: commit bos@686: bos@686: bos@686: svn copy bos@686: hg clone bos@686: To create a new branch bos@686: bos@686: bos@686: svn copy bos@686: hg copy bos@686: To copy files or directories bos@686: bos@686: bos@686: svn delete (svn bos@686: remove) bos@686: hg remove bos@686: bos@686: bos@686: bos@686: svn diff bos@686: hg diff bos@686: bos@686: bos@686: bos@686: svn export bos@686: hg archive bos@686: bos@686: bos@686: bos@686: svn help bos@686: hg help bos@686: bos@686: bos@686: bos@686: svn import bos@686: hg addremove; hg bos@686: commit bos@686: bos@686: bos@686: bos@686: svn info bos@686: hg parents bos@686: Shows what revision is checked out bos@686: bos@686: bos@686: svn info bos@686: hg showconfig bos@686: paths.parent bos@686: Shows what URL is checked out bos@686: bos@686: bos@686: svn list bos@686: hg manifest bos@686: bos@686: bos@686: bos@686: svn log bos@686: hg log bos@686: bos@686: bos@686: bos@686: svn merge bos@686: hg merge bos@686: bos@686: bos@686: bos@686: svn mkdir bos@686: n/a bos@686: Mercurial does not track directories bos@686: bos@686: bos@686: svn move (svn bos@686: rename) bos@686: hg rename bos@686: bos@686: bos@686: bos@686: svn resolved bos@686: hg resolve -m bos@686: bos@686: bos@686: bos@686: svn revert bos@686: hg revert bos@686: bos@686: bos@686: bos@686: svn status bos@686: hg status bos@686: bos@686: bos@686: bos@686: svn update bos@686: hg pull -u bos@686: bos@686: bos@686: bos@686: bos@686:
bos@686:
bos@686:
bos@686: bos@686: bos@686: Useful tips for newcomers bos@686: bos@691: Under some revision control systems, printing a diff for a bos@686: single committed revision can be painful. For instance, with bos@686: Subversion, to see what changed in revision 104654, you must bos@686: type svn diff -r104653:104654. Mercurial bos@686: eliminates the need to type the revision ID twice in this common bos@686: case. For a plain diff, hg export 104654. For bos@686: a log message followed by a diff, hg log -r104654 bos@686: -p. bos@686: bos@691: When you run hg status without any bos@686: arguments, it prints the status of the entire tree, with paths bos@686: relative to the root of the repository. This makes it tricky to bos@686: copy a file name from the output of hg status bos@686: into the command line. If you supply a file or directory name bos@686: to hg status, it will print paths relative to bos@686: your current location instead. So to get tree-wide status from bos@686: hg status, with paths that are relative to bos@686: your current directory and not the root of the repository, feed bos@686: the output of hg root into hg bos@686: status. You can easily do this as follows on a bos@686: Unix-like system: bos@686: bos@686: $ hg status `hg root` bos@686: bos@559:
bos@559: bos@559: