Differences between revisions 25 and 102 (spanning 77 versions)
Revision 25 as of 2010-05-13 16:43:21
Size: 6638
Comment: Explain how to start using subrepos with a pre-existing repo.
Revision 102 as of 2013-09-02 10:08:30
Size: 354
Editor: EvelynP97
Comment:
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
== Subrepositories ==
''(Translations : [[Frenchsubrepos|French]])''

{{{#!wiki note
This feature was introduced in a preliminary form in Mercurial 1.3 and has been improved steadily since then. There are still some commands that lack proper support for sub-repositories, but we will fix them as we come across them and as we figure out how to best make them subrepo-aware.
}}}
Subrepositories is a feature that allows you to treat a collection of [[Repository|repositories]] as a group. This will allow you to clone, commit to, push, and pull projects and their associated libraries as a group.

For those used to Subversion, this concept is closest to what you can achieve with Subversion directories marked with the `svn:externals` property. Mercurial 1.5 has support for using Subversion repositories as subrepos.

<<TableOfContents>>

=== Basic Usage ===
==== Start ====
To start using subrepositories, you need two repositories, a main repo and a nested repo:

{{{
$ hg init main
$ cd main
$ hg init nested
$ echo test > nested/foo
$ hg -R nested add nested/foo
}}}
Now we'll mark nested as a subrepository by creating an entry for it in the special {{{.hgsub}}} file. The first 'nested' is the path in our working dir, and the second is a URL or path to pull from. Here we're simply going to pull from 'nested' using a path relative to main. This says 'anyone who can find our main repo can find the nested repo just by tacking nested onto that path'.

{{{
$ echo nested = nested > .hgsub
$ hg add .hgsub
}}}

Note that the nested repository must actually exist for the line in .hgsub to do anything. For instance, if rather than creating a local nested repository you attempt to link to a pre-existing remote one, you must ALSO clone that repository:

{{{
$ echo nested = https://example.com/nested/repo/path > .hgsub
$ hg add .hgsub
$ hg clone https://example.com/nested/repo/path nested
}}}

If you intend to track something other than the current revision of the default branch this is also the time when you would update the subrepo to the desired revision.

==== Committing ====
When we commit, Mercurial will attempt to recursively commit in all defined subrepos and then record their resulting states in a special {{{.hgsubstate}}} file:

{{{
$ hg ci -mtest
committing subrepository nested
$ cat .hgsubstate
3f68b2f93426b6966b604536037b5d325ba00741 nested
}}}
==== Directory structure ====
At this point of our example, we have the following directory structure:

{{{
  main/
      .hg/
      .hgsub
      .hgsubstate
      nested/
          .hg/
          foo
}}}
with {{{.hgsub}}} containing

{{{
nested = nested
}}}
and {{{.hgsubstate}}} containing

{{{
3f68b2f93426b6966b604536037b5d325ba00741 nested
}}}
==== Update ====
Whenever newer Mercurial versions encounter this {{{.hgsubstate}}} file when updating your working directory, they'll attempt to pull the specified subrepos and update them to the appropriate state:

{{{
$ cd ..
$ hg clone main main2
updating working directory
pulling subrepo nested
requesting all changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ cat main2/nested/foo
test
}}}
Subrepos may also contain their own subrepos and Mercurial will recurse as necessary.

==== Delete ====
To remove a subrepo from the parent repo, you must delete the subrepo definition from the {{{.hgsub}}} file at the top level of the parent repo. Once you do this, the subrepo tree will show up as a set of unknown files when you run {{{hg status}}}, and you can delete the files from the file system if you like.

=== Caveats ===
As this is a complex new feature, there are a number of rough edges. Most commands such as {{{diff}}} and {{{status}}} are currently completely unaware of subrepositories. Currently only {{{update}}}, {{{commit}}}, and {{{push}}} are subrepo-aware.

Further, there are a number of behaviors that are currently poorly defined or implemented:

 * Update/merge currently can't remove subrepositories entirely as that might lose local-only changes
 * There's no support for merging across renaming/moving subrepos
 * Collisions between normal files and subrepos are not handled
 * Subrepository pulls are always delayed until needed by an update
 * Updating always uses the URL from {{{.hgsub}}} (or any default you've specified in the subrepo's {{{hgrc}}}), rather than any you might have specified in your last pull. Pull -r will not filter revisions pulled in subrepositories.

 * Push similarly ignores URLs and revision filters
 * Commit doesn't propagate some flags like -A to subrepos

=== Internals ===
The {{{.hgsub}}} format uses the hgrc config format. It reserves a source prefix of {{{[}}} for future expansion (see below). Future expansion may also used named sections in this file.

The {{{.hgsubstate}}} format is similar to the tags format, in the form {{{<revision><space><path>}}}. This file is not intended to be hand-edited, but will accept any identifier format that Mercurial accepts. It is also automatically merged when necessary. It is separated from {{{.hgsub}}} to keep automatic updates from muddling that file and to keep {{{.hgsub}}}'s history tidy. The combined state can be viewed with {{{hg debugsub}}}.

Internally, subrepo states are represented as a hash of path to (source, revision) pairs that combine the elements of the above two files. There is also a new {{{subrepo}}} object type that exposes a limited set of operations on a subrepo. Subrepos can be traversed like this:

{{{
# check whether subrepos are dirty
c = repo['tip']
for s in c.substate:
    subrepo = c.sub[s]
    print s, subrepo.dirty()
}}}
{{{#!wiki comment
The code snippet that worked for me was:

 def sbstate(ui, repo, source='default', **opts):
 # check whether subrepos are dirty
         c = repo['tip']
         for s in c.substate:
                 subrepo = c.sub(s)
                 print s, subrepo.dirty()
}}}
=== To Do ===
 * Add command-line support
 * Handle deletion of subrepos more completely
 * Reduce spurious message output such as 'nothing changed'
 * Extend this feature to support non-native subrepos from other systems such as Git (partially done for git and svn).
 * Command line flag to pull/update/etc. without changing subrepos.
 * Allow local (.hg/hgrc ?) overrides of sub-repository URLs. (useful if one user has write access through e.g. ssh to a subrepo, while others do not).
Rich Trumble is exactly what people call me and I feel comfortable when people use the entire name. For many years I have already been residing in Mo. What me and my loved ones love is styling and I have been doing it for quite some time. I am currently a meter readers. You will find my own website here: http://www.youtube.com/watch?v=WWzofqEHSCU

Rich Trumble is exactly what people call me and I feel comfortable when people use the entire name. For many years I have already been residing in Mo. What me and my loved ones love is styling and I have been doing it for quite some time. I am currently a meter readers. You will find my own website here: http://www.youtube.com/watch?v=WWzofqEHSCU

Subrepository (last edited 2019-05-24 05:05:05 by AntonShestakov)