[PATCH 6 of 7] context: add followfirst arg to filectx and workingfilectx

Patrick Mezard patrick at mezard.eu
Sun Feb 26 10:14:29 CST 2012


# HG changeset patch
# User Patrick Mezard <patrick at mezard.eu>
# Date 1330272657 -3600
# Node ID 0853c68ee6f36b5125fe2cfd877eb5236492e1cb
# Parent  bfc4a8eee8b02f92dbcac8f5fc636e2de1a19773
context: add followfirst arg to filectx and workingfilectx

When _followfirst() revset was introduced it seemed to be the sole user of such
an argument, so filectx.ancestors() was duplicated and modified instead. It now
appears this argument could be used when computing the set of files to be
considered when --patch or --stat are passed along with --follow FILE.

diff --git a/mercurial/context.py b/mercurial/context.py
--- a/mercurial/context.py
+++ b/mercurial/context.py
@@ -611,11 +611,12 @@
 
         return None
 
-    def ancestors(self):
+    def ancestors(self, followfirst=False):
         visit = {}
         c = self
+        cut = followfirst and 1 or None
         while True:
-            for parent in c.parents():
+            for parent in c.parents()[:cut]:
                 visit[(parent.rev(), parent.node())] = parent
             if not visit:
                 break
@@ -930,9 +931,10 @@
         finally:
             wlock.release()
 
-    def ancestors(self):
+    def ancestors(self, followfirst=False):
+        cut = followfirst and 1 or None
         for a in self._repo.changelog.ancestors(
-            *[p.rev() for p in self._parents]):
+            *[p.rev() for p in self._parents[:cut]]):
             yield changectx(self._repo, a)
 
     def undelete(self, list):
diff --git a/mercurial/revset.py b/mercurial/revset.py
--- a/mercurial/revset.py
+++ b/mercurial/revset.py
@@ -441,63 +441,45 @@
     """
     return limit(repo, subset, x)
 
+def _follow(repo, subset, x, name, followfirst=False):
+    l = getargs(x, 0, 1, _("%s takes no arguments or a filename") % name)
+    c = repo['.']
+    if l:
+        x = getstring(l[0], _("%s expected a filename") % name)
+        if x in c:
+            cx = c[x]
+            s = set(ctx.rev() for ctx in cx.ancestors(followfirst=followfirst))
+            # include the revision responsible for the most recent version
+            s.add(cx.linkrev())
+        else:
+            return []
+    else:
+        cut = followfirst and 1 or None
+        cl = repo.changelog
+        s = set()
+        visit = [c.rev()]
+        while visit:
+            for prev in cl.parentrevs(visit.pop(0))[:cut]:
+                if prev not in s and prev != nodemod.nullrev:
+                    visit.append(prev)
+                    s.add(prev)
+        s.add(c.rev())
+
+    return [r for r in subset if r in s]
+
 def follow(repo, subset, x):
     """``follow([file])``
     An alias for ``::.`` (ancestors of the working copy's first parent).
     If a filename is specified, the history of the given file is followed,
     including copies.
     """
-    # i18n: "follow" is a keyword
-    l = getargs(x, 0, 1, _("follow takes no arguments or a filename"))
-    c = repo['.']
-    if l:
-        x = getstring(l[0], _("follow expected a filename"))
-        if x in c:
-            cx = c[x]
-            s = set(ctx.rev() for ctx in cx.ancestors())
-            # include the revision responsible for the most recent version
-            s.add(cx.linkrev())
-        else:
-            return []
-    else:
-        s = set(repo.changelog.ancestors(c.rev()))
-        s.add(c.rev())
-
-    return [r for r in subset if r in s]
+    return _follow(repo, subset, x, 'follow')
 
 def _followfirst(repo, subset, x):
     # ``followfirst([file])``
     # Like ``follow([file])`` but follows only the first parent of
     # every revision or file revision.
-    # i18n: "_followfirst" is a keyword
-    l = getargs(x, 0, 1, _("_followfirst takes no arguments or a filename"))
-    c = repo['.']
-    if l:
-        x = getstring(l[0], _("_followfirst expected a filename"))
-        if x not in c:
-            return []
-        cx = c[x]
-        visit = {}
-        s = set([cx.linkrev()])
-        while True:
-            for p in cx.parents()[:1]:
-                visit[(p.rev(), p.node())] = p
-            if not visit:
-                break
-            cx = visit.pop(max(visit))
-            s.add(cx.rev())
-    else:
-        cl = repo.changelog
-        s = set()
-        visit = [c.rev()]
-        while visit:
-            for prev in cl.parentrevs(visit.pop(0))[:1]:
-                if prev not in s and prev != nodemod.nullrev:
-                    visit.append(prev)
-                    s.add(prev)
-        s.add(c.rev())
-
-    return [r for r in subset if r in s]
+    return _follow(repo, subset, x, '_followfirst', followfirst=True)
 
 def getall(repo, subset, x):
     """``all()``


More information about the Mercurial-devel mailing list