Question

Take this repo structure:

Server (main repo)
    ProjectA (subrepo)
    SharedLibrary (subrepo)

Client (main repo)
    ProjectB (subrepo)
    SharedLibrary (subrepo)

SharedLibrary points to the same folder (this is Windows), it is not a separate copy/clone under each main repo.

Assume each main repo has two changesets, 0 and 1(tip). We start with both main repos at the 1(tip) revision.

Take the following steps:

  1. In the Client repo, update to changeset 0. This updates ProjectB and SharedLibrary to earlier but matching revisions.

  2. ProjectA is now out of sync with SharedLibrary. Step 1 updated SharedLibrary to an older revision than what is required for ProjectA, which is still at 1(tip).

  3. In the Server repo, we want to update SharedLibrary to the correct revision for ProjectA, so we run hg update tip in the Server main repo. This does NOT update SharedLibrary to the correct revision. It leaves SharedLibrary in the same revision as step one.

  4. Go back to Client repo and run hg update tip. SharedLibrary is now at the correct revision for both ProjectA and ProjectB.

It appears updating in the Server repo isn't checking to see if SharedLibrary is at the correct revision. Is this behavior expected, or is there a better way to do this?

Was it helpful?

Solution

What you're seeing is that hg update will merge when the working copy is dirty. Let me explain it with a normal file first. Imagine you have a repository with two revisions. I'm at revision 0 and foo is modified:

$ hg diff
diff --git a/foo b/foo
--- a/foo
+++ b/foo
@@ -1,3 +1,3 @@
 first
 second
-third
+third line

You see I changed the third line. Now, if I run hg update 1 the modification will be merged with how foo looks like in revision 1:

$ hg update 1
merging foo
0 files updated, 1 files merged, 0 files removed, 0 files unresolved

The modification is still there and foo is still dirty:

$ hg diff
diff --git a/foo b/foo
--- a/foo
+++ b/foo
@@ -1,3 +1,3 @@
 first line
 second
-third
+third line

When you did

$ cd client
$ hg update 0

you made sure that SharedLibrary was updated to the revision described in .hgsubstate for revision 0 in client.

When you then went to server, the SharedLibrary subrepo was no longer at the revision mentioned in .hgsubstate at revision 1 in server. In other words, the working copy in server was dirty — a hg commit would result in a new .hgsubstate file being committed.

Mercurial preserves this modification when you hg update in server and this is why you see that SharedLibrary wasn't made current when you updated. Use hg update -C if you want to make the subrepo current.

The idea behind this feature is that you can test different versions of your subrepos. When hunting for a bug, it's often necessary to update the main repository to older versions and so it's convenient that the modifications to the subrepo revisions stay in place.

Note that the confusing situation you're seeing isn't caused by how you've re-used the same subrepo twice. However, as Lasse points out, the real way to use a single subrepo in multiple projects is to put it once on your server and then clone it into your local clones — once per clone.

I've described this in more detail, but briefly you should follow the recommendations and maintain an identical structure on both server and clients. Use SharedLibrary = SharedLibrary paths in your .hgsub file to maintain this structure. Link the repositories together on the server-side (see my other answer) to make a single repository appear under several different URLs/directories.

When starting out with subrepos, then beware of tight coupling. If you can, then try to use a proper dependency management system such as Maven+Nexus for Java based projects.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top