Hg Guest Repo
Extension for enterprises needing to handle modules and components
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
Guest repositories are administered using the two files .hgguestrepo and .hggrmapping. These files are in the INI format used by Mercurial.
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.
--local flag causes the .hggrmapping and .hgguestrepo file in the working directory
to be used.
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.
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.
echo "lib-python_interface = ssh://user@remote-host:/python/python_interface" > .hggrmapping
In this case, we are mapping the repository on the remote server to the local folder lib/python_interface.
Now we have set up the .hgguestrepo file with our mapping along with a branch or revision to point to:
echo "lib/python_interface = lib-python_interface default" > .hgguestrepo
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.
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.
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.
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.
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>
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:
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:
If present, the following keys are also valid in the schema
bookmarks tags current_bookmark changed
The absence of these keys in the JSON indicates that the guestrepo does not have any of these attributes.
List the outgoing changes for all guestrepos.
List the incoming changes for all guestrepos.
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 parsing configuration files and resolving remote paths will cause guestrepo to abort before attempting any operations.
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.
The guestrepo extension has an option to use multiple threads to improve performance in I/O bound situations.
Unresponsive remote operations may cause guestrpo to hang indefinitely.
- Changeset identifiers in the .hgguestrepo file cannot contain spaces
- Convert script could be improved to allow both guestrepos and subrepos
- No warning on modified/uncommited guestrepo files
Logilab hosts a Guestrepo mailing list at:
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.
Schweitzer Engineering Laboratories, Inc. 2350 NE Hopkins Court Pullman, WA 99163 - USA
Contributors: Ben Smith