Mercurial basics

Contents

Overview

Mercurial is a revision control system. That means it is designed to help track work on a collection of files, giving you the ability to identify and retrieve the revisions that existed at various points during the process. The huge motivation for revision control is when there are several people all working on the same program (or collection of programs), because then it is very helpful to be able to fugure out what was changed and by whom. But revision control is also helpful when you are working by yourself: if you manage to make a mess, you can back up to a coherent prior state.

Mercurial can do much more than we need in this class. If you get really interested, or you need something more, there is a very good online tutorial and reference, This page is limited to the features you are most likely to need in this class.

General ideas

Mercurial manages a subtree of files: a directory and all of its subdirectories. This matches the way we usually work on projects (including labs): we make a new directory for each new project. When we are working in a Mercurial-managed tree, we see the files there as we would normally. But Mercurial also maintains, behind the scenes, additional files that keep the history and other information; we call that hidden collection the repository. (The repository is actually hiding in a dirctory named .hg, taking advantage of the fact that names beginning with dot are not normally shown.) The visible files we actually work with are called a working copy. We manage the repository and its relationship with the working copy using the hg commmand.

The main Mercurial command hg is always followed by another command that tells Mercurial what to do. It is very helpful to remember that one of those commands is help. So you can always do

$ hg help
to get general help, or add a command, such as update, to the end of the help to get a reminder of what that command does and what its arguments can be; for example,
$ hg help update
or even
$ hg help help

Setup and customization

Before you can make very much use of Mercurial, you need to do a tiny bit of setting up (which has already been done for the lab accounts, and in rudimentary form for the accounts of students in this class). Whenever you run hg, it will look for a file named .hgrc in your home directory for some settings and options. You can add to that later on if you want to set some more options.

Repositories

In this class, you'll often start from a repository that already exists; you'll create your own working copy and repository by cloning the existing repository. When that repository is local, you can name it with its filename; so the command

$ hg clone /cslab/class/csci235/in-class/09-10 .
will clone the repository under /cslab/class/csci235/in-class/09-10 to the current working directory (that's the dot); it will make a new directory named 09-10 to hold the working copy and repository.

If you already have a directory for which you would like to start using Mercurial, you can create a repository by (1) making sure that you are in the top directory of the tree you want to manage and then (2) issuing the command

$ hg init

When you create a repository, you will need to remember to use the hg add command to tell the repository what files it should manage (see below).

Because there are usually files in the working copy that you don't want in the repository (such as the compiled versions of the source files), you can use a file .hgignore to tell Mercurial the filenames it should ignore. That will be included when you clone a repository, but you can edit it if you need to. That file has patterns in it (a lesson in itself), but you can get a reasonable starting file for this class by copying the file found at

/cslab/class/csci235/misc/dot.hgignore
That file ignores .class files, Emacs backups, and dot-files. You will want to remember to explicitly add the .hgignore file, because it will otherwise be ignored.

The main commands

These are the commands you will use the most.

The general pattern you will use most of the time is

  1. Clone a repository that we have provided with hg clone
  2. Make changes to the files in the working copy. If you create a new file in the working copy, use hg add to tell the repository about it. If you want to get rid of a file, use hg remove to remove it from the working copy and tell the repository that it goes away. Or, if you just want it to go away in the repository, use hg forget.
  3. When you reach a meaningful point worth remembering, do

Using the saved versions

Revert

If you make a mess out of (or remove) one or more files, you can revert to a saved version; as long as you are reverting to the latest committed version, it is fairly simple. To revert the file Palindrome.java, you would simeply use

$ hg revert Palindrome.java
As the message printed tells you, it rename what is in the working copy by adding .orig to the end of the name. That way you can use an editor to pick pieces from that file. To get revert all files that have been changed, you would use --all instead of the filename(s).

You can revert a file to a particular version of a file by adding a -r and a revision number after revert. Doing that may make a future commit more complicated--requiring a merge. That's beyond the scope of this introduction; so you might want to do your experimenting with a copy of the repository.

Working with another copy

Note that you can also make another copy from the repository by using the clone command. From the top directory in your repository, you can do

$ hg clone . ../new-copy
to make a new repository and working copy in the directory ../new-copy. You can then move into that copy and manipulate it without messing up the current one. That's especially useful if you want to try reverting files to several different revisions or you want to look at an entire revision other than the most recent one. You can discard a working copy and its copy of the repository by removing the entire directory. Warning: this is dangerous. If you wanted to get rid of the copy created above and you are currently in the directory new-copy, you would need to
  1. $ cd ..
    to move to its parent directory
  2. DANGER:
    $ rm -rf new-copy
    to remove the directory and anything below it, without asking any questions. Be sure you mean it before you type that command.
Selecting a particular revision

You can also reset the working copy to match any committed revision by adding -r version to the update command. That is easy if you want to just look; you can ask which version the working copy is based on by using hg summary.

Editing based on a revision other than the latest one is allowed--and even useful. (It is essential when you have more than one person working on a program.) But doing that will leave you with more than one "latest" version, which makes working with all of the revisions more complicated. If you do that, you'll need to learn how to merge, which is beyond the cope of these notes.

Copying between accounts and/or computers

There are special ways to copy a directory with a Mercurial repository. If you are making a new copy, it is called cloning; there are other commands for making two existing copies match.

A repository can be local, in which case you name it specifying the name of the directory where it exists; that is what the example clone command above does.

When a repository is remote, you need to tell how to reach it, which you can do with a URL using ssh. If the other computer is named cslab25 and the account name there is mortimer.snerd, the URL will have the form ssh://mortimer.snerd@cslab25/directory-path (see the example below).

Cloning

If user mortimer.snerd wants to create a new copy of the repository in the current directory (in a lab account) as the directory cs235/lab4 under his home directory, the command would be

$ hg clone . ssh://mortimer.snerd@cslab25/cs235/lab4
The dot is the source (here), and the URL is the remote name.

He'll be prompted for his password, twice.

When he logs in to his own account and changes into the cs235/lab4 directory, all that will be there is the repository--no working copy. To set up the working copy, he would need to

$ hg update
which makes the working copy match the last committed version from the repository.

Push and pull

When another copy of a repository already exists, you push local changes to the remote copy, and you pull remote changes to the local copy. Usually you want to check what will happen before you do it.

To push changes out, our friend Mortimer would first

$ hg outgoing ssh://mortimer.snerd@cslab25/cs235/lab4
to see what changes need to go, then
$ hg push ssh://mortimer.snerd@cslab25/cs235/lab4
to transfer them.

To pull changes in, the sequence would be

$ hg incoming ssh://mortimer.snerd@cslab25/cs235/lab4
to check, then
$ hg pull ssh://mortimer.snerd@cslab25/cs235/lab4
to transfer the changes.

If you are doing this to move files to and from your own computer, you'll probably want to run the push and pull commands on your computer, because the lab computers are easier to name.

More to come

A later installment will provide more information about working with multiple copies of a repository and how you can use Mercurial to work cooperatively with other programmers.


Cary Gray

Last modified: Tue Feb 3 14:55:05 CST 2015

Valid HTML 4.01!