[PATCH] revset: add the 'subrev' symbol

Matt Harbison mharbison at attotech.com
Wed Jun 24 16:55:09 CDT 2015

# HG changeset patch
# User Matt Harbison <matt_harbison at yahoo.com>
# Date 1435179910 14400
#      Wed Jun 24 17:05:10 2015 -0400
# Node ID 74b79bc0f22824f1858750f987915671e3ecf1b9
# Parent  1de5b35cecd32a4691d0542d03348c13e5813c95
revset: add the 'subrev' symbol

This finds revisions in the outer repo that track a named revision of a subrepo.
It allows for a partial match, as long as the named revision is at least as long
as the 'shortid' form defined by the subrepo.  Allowing shorter strings seems
risky- the user may specify a "{rev}" value, and not realize it only partially
matches on a full "{node}".

A more general query is to figure out what revisions in the outer repo track the
named revision, _or a descendant of it_.  This would make it much easier to
figure out where a subrepo change becomes visible if there are a series of
subrepo changes, with one lockin commit to the outer repo.  But that looks much
more complicated.  If that makes sense to implement in this revset in the
future, we can probably do so by adding an argument to the revset that controls
the behavior, similar to the -key arg to sort().

diff --git a/mercurial/revset.py b/mercurial/revset.py
--- a/mercurial/revset.py
+++ b/mercurial/revset.py
@@ -1865,6 +1865,32 @@ def subrepo(repo, subset, x):
     return subset.filter(matches)
+def subrev(repo, subset, x):
+    """``subrev(id)``
+    Changesets that track the given subrepo revision
+    """
+    # i18n: "subrev" is a keyword
+    id = getstring(x, _("subrev requires a string"))
+    def matches(x):
+        c = repo[x]
+        for subpath, (s, r, k) in c.substate.iteritems():
+            if id == r:
+                return True
+            sub = c.sub(subpath)
+            shortid = sub.shortid(r)
+            # Partial match (with a min length for sanity), for subrepos that
+            # support short ids.  Ones that don't return the full id.
+            if len(id) >= len(shortid) and id.startswith(shortid):
+                return True
+        return False
+    return subset.filter(matches)
 def _stringmatcher(pattern):
     accepts a string, possibly starting with 're:' or 'literal:' prefix.
@@ -2079,6 +2105,7 @@ symbols = {
     "sort": sort,
     "secret": secret,
     "subrepo": subrepo,
+    "subrev": subrev,
     "matching": matching,
     "tag": tag,
     "tagged": tagged,
diff --git a/tests/test-subrepo-recursion.t b/tests/test-subrepo-recursion.t
--- a/tests/test-subrepo-recursion.t
+++ b/tests/test-subrepo-recursion.t
@@ -229,6 +229,13 @@ Log with the relationships between repo 
   1:9647f22de499 0-1-1
   0:4904098473f9 0-0-0
+  $ hg log -r "subrev(d254738c5f5e)"
+  changeset:   1:4b3c9ff4f66b
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     1-2-1
 Status between revisions:
   $ hg status -S

More information about the Mercurial-devel mailing list