#pragma section-numbers 3
== Forest Extension ==
/!\ '''This third-party extension does not appear to be actively maintained. Consider using [[subrepos|subrepos]] instead.'''
'''This extension is not being distributed along with Mercurial.'''
''Author: Robin Farine''<
>
''Maintainer: Simon Law ''
Repository: https://bitbucket.org/gxti/hgforest
''Old repository'': http://hg.akoha.org/hgforest/
Compatibility: Mercurial 1.x
(There's [[http://www.bitbucket.org/pmezard/hgforest-crew/overview/|another version]] that should also work against post-1.0 releases.)
'''Note:''' The snapshot file is undergoing a bit of refactoring. But new versions of Forest should be able to read old ones, and they are not required anymore for most uses.
<>
=== Overview ===
The Forest extension allows operations on trees with nested Mercurial repositories, called forests. Those to some degree correspond to multi-project CVS/Svn/... repositories.
The extension defines some new commands, which work on the whole tree of repositories instead of working on single directory - {{{fclone}}}, {{{fpull}}}, {{{fpush}}}, {{{fstatus}}}, {{{fupdate}}}. It also adds own specific commands: {{{fseed}}}, {{{fsnap}}}, {{{ftrees}}}.
'''ToDo: old description claimed that status and update work recursively, it does not seem to be a case? Or is it just a bug?'''
The forest extension brings one new concept - a ''snapshot file''. This file represents state of a forest at a given time
'''ToDo: detailed explanation what exactly is the snapshot file'''
=== Enabling the extension ===
Configure your .hgrc to enable the extension by adding following lines:
{{{
[extensions]
hgext.forest=
# or, if forest.py is not in the hgext dir:
# forest=/path/to/forest.py
}}}
Some additional configuration can be done using the '[forest]' stanza in your configuration file:
{{{
[forest]
# will nested repositories directly under a .hg directory be skipped (0|no|false) or not (1|yes|true)?.
# The default value is 0. (don't skip them)
walkhg = (0|no|false|1|yes|true)
}}}
'''ToDo: does walkhg=true truly mean that .hg is NOT walked? It is crazy....'''
=== Usage ===
Below some typical examples of how the extension can be used.
==== Creating a forest from scratch ====
Forest is just a mercurial repository containing some other mercurial repositories.
{{{
mkdir forestdir forestdir/subproject1 forestdir/subproject2
cd forestdir
# Initialize mercurial repo for the forest itself
hg init
# Initialize subproject repos
cd subproject1
hg init
cd ../subproject2
hg init
cd ..
}}}
We have a forest containing two subprojects. Of course new subprojects can be added at any time in the same way.
==== Creating a forest on top of existing repositories ====
Let's consider more realistic example - we want to bind as forest some already existing repositories. Then there are
two options. To create the forest in new location, just initialize repository there and clone subprojects into
subdirectories:
{{{
mkdir forestdir
cd forestdir
hg init
# To keep the same name (here - somelib)
hg clone /somelib
# To change name
hg clone /somelib sublib
}}}
Instead of cloning, one can just move the directories (this preserves working dir state).
One can also build forest in existing directory. Let's say we have mercurial repositories in $HOME/someproject/subproject1
and $HOME/someproject/subproject2. Then bare
{{{
cd $HOME/someproject
hg init
}}}
creates the forest in $HOME/someproject.
==== Cloning existing forest ====
To clone a forest use {{{fclone}}}. It works just as normal clone (the same URL syntaxes are recognized).
For example:
{{{
hg fclone /some/existing/forest new_forest
# Remote syntax should work too
hg fclone ssh://some.machine/some/existing/forest ./forest
}}}
'''ToDo''': What if one isn't already in a directory where {{{[extensions] hgext.forest=}}} is set?
==== Building cloned forest on top of already cloned repositories ====
'''ToDo: describe''' (casus when I have machineA:devel/proj1,
machineA:devel/proj2, machineB:devel/proj1, machineB:devel/proj2 and want
to forestize devel directory)
==== Verifying status of the existing forest ====
To display the status of the forest use
{{{
cd forestdir
hg fstatus
}}}
This will display aggregated status of all subprojects (and the main forest repo itself).
Note: you must issue this command while being in main forest directory, issuing
it in subproject dir will bring just the status of this dir, this is some limitation
of the extension.
To list just the roots of repositories (forest contents), use:
{{{
cd forestdir
hg ftrees
}}}
(as above, issue it in main forest directory)
==== Developing within forest ====
Actions like add/delete/commit/... work as usual - cd to the subproject you want to develop, hack there, add/remove/commit there. There are no
global shortcuts to execute such commands on a forest as a whole.
Note: beware of using add/delete for subproject files while being in the top-level forest directory. If you do sth like
{{{
cd forestdir
hg add subproject/file1.txt
}}}
then the file will be marked for addition for the forest repository, not for the subproject repository! This is never something you would like to do...
==== Pulling, pushing and updating ====
One can of course use standard pull, push, and update commands while working in individual forest subprojects,
they work as usual.
To pull, push and update whole forest at once, use {{{fpull}}}, {{{fpush}}} and {{{fupdate}}}.
To use fpull and fpush we need a snapshot file. For the simplest case, let's create the file
which points to the tips of subprojects:
{{{
cd forestdir
hg fsnap -t > snapshot.txt
}}}
(you may take a look at snapshot.txt, this is simple textual file which lists subprojects)
Then you can try
{{{
cd forestdir
hg fpull snapshot.txt default
hg fpush snapshot.txt default
}}}
In case of the snapshot built with -t option (pointing to tips) those commands just push or pull
all forest subprojects and the main forest directory.
Update can be performed similarly
{{{
cd forestdir
hg fupdate snapshot.txt
}}}
but here, when we use tips, snapshot is not necessary, alternatively one can issue
{{{
cd forestdir
hg fupdate --tip
}}}
Note: you can alias remote forests by creating aliases in top level forest mercurial repository.
'''ToDo''': or maybe aliases must be defined both on top and in subdirs? And what if there is mismatch, or somewhere we lack some alias?
==== Partial clone ====
Forest subproject is still normal mercurial repository. So it can be cloned as usual.
{{{
# Clone only subproject1 without cloning the rest of the forest
hg clone forestdir/subproject1 subproject1_branch
}}}
==== Using snapshots ====
'''ToDo''': some explanation what non-tip snapshots are used for, how should one
operate on them etc is desperately needed.
With the {{{fsnap}}} and {{{fseed}}} commands it is possible to create a forest that can be pushed to a shared repository, and subsequently cloned by others. This allows you to have several repositories on a server, with a separate forest that collects them. Developers can then choose to clone individual repositories, or the entire forest. The initial setup might look like this, assuming an empty Mercurial repository named {{{forest}}} exists on {{{}}}:
{{{
hg clone /forest
cd forest
hg clone /proj1
hg clone /proj2
hg fsnap -t > snapshot.txt
# some edits of snapshot.txt may be needed, see below
hg add snapshot.txt
hg ci -m "Adding snapshot file"
hg push
}}}
''It may be necessary to replace the {{{None}}} in the snapshot file with {{{tip}}}; it didn't work for me (Nathan) otherwise.''
With the initial setup complete, other developers can now perform the following actions to clone the forest and all of its child projects. This is despite the fact that the shared forest does not actually contain any child repositories.
{{{
hg clone /forest
cd forest
hg fseed snapshot.txt
}}}
Having non-tip revision identifiers in snapshot.txt can be a hint to others (i.e. {{{fseed}}}) that this Hg repository needs this module here with this revision, as the tip revision may have new, backwards-incompatible changes. However, there is no command to "restore" the state of the modules to the one defined in snapshot.txt if changes were made (such as running {{{hg up}}}) on the module, save for going into each modules and do an hg checkout with the "correct" revision id.
=== See also ===
* NestedRepositories for a proposal to integrate this extension into core Mercurial
----
CategoryExtensionsByOthers