[PATCH 1 of 3] subrepo: fix diff/status -S of added subrepo (issue3056)

Dov Feldstern dovdevel at gmail.com
Wed May 16 16:46:58 CDT 2012


# HG changeset patch
# User Dov Feldstern <dfeldstern at gmail.com>
# Date 1337203115 -10800
# Branch stable
# Node ID 52df9ecdec9b77cd3b333f4505cf14b0f22f230c
# Parent  7002bb17cc5eceb8c1ab792bdaf10bd96c08c8d8
subrepo: fix diff/status -S of added subrepo (issue3056)

When comparing revisions between which a subrepo was added (i.e., subrepo
doesn't yet exist in rev1, but does exist in rev2), diff/status -S should
report the new subrepo's files as newly added files (because, from the parent
repo's point of view, the contents of the new subrepo is new content). However,
until now, the subrepo's contents was not reported at all in the comparison of
rev1 and rev2.

The problem was due to the fact that when iterating over the subrepos in the
two revisions being compared, if at a given subpath there was no subrepo in
rev1, then we would return the subrepo for that subpath in rev2. This, however,
does not allow us to consistently show the differences going from rev1 -> rev2,
because we are now left with a set of subrepos which are from either rev1 or
rev2,and we have no way of knowing which it is.

The solution is that in the above case, we should use rev2 as a "helper
context" for deciding what *kind* of repository to return (we need to return a
subrepo, so that we will then be able to compare it with the matching subrepo
from rev2); however, the returned subrepo should be in the null state (which
reflects the fact that the subrepo didn't yet exist in rev1). Then, it can be
compared with the matching subrepo from rev2, and the comparison is still being
done in the right direction (rev1 -> rev2).

Note that this changeset only solves half of the issue --- the direction in
which subrepo was *added* between rev1 and rev2. The other direction (subrepo
*removed* between rev1 and rev2) will be treated in the next changeset.

This changeset also fixes some existing tests which until now were displaying
the incorrect behavior.

diff -r 7002bb17cc5e -r 52df9ecdec9b mercurial/context.py
--- a/mercurial/context.py	Mon May 14 13:25:42 2012 +0100
+++ b/mercurial/context.py	Thu May 17 00:18:35 2012 +0300
@@ -290,8 +290,11 @@
             if match.bad(fn, _('no such file in rev %s') % self) and match(fn):
                 yield fn
 
-    def sub(self, path):
-        return subrepo.subrepo(self, path)
+    def sub(self, path, helperctx=None):
+        '''return subrepo at path. If there is no subrepo at path, but
+        there is a subrepo at path in the provided helperctx, return
+        a subrepo of the type in helperctx, set to the null state.'''
+        return subrepo.subrepo(self, path, helperctx)
 
     def match(self, pats=[], include=None, exclude=None, default='glob'):
         r = self._repo
diff -r 7002bb17cc5e -r 52df9ecdec9b mercurial/subrepo.py
--- a/mercurial/subrepo.py	Mon May 14 13:25:42 2012 +0100
+++ b/mercurial/subrepo.py	Thu May 17 00:18:35 2012 +0300
@@ -247,17 +247,19 @@
             reporelpath(repo))
 
 def itersubrepos(ctx1, ctx2):
-    """find subrepos in ctx1 or ctx2"""
-    # Create a (subpath, ctx) mapping where we prefer subpaths from
-    # ctx1. The subpaths from ctx2 are important when the .hgsub file
-    # has been modified (in ctx2) but not yet committed (in ctx1).
-    subpaths = dict.fromkeys(ctx2.substate, ctx2)
-    subpaths.update(dict.fromkeys(ctx1.substate, ctx1))
-    for subpath, ctx in sorted(subpaths.iteritems()):
-        yield subpath, ctx.sub(subpath)
+    """return subrepos in ctx1 or ctx2, as (subpath, subrepo) pairs.
+    The returned subrepo's state is its state in ctx1. If the subrepo
+    only appears in ctx2, the returned subrepo is of the same kind as
+    that subpath's subrepo in ctx2, but with the nullid state."""
+    subpaths = set(ctx1.substate).union(set(ctx2.substate))
+    for subpath in sorted(subpaths):
+        yield subpath, ctx1.sub(subpath, ctx2)
 
-def subrepo(ctx, path):
-    """return instance of the right subrepo class for subrepo in path"""
+def subrepo(ctx, path, helperctx=None):
+    """return instance of the right subrepo class for subrepo at path
+    in ctx. If there is no subrepo at path in ctx, but there is one at
+    path in the provided helperctx, return an instance of *that* kind
+    of subrepo, set to the null state."""
     # subrepo inherently violates our import layering rules
     # because it wants to make repo objects from deep inside the stack
     # so we manually delay the circular imports to not break
@@ -268,6 +270,9 @@
 
     scmutil.pathauditor(ctx._repo.root)(path)
     state = ctx.substate.get(path, nullstate)
+    if state[2] == 'empty' and helperctx:
+        state = helperctx.substate.get(path, nullstate)
+        state = (state[0], node.hex(node.nullid), state[2])
     if state[2] not in types:
         raise util.Abort(_('unknown subrepo type %s') % state[2])
     return types[state[2]](ctx, path, state[:2])
diff -r 7002bb17cc5e -r 52df9ecdec9b tests/test-mq-subrepo.t
--- a/tests/test-mq-subrepo.t	Mon May 14 13:25:42 2012 +0100
+++ b/tests/test-mq-subrepo.t	Thu May 17 00:18:35 2012 +0300
@@ -104,6 +104,7 @@
   [255]
   % update substate when adding .hgsub w/clean updated subrepo
   A .hgsub
+  A sub/a
   % qnew -m0 0.diff
   path sub
    source   sub
@@ -119,6 +120,7 @@
   [255]
   % update substate when modifying .hgsub w/clean updated subrepo
   M .hgsub
+  A sub2/a
   % qnew -m1 1.diff
   path sub
    source   sub
@@ -163,6 +165,7 @@
   [255]
   % update substate when adding .hgsub w/clean updated subrepo
   A .hgsub
+  A sub/a
   % qrefresh
   path sub
    source   sub
@@ -179,6 +182,7 @@
   [255]
   % update substate when modifying .hgsub w/clean updated subrepo
   M .hgsub
+  A sub2/a
   % qrefresh
   path sub
    source   sub
@@ -268,6 +272,7 @@
   [255]
   % update substate when adding .hgsub w/clean updated subrepo
   A .hgsub
+  A sub/a
   % qrecord --config ui.interactive=1 -m0 0.diff
   diff --git a/.hgsub b/.hgsub
   new file mode 100644
@@ -296,6 +301,7 @@
   [255]
   % update substate when modifying .hgsub w/clean updated subrepo
   M .hgsub
+  A sub2/a
   % qrecord --config ui.interactive=1 -m1 1.diff
   diff --git a/.hgsub b/.hgsub
   1 hunks, 1 lines changed


More information about the Mercurial-devel mailing list