Mercurial (Hg)

Environment

    • Windows 7

    • Mercurial 1.7.2

    • TortoiseHG 1.1.7

    • Visual Studio 2010

Mercurial, a/k/a Hg, is a source code management tool. Hg refers to the set of files that make up a project as a repository, or repo. Every repo is complete and independent from any other repos for the project.A changeset is an identified set of changes made to one or more files in a repo. The term is often abbreviated to change or cset and is also referred to as a revision or a rev. Changesets are assigned revision numbers, which are unique to a repo but not to other copies of the repo, and an identifier, consisting of 12 hex digits, which is unique across all copies of a repo. So when working with a local repo it is easier to type the small numbers used to identify a changeset, while still having a unique ID across all copies of the repo in order to identify a changeset.

The commit command creates a new changset, assigns it a rev and ID, and records the parent of the changeset (except in the case of the root changeset). Changesets that don’t have any children are called head changesets, or heads. There is a head changeset for each branch that exists in the repo, and there can be multiple heads with the same branch name.

The tip revision is the changeset most recently added to the repository (and therefore the most recently changed head) and the tip tag is special and cannot be renamed or assigned to a different changeset.

Getting Started

Here are some cheat sheets for getting started with Mercurial and using the TorgtoiseHG, VisualHG, and Eclipse tools.

Hg Config File

On Windows, the user-specific config file (.hgrc) lives here:

%userprofile%\mercurial.ini

A typical .hgrc file might look like this:

# Generated by tortoisehg-config

[paths]

default = \\s1\repositories

project1 = https://user:password@bitbucket.org/user/project1

project2 = https://user:password@bitbucket.org/user/project2

[ui]

merge = kdiff3

username = gd

[tortoisehg]

vdiff = kdiff3

[gtools]

fontcomment = Consolas

fontdiff = Consolas

fontlist = Consolas

fontlog = Consolas

.hg\hgrc file in a repo specifies the repo-specific settings:

[paths]

default = \\s1\repositories\some-project

default-push = \\s1\repositories\some-project-push

Obtaining an Existing Repo

To get a local (working) copy of a repository first set your current directory to the directory you want to be the parent of your repo directory. Something like:

mkdir repos

cd repos

Now use the clone command:

hg clone http://hg.example.com/some-project

This command will pull the repo files from the specified location and place a copy of the repo to the directory some-project int the current directory. You can specify that the repo be placed in a different directory as follows:

hg clone http://hg.example.com/some-project my-repo

This command would place a copy of the repo in the my-repo subirectory.

Upating a Repo

So now you have a copy of a repo stored locally. As changes are made to the repo you copied from you will probably want to update your repo with those changes. To update your local copy of the repo, first take a look at the changes that have been made to the source repo using the incoming command:

cd my-repo

hg incoming http://hg.example.com/some-project

If you see any changes you want to bring into your copy of the repo use the pull command:

cd my-repo

hg tip

hg pull http://hg.example.com/some-project

hg tip

The tip commands before and after the pull command will tell you the rev of your repo before the pull and after the pull.

Since it is possible that changes might have been made to the source repo after you issued the incoming command but before you used the pull command, you might want to explicitly update your repo to a specific rev of the source repo. The incoming command will tell you the changeset ID of the latest changeset. You can then update your repo to this explicit changeset ID with a command like this:

hg pull -r:7c27d9cd42af http://hg.example.com/some-project

You aren’t quite done yet. Hg has only updated the repo files with the latest changeset(s) from the source repo. To have these changeset(s) applied to your repo you must use the update command:

hg update tip

Using the Hg update command is analogous to what other source control systems call check-out.

The pull and update steps can be done with one command:

hg pull -u http://hg.example.com/some-project

You will also need to resolve any file conflicts after doing an update. This can be done using the merge command:

hg merge

To review the revisions without actually merging the changes into your repo, use the -P option:

hg merge -P

To force a merge:

hg merge -f

After any necessary merging has been completed, the commit command must be used to commit the changes to the repo:

hg commit -m "Changed made."

There is also a standard extension called fetch the does a pull, update, merge, then a commit all in one operation. To enable this extension add these lines to your config file:

[extensions]

fetch =

Note that there is no need to specify the location of the fetch extension because this extension is distributed with Hg so that Hg knows where it is located.

Making Changes

To make changes to your repo, simply edit the files in your repo’s working directory. To see which files have been changed in your repo, use the status command:

hg status

The first letter on each line displayed by this command will be one of the following:

    • M—The file has been modified.

    • A—This is a newly added file.

    • R—This file has been deleted (removed).

    • C—This file is clean, no changes have been made to it.

    • !—This file is missing.

    • ?—This file is not part of the repo.

    • I—This file is being explicitly ignored by the repo commands.

A line that does not begin with one of these letters means the line is showing the origin of the previous file listed as A (added). These lines only appear when the -C option is used in the status command.

To see just the changes you have made to your repo, try this command:

hg status -mard

This command will show only those files that have been changed (modified), newly added, removed, or deleted.

Adding Files to a Repo

Create the new file then use the add command to add it to the repo:

hg add file.txt

To see a list of files which would be added, but not actually add them to the repo, use the -n option:

hg add -n

Deleting Files From the Repo

hg remove ...

If you forget to rename a file with using Hg’s rename command and rename a file directly with, say, Windows Explorer, then you will need to tell Hg about it. The -A option to the rename command allows this. Let’s say you directly renamed a-file.txt to b-file.txt. To tell Hg about this, use this command:

hg remove -A a-file.txt b-file.txt

Unlike with adding files to a repo, you must explicitly tell Hg that you have deleted a file from a repo. In earlier versions, Hg did detect when a repo file was no longer in the working directory and therefore automatically stopped tracking it. In practice, this proved to be too easy to accidentally delete a file and have Hg silently remove the file from the repo on the next commit command.

Renaming Files in the Repo

hg rename a-file.txt b-file.txt

If you forget to rename a file with using Hg’s rename command and rename a file directly with, say, Windows Explorer, then you will need to tell Hg about it. The -A option to the rename command allows this. Let’s say you directly renamed a-file.txt to b-file.txt. To tell Hg about this, use this command:

hg rename -A a-file.txt b-file.txt

Interestingly, when renaming a file, Hg actually copies the source file to the destination file and then marks the newly copied file (the destination file) as added, and the copied-from file (the source file) as removed. This allows Hg to keep the file history for the source file in tact and to track the destination file as a copy of the original, now removed, file.

Committing Changes

Once you have modified, added, or removed files from the repo, you must commit those changes to the repo.

hg commit -m "..."

Pushing Changes to Another Repo

hg outgoing http://hg.example.com/some-project

then

hg push http://hg.example.com/some-project

Reverting Changes to the Repo

If you make a mistake to your repo you can use the revert command to back out those changes. If you mistakenly add, remove, copy, or rename a file and wish to undo that change, simply use the revert command against the file(s) and it will be as if you had never made the change. You may only revert changes that have not yet been committed.

If you have edited a file and want to back out those edits, and if you have not done a commit since those edits were made, you can also use the revert command to restore the file to how it appears in the parent of the working directory. Modified files are saved with a .orig extension before reverting, unless the --no-backup option is used on the revert command.

Here are the conditions under which the revert command will operate, as per the Mercurial: The Definitive Guide book:

    • If you modify a file, it will restore the file to its unmodified state.

    • If you hg add a file, it will undo the “added” state of the file, but leave the file itself untouched.

    • If you delete a file [from the file system] without telling Mercurial, it will restore the file to its unmodified contents.

    • If you use the hg remove command to remove a file, it will undo the “removed” state of the file, and restore the file to its unmodified contents.

Note: If you want to revert the repo to a previous rev then you most likely want to use the update command.

Rolling Back Changes

If you do a commit by mistake, you can simply use the rollback command to undo the commit and remove all history of the erroneous commit from the repo.

The rollback command is just as effective if you do an erroneous pull, import, push (to the same repo), and unbundle.

However, once you have pushed your changes to another repo, the rollback command becomes ineffective. For example, if you push a changeset to another repo, then roll it back, then pull from the repo you pushed to, the changeset you thought you just rolled back will reappear in your repo.

There is a note in the Mercurial: The Definitive Guide book that describes a way to roll back pushed changes:

If you absolutely know for sure that the change you want to roll back is the most recent change in the repository that you pushed to, and you know that nobody else could have pulled it from that repository, you can roll back the changeset there, too, but you really should not expect this to work reliably. Sooner or later a change really will make it into a repository that you don’t directly control (or have forgotten about), and come back to bite you.

Lastly, the rollback command can only be used once. Once you do a rollback, you can’t rollback again until you perform another commit or pull.

Next Steps

Had enough with the command line? Have no fear, simply install TortoiseHG and you’ll have a great set of Hg tools on your Windows Explorer context menu. If you use Visual Studio, the VisualHG plugin works great.

However, the command line can be quite efficient to do your Hg work with. I am partial to Cygwin and used it for every command example shown on this page.

Branches

Parallel development. New features. Bug fixes. Experimental code. All of these require the ability to branch the repo so that these various activities can occur without creating total chaos in the source code. Hg handles these simultaneous branches with ease.

Tags

The special tag name tip always exists and always refers to the changeset most recently added to the repo.

If you use version numbers to track your releases, you might tag the current branch as v2.4.3 as follows:

hg tag v2.4.3

To retrieve the repo as it was when this tag was created you could use the update command:

hg clone -U main local-copy

cd local-copy

hg update v2.4.3

This will update the local copy’s working directory to the changeset (rev) associated with the v2.4.3 tag.

Tags can be deleted:

hg tag --remove v2.4.3

and can be changed:

hg tag -f -r 123 v2.4.3

In this command, tag v2.4.3 will now point to changeset rev 123.

You may also create local tags, tags which are in your copy of the repo only. They are stored in the file .hg/localtags—which is not tracked in the repo—and can be useful to store comments. You might make a note that “The frob bug is in this rev.” like so:

hg tag "The frob bug is in this rev."

Branching

Once you have a released version, you might want to create a stable branch of the repo:

hg clone -rv2.4.3 main stable

Developers can then close this stable branch and add bug fixes to it. To bring those bug fixes back into the main branch, simply do this:

cd main

hg pull ../stable

hg merge

hg commit -m "Bring in bug fixes from stable branch."

You might start to work on a new feature which is destined for a new future release of the software (we’ll call it “feature-1”) so just like with the stable branch you could make a branch for this new feature:

hg clone -rv2.4.3 main feature-1

In this example, you are going to develop the feature-1 enhancements from the v2.4.3 code base.

Once the development of the feature is at a state where it is ready to be added the master branch, just pull then merge from the master branch into the feature branch, then push back up to the master branch.

Named Branches

TBS.

TortoiseHG

TortoiseHG provides a GUI interface to Hg along with additional functionality that enhances the use of Hg.

After installing TortoiseHG, the first thing to do is to configure it. Right-click on your desktop background then choose TortoiseHGGlobal Settings. The Settings dialog that is displayed is simply a GUI wrapper around the mericurial.ini file described above. In fact, you can click the Edit File button and the file will be brought up in Notepad; clicking the Reload button will reset the GUI to match and changes that have been made to the file since the GUI was started.

The global settings are those settings that will be used by default in all of your repos. These settings can be overridden for a repo, but we’ll concentrate on these global settings first. Go to the Commit page and then put something in the Username field. The username is a free-form field where you put something to identify the changes you make to your repos. You might also want to set kdiff3 as your Three-way Merge Tool and Visual Diff Tool in on the TortoiseHG page.

If you would like TotoiseHG to do an update, detach, or rebase automatically after every pull, you can set this in the After Pull Operation option on the Synchronize page. You can also set up often-used repo paths on this page. I also like to set my fonts to Consolas in the Custom fonts option on the Font page.

To change any of these settings and make them specific to a repo just browse to your repo’s directory with Windows Explorer and right-click on it, then choose TortoiseHGRepository Settings. You will be in the same settings window as just described, but the settings shown here reflect those stored in the repo settings file (.hg/hgrc) as opposed to your user global settings that are stored in your mercurial.ini file. Go ahead and change any repo-specific settings that you’d like.

TortoiseHG includes a program called hgtk which contains the same set of commands as the hg program described above, but these commands provide a GUI interface to the standard Hg commands. For example, as shown above you use the hg status command to see that status of your repo. With TortoiseHG you can see the same information in a graphical interface with this command:

hgtk status

Another way to get to this dialog is to right-click in a repo directory and select View File Status from the TortoiseHG menu.

The following table summarizes a few of the equivalent commands.

Other hgtk utilities:

hgtk datamine

hgtk guess

hgtk hignore

hgtk mpatch

hgtk recovery

hgtk repoconfig

hgtk shelve

hgtk userconfig

hgtk vdiff

Some TortoiseHG windows display a list of files, for example the status and commit windows. This file list has a column titled st and you’ll see the same list of letters in that column that Hg uses in it’s file status display (see the Making Changes section, above). There is one additional letter that TortoiseHG can display for a file and that is S which indicates a dirty subrepository that needs to be committed. At the bottom of the file list is a control labeled View 'MAR?!' which is collapsed by default. If you expand this control you will see a checkbox for each status letter allowing you to filter the file list.

The file list also has a column named ms which indicates the merge state of the file. If a merge has not been done, or if a merge has been done and the file has no conflicts, then this column will be blank. If a merge has been done but a commit has not yet been done then this column will have either an R to indicate the file had a conflict but that conflict has been resolved, or a U to indicate a file that still has an unresolved conflict.

Another nice feature of the file list is that when that file list has focus (click on one of the file names) you can then just start typing letters to select the first file name that matches what you have typed.

Color Fix

Some TortoiseHG windows display yellow text on a white background making the text pretty much impossible to read. This has been reported and the work-around is documented here:

https://bitbucket.org/tortoisehg/stable/issue/1627/yellow-text-on-white-background-not

Just edit your mercurial.ini file and add this:

[color]

log.changeset = red

VisualHG

TBS.

Hg With Eclipse

TBS.

Maintenance

Backup

The following command will create a full snapshot of the specified repository into the directory some-project.backup without checking out a working directory after the clone completes. The backup directory can then be copied to disk or tape.

hg clone -U http://hg.example.com/some-project some-project.backup

References

Related Tools

    • Mercurial—Distributed source code management tool.

  • TortoiseHG

    • VisualHG—Mercurial Source Control Plugin for MS Visual Studio

    • kdiff3—Compare and merge up to three files at once.