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

Dov Feldstern dovdevel at gmail.com
Wed Apr 25 05:02:45 CDT 2012


# HG changeset patch
# User Dov Feldstern <dfeldstern at gmail.com>
# Date 1335346512 -10800
# Branch stable
# Node ID aaa5bc10d80dc7b974b1a9be1d9fdf9fad093dfd
# Parent  e3c7ca15cde24f7e1ef5018fcfd902f4d6c95adc
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.

diff -r e3c7ca15cde2 -r aaa5bc10d80d mercurial/context.py
--- a/mercurial/context.py	Mon Apr 23 00:38:22 2012 +0900
+++ b/mercurial/context.py	Wed Apr 25 12:35:12 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 e3c7ca15cde2 -r aaa5bc10d80d mercurial/subrepo.py
--- a/mercurial/subrepo.py	Mon Apr 23 00:38:22 2012 +0900
+++ b/mercurial/subrepo.py	Wed Apr 25 12:35:12 2012 +0300
@@ -239,17 +239,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
@@ -260,6 +262,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])


More information about the Mercurial-devel mailing list