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 .hggrconf and .hggrsnap. These files are in the INI format used by Mercurial.
Each guest repository must have a remote path defined in the .hggrconf file to successfully push or pull.
Remote paths are referenced by assigning to each path a unique name (visible only within the namespace of guestrepos).
The .hggrconf file lists remote paths in the following INI format:
[name] pulluri = remote-path
If a remote repository is moved, the path referenced by a name can be updated to point to the new location.
Example .hggrconf file:
[remoteid] pulluri = http://host/path/to/repo [remoteid2] pulluri = /path/to/repo2
The .hggrconf file also specify the location of the guest relative to the root of the parent repository
[remoteid] pulluri = http://host/path/to/repo layout = deepeer/path/mygr
The .hggrconf file used for any operation is the .hggrconf file at the most recently committed head of the current branch. Using the most recent revision of the .hggrconf file keeps the guests of previous revisions pointed to the correct location.
--local flag causes the .hggrconf and .hggrsnap file in the working directory
to be used.
The .hggrsnap file defines guest snapshots by specifying two things:
The .hggrsnap file lists guest repositories in the following INI format:
location = changeset-id
Example .hggrsnap file:
path/to/guest = csid path/to/other/guest = csid
If the the directory of the guest repository exists, it must contain a mercurial repository.
Currently guestrepo is only being tested on the Python 2.7 line. If earlier Python testing is desired, please contact the maintainer.
34c213eba276 of guestrepo tests pass with hg versions...
Tests fail on flavor text for
Internal hg api changes at
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.
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 .hggrconf and .hggrsnap files. To add an existing remote repository as a Guestrepo, it needs to be added to each of these files. The .hggrconf file specifies the mapping between the remote repository and where it should be in relation to the shell repository.
echo "[lib-python_interface]\npulluri = ssh://user@remote-host:/python/python_interface\nlayout=lib/python_interface" > .hggrconf
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 .hggrsnap file with our mapping along with a branch or revision to point to:
echo "lib/python_interface = default" > .hggrsnap
A hg grpull command will now let you pull down the latest version of the lib-python_interface guestrepo that is on the server.
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 .hggrconf and .hggrsnap to the repository Verify that .hggrconf and .hggrsnap are correct before removing .hgsub and .hgsubstate
The .hggrconf file should have the same mapping between your guestrepo and its remote path that is in the .hgsub file. Similarly, the .hggrsnap file should have the same mapping along with the revision that the subrepo was pointing to.
To finish converting the repo,
hg add the .hggrconf and .hggrsnap
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 .hggrconf and .hggrsnap 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 .hggrsnap 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 --clean option allows you to "disable" (by running the "hg up null" command) any non-guest repository found under the shell directory. This allows the user to ensure the shel repository is really in the state described by the .hgguestrepo file (on can also purge each of theses non-guest repositories by adding the --purge option). This is usefull for example to run tests (in a controller environment) in a setup where there are several branches in the shell repository, with different set of guest repositories referenced among the branches.
The freeze command outputs the state of the guest repositories to the .hggrsnap file. It uses same format as the .hggrsnap file, but only outputs the absolute changeset hash.
"local_dir" = "changeset hash"
Freeze can be used to generate an .hggrsnap file for a release:
$ hg branch Release $ hg grfreeze $ hg commit -m Release
Freeze can also save a .hggrsnap to a particular file using the --file option:
$ hg grfreeze --file <output_file>
Print the exact changeset of all guests to stdout with information about the corresponding guest repositories (the local directory and name).
The state command outputs the state of the guest repositories to standard out. It uses an INI format:
local_directory = gest_name changeset_id
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.
Alphabetical by last name:
Tom Benda Sietse Brouwer Mathieu Clabaut Pierre-Yves David David Douard Mohankumar Gurusamy Alain Leufroy Paul Nathan Daniel Norris David Sankel
Guestrepo: A Mercurial Extension for the managing of components
Copyrights belong to respective holders: initial development is (C) SEL 2012-2013; contributors took up the torch from there.
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.
Contact information for S.E.L.:
Schweitzer Engineering Laboratories, Inc. 2350 NE Hopkins Court Pullman, WA 99163 - USA
Other contact information to be found in the changelogs.