Mercurial: Exporting a Revision Using Archive

Most of the work of transitioning from one version control system to another is figuring out the mapping from the jargon of the old one to the new. In Subversion, you could give someone a copy of a certain version using the export command. The copy thus created would be free of any repository information.

The corresponding operation in Mercurial is called archive. This creates an unversioned archive of a certain revision of the repository. Creating an archive of the current revision of your repository to give to a colleague named Ram is as easy as:

$ hg archive ../Copy-For-Ram

Another cool feature of the archive command is that it can create archives in compressed formats like zip. For example, to create a zip archive of the above:

$ hg archive Copy-For-Ram.zip

The hash of the revision being exported can be used in the name of the destination directory or file. For example:

$ hg archive Copy-For-Ram-%h.zip

The above command will create a file whose name might be Copy-For-Ram-72f497079285.zip, where 72f497079285 is the hash of the exported revision.

(Thanks to Rudi and Paul on StackOverflow for these tips.)

Tried with: Mercurial 1.9.2

Mercurial: Waiting for Lock

Problem

Mercurial repositories can sometimes be left in a locked state. A lock is created whenever a client is connected to a repository. But, this lock is not removed if the client got disconnected, say over the network. If any client now tries to change the repository (say push changes), Mercurial complains that it is waiting for the lock.

Here is an example:

P:\Foobar>hg push
pushing to Q:\FoobarRep
waiting for lock on repository Q:\FoobarRep held by 'Computer42:9999'

In this example, Mercurial is complaining that a lock is still being held by a client from the computer named Computer42 over port 9999.

Solution

Delete the lock file in the .hg\store directory of the repository. In the example above, delete the file Q:\FoobarRep\.hg\store\lock

Mercurial: Waiting for lock

In some rare cases, you get this error when pushing changes to a Mercurial repository:

$ hg push
pushing to D:\HgReps\Foobar
waiting for lock on repository D:\HgReps\Foobar held by ”
interrupted!

A few solutions to this problem:

  • Figure out the process holding a lock onto the repository and kill it.
  • If the above does not work, delete the file .hg/store/lock in the repository D:\HgReps\Foobar

Tried with: Mercurial 1.6 on Windows 7

Mercurial: Collaborating on a Windows Network Using Shares

You might feel the need to publish Mercurial repositories in a central location and collaborate using that. This is really useful when:

  • You are working from 2 or more workstations or laptops.
  • You are in a small team and there are 2 or more people working on the project.

Publishing a Mercurial repository in a central location enables different people or computers to push and pull from it. There are a few common ways to do this:

  • hg serve: Real easy and quick to setup with simple features.
  • SSH: Not as easy on Windows as on Linux. OpenSSH server is the most common option, but it comes with Cygwin and all its problems.
  • HTTP: Requires quite a lot of configuration on Windows.
  • SMB: If you are on a Windows network, your computers or team is small in number and your needs are simple, then using a Windows share is very compelling!

You can start publishing Mercurial repositories using Windows shares in just a few minutes:

  1. Designate one computer as the central repository server. Let us call it A. It can be the workstation of the one of the team members, it does not really matter. Other computers, B and C, should be in the same Windows network as A.
  2. Create a directory on A, say D:\HgReps and move all your current repositories to it. New repositories in the future should also be created here.
  3. Share the directory on A, so it becomes \\A\HgReps. Give only the team members who use A, B and C access to read and write to this share. You could also give read access to other users who you wish only pull from A. These access permissions should be very easy to configure if you are in a well set up Windows domain.
  4. Point all the current working directories on A, B and C to push and pull from \\A\HgReps. To do this, open the .hg/hgrc file in each working directory and edit it so it points to A. For a project named Foobar, the .hg/hgrc file looks like:
    [paths]
    default = \\A\HgReps\Foobar
    

All this setup is ridiculously easy to do for a small team and everything just works without much configuration. Another nice side-effect is that you can backup the D:\HgReps on computer A easily and grab all the team’s commits.

Mercurial: Merging Branches

Mercurial users keep insisting that you do not really need to create actual branches to work. But, if you are one of the few who likes to do this, merging branches is just as easy too. I use TortoiseHg, but the equivalent command-line options are just as obvious.

  1. Consider branches A and B. You wish to merge B to A, so that work on A can continue. Typically, A might be the default branch and B can be a feature branch.
  2. Finish, test and commit all the files on both branches A and B.
  3. Open Repository Explorer. Update the working directory to branch A. This can be done by choosing the head of branch A, right-click and choose Update.
  4. Choose the head of branch B, right-click and choose Merge with. Tip of branch A will automatically be chosen as the target for the merge. Click Merge.
  5. Mercurial will try to merge the files automatically as much as possible. For the files with merge conflicts, it will pop up KDiff3 windows so you can pick the changes you want merged. The conflict windows are displayed sequentially, finish one and the next one is displayed.
  6. Settle all the conflicts and your merge is done! Branch B should be connected to branch A nicely in the graph displayed in Repository Explorer now.

Mercurial: Switching to a Branch

To switch the working set of a Mercurial repository to a branch use the hg update command:

$ hg update BRANCH_FOOBAR

The only time I really use this is after cloning a Mercurial repository. After a clone the working set of the repository is always set to the default branch. I need to switch to work on a different branch. To view the available branches in a Mecurial repository use:

$ hg branches

Mercurial: Repository with No Working Copy

Mercurial engenders an easy distributed working style. But, for important projects you might like to have a central repository that everyone pushes to and is backed up regularly. Since this central repository is backed up, it is irritating to have a working copy of files in it (which is the default behavior of Mercurial).

To have a central repository with no working copy, clone your existing central repository using the --noupdate (or -U) option:

$ hg clone -U FoobarCentralRep FoobarNewRep

Let everyone working on projects clone from this new repository and push their changes back to it:

$ hg clone FoobarNewRep MyFoobarExperiments

Mercurial: Branching

Despite the allure of working in a distributed fashion in separate repositories and later merging the changes together, there are genuine cases when working in isolation in a separate branch is necessary. This kind of traditional branching is just as easy as everything else in Mercurial.

For example, assume we are working on a Car project. It has only one branch, the default. At some point in time we decide to spin off a separate project from the car to work on a fuel efficient car. This project may or may not ever merge back to the main Car project. Hence, branching instead of cloning is the better option for this.

First we clone the existing repository:

$ hg clone Car EfficientCar

To see the current branch in the new repository:

$ hg branch
default

To create a branch for the fuel efficient car from the default branch:

$ hg branch EfficientCar

We need to commit this new branch before we do anything else:

$ hg commit

We can now work on the EfficientCar branch independent of changes happening in the default branch. When we decide to push changes in this branch (or repository) to the parent (central) repository, it aborts with an error:

$ hg push
pushing to Car
searching for changes
abort: push creates new remote branches: EfficientCar!
(use 'hg push --new-branch' to create new remote branches)

This push introduces a new branch in the parent repository, so Mercurial is warning the user about this addition. We are okay with this, so we push again, this time with force:

$ hg push --new-branch

Any number of branches can be created at any level like this easily in Mercurial. For example to experiment on a solar car we branch off from EfficientCar:

$ hg branch
EfficientCar
$ hg branch SolarCar

Mercurial: hgignore

There might be certain files or kinds of files you might want Mercurial to ignore or not track. For example, the *.obj and *.exe files generated by the Visual C++ compiler. Ignoring such files also reduces the visual clutter or information overload in the output of commands such as hg status.

To tell Mercurial to ignore certain files (say *.obj and *.exe files), create a .hgignore file in the root of your repository and add the following text into it:

#-------------------------------------------------------
# .hgignore: Files that Mercurial should ignore
#-------------------------------------------------------

# Use glob syntax
syntax: glob

# Ignore object files
*.obj

# Ignore executables
*.exe
#-------------------------------------------------------

Note that the .hgignore file needs to be added and committed into the repository as well:

$ hg add .hgignore
$ hg commit