Hg Guest Repo

Many products, multiple projects within those products, multiple
developers within those projects, multiple branches per developer

Source code shared in a multiplicity of configurations

Third party code (possibly patched on some branches)

A given module may have multiple versions going into the same product

Hg subrepos do not handle the sharing of components well, due to the
recursive merge from the top (super) repo and requirement to lock at a
specific version.

Guestrepo's goal is to overcome these limitations.

The guestrepo extension does not change any existing Mercurial behavior.
It only adds new commands.

To enable the extension after installing on Linux, add the following
to your ~/.hgrc.

[extensions]guestrepo=

Windows users will have to specify

[extensions]guestrepo=c:\absolute\path\to\guestrepo

Administration

Guest repositories are administered using the two files .hgguestrepo and
.hggrmapping. These files are in the INI format used by Mercurial.

Remote Paths

Each guest repository must have a remote path defined in the .hggrmapping
file to successfully push or pull.

Remote paths are referenced by assigning a each path a unique name
(visible only within the namespace of guestrepos).

The .hggrmapping file lists remote paths in the following INI format:

name = remote-path

If a remote repository is moved, the path referenced by a name can be
updated to point to the new location.

Example .hggrmapping file:

remoteid = http://host/path/to/repo
remoteid2 = /path/to/repo2

The .hggrmapping file used for any operation is the .hggrmapping file at
the most recently committed head of the current branch.
Using the most recent revision of the .hggrmapping file keeps the guests of
previous revisions pointed to the correct location.

The --local flag causes the .hggrmapping and .hgguestrepo file in the working directory
to be used.

.hgguestrepo

The .hgguestrepo file defines guests by specifying three things:

location: The location of the guest relative to the root of the parent
repository.

remote id: The name of a remote path defined in the .hggrmapping file.

changeset id: A Mercurial identifier e.g., a tag, bookmark, changeset
hash, branch, or other future identifier resolvable to a
single changeset.

The .hgguestrepo file lists guest repositories in the following INI format:

location = remote-id changeset-id

Example .hgguestrepo file:

path/to/guest = remoteid csid
path/to/other/guest = remoteid2 csid

If the the directory of the guest repository exists, it must contain a
mercurial repository.

HOWTO

Setting up the shell

Guestrepos should be added to a single top-level repository that
contains the .hgguestrepo and .hggrmapping files. This is known as the
shell repository and is what will be cloned down by anyone wanting to
work on a project using Guestrepos.

Creating a New Project Using Guestrepos

To create a new project, you first need to set up a shell repository.

cd shell
hg init
touch README

You now need to set up your .hgguestrepo and .hggrmapping files. To
add an existing remote repository as a Guestrepo, it needs to be added
to each of these files. The .hggrmapping file specifies the mapping
between the remote repository and where it should be in relation to
the shell repository.

A hg grpull command will now let you pull down the latest version of
the lib-python_interface guestrepo that is on the server.

Converting a Project Using Subrepositories

If you are converting an existing project, then you already have a
top-level repository to use as a shell. In this case, all you have to
do is use the grconvert command to create the .hgguestrepo and
.hggrmapping files from your existing .hgsub file.

Suppose you have the following structure for your repository

my_project/
.hg
.hgsub
.hgsubstate
README
super_library/

In this case, super_library is a subrepository as defined in the
.hgsub file.

To convert this into a subrepository, simply run:

user@test_machine:/tmp/my_project$ hg grconvert
Do not forget to add .hgguestrepo and .hggrmapping to the repository
Verify that .hgguestrepo and .hggrmapping are correct before removing .hgsub and .hgsubstate

The .hggrmapping file should have the same mapping between your
guestrepo and its remote path that is in the .hgsub file. Similarly,
the .hgguestrepo file should have the same mapping along with the
revision that the subrepo was pointing to.

To finish converting the repo, hg add the .hgguestrepo and .hggrmapping
files to the shell repository and hg rm the .hgsub and .hgsubstate
files and then commit.

All of the guestrepo commands should now work.

Commands

Pull

hg grpull [guestrepo...]

Pull each guest repo from the location specified in the mapping file.
If any guest repo does not exist it is cloned and updated to the specified
changeset id in the .hgguestrepo file.
See sync for information on how guests are updated.
A pull to an existing repo will not update.

Pull is run recursively on guest repositories.

Push

hg grpush [OPTIONS] [guestrepo...]

Push each guest to the path specified in the mapping file.

Push is run recursively on guest repositories.

Passing the --local flag will use the .hggrmapping and .hgguestrepo files in the
working directory even if they have been modified.

Push is normally optimized to check to see if there are any draft changesets
before attempting to push to the remote repository. This can be overridden by
the --all flag. The --local flag also overrides this behavior since it is might
be necessary to push public changesets to a new repository.

Sync

hg grupdate [guestrepo...]

Update each guest repo to the changeset identifier in the .hgguestrepo file.
The changeset identifier can be a branch, tag, changeset hex, bookmark, or
any other identifier that can be given to Mercurial's update command.

A warning will be raised if a guest is updated to a branch with multiple
heads.

Update is recursive. If the update operation adds a new guest, it is
cloned to the newly added identifier.

Update will present an error and do nothing if there are local changes in any
guest repository.
This prevents the update from causing a merge with local changes.

Freeze

hg grfreeze

The freeze command outputs the state of the guest repositories to the
.hgguestrepo file. It uses same format as the .hgguestrepo file, but only
outputs the absolute changeset hash.

"local_dir" = remoteid "changeset hash"

Freeze can be used to generate an .hgguestrepo file for a release:

$ hg branch Release
$ hg grfreeze
$ hg commit -m Release

Freeze can also save a .hgguestrepo to a particular file using the --file
option:

$ hg grfreeze --file <output_file>

State

hg grstate

Print the exact changeset of all guests to stdout, as in .hgguestrepo.

The state command outputs the state of the guest repositories to standard out.
It uses same format as the .hgguestrepo file, but only outputs the absolute
changeset hash

State is essentially the freeze command directed to standard out rather than
.hgguestrepo.

State takes an optional flag --json that prints the state of the guest
repositories as a single JSON array. The schema is as follows:

[{"id":"<value>","path":"<value>","remote_path":"<value>"}]

Summary

hg grsummary

Summary presents a simple description of the state of the project: a column of
subdirectories, followed by the branch of the current changeset, followed by the
tags and bookmarks pointing to the current changeset, followed by a * if
modified.

local_directory (branch) [tags] [bookmarks] [*current bookmark] [*]

Summary takes an optional flag --json that prints the summary of the guest
repositories as a single JSON array. The schema is as follows:

The absence of these keys in the JSON indicates that the guestrepo does not have
any of these attributes.

Out

hg grout

List the outgoing changes for all guestrepos.

In

hg grin

List the incoming changes for all guestrepos.

Error Handling

One of the key defects in the user experience of subrepositories is
the invalid state that is occasionally maneuvered into and the
requirement for a guru to fix the user's state. This wastes time. We
claim it is better to have a globally inconsistent repository with the
ability to return to a consistent state than a globally consistent
and dysfunctional repository.

Errors that occur when operating on a guest repository do not cause other
operations to be aborted. At the end of operation all errors are reported along
with the current state of the repository and if it is 'sane' to use (i.e., not
left in an an aborted operation state).

Errors will be displayed on standard error, and all errors cause a
non-zero exit code.

Performance

The guestrepo extension has an option to use multiple threads to improve
performance in I/O bound situations.

Mailing List

LICENSE

Guestrepo: A Mercurial Extension for the managing of components

Copyright (C) 2012 Schweitzer Engineering Laboratories, Inc.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.