diff mercurial/discovery.py @ 51646:6454c117c6a4 stable 6.8rc0

branching: merge default into stable for 6.8rc0
author Raphaël Gomès <rgomes@octobus.net>
date Mon, 24 Jun 2024 12:05:31 +0200
parents 3a6fae3bef35
children
line wrap: on
line diff
--- a/mercurial/discovery.py	Thu Jun 13 09:52:39 2024 +0200
+++ b/mercurial/discovery.py	Mon Jun 24 12:05:31 2024 +0200
@@ -18,6 +18,7 @@
     bookmarks,
     branchmap,
     error,
+    node as nodemod,
     obsolete,
     phases,
     pycompat,
@@ -98,29 +99,62 @@
     def __init__(
         self, repo, commonheads=None, ancestorsof=None, missingroots=None
     ):
-        # at least one of them must not be set
-        assert None in (commonheads, missingroots)
+        # at most one of them must not be set
+        if commonheads is not None and missingroots is not None:
+            m = 'commonheads and missingroots arguments are mutually exclusive'
+            raise error.ProgrammingError(m)
         cl = repo.changelog
+        unfi = repo.unfiltered()
+        ucl = unfi.changelog
+        to_node = ucl.node
+        missing = None
+        common = None
+        arg_anc = ancestorsof
         if ancestorsof is None:
             ancestorsof = cl.heads()
-        if missingroots:
+
+        # XXX-perf: do we need all this to be node-list? They would be simpler
+        # as rev-num sets (and smartset)
+        if missingroots == [nodemod.nullrev] or missingroots == []:
+            commonheads = [repo.nullid]
+            common = set()
+            if arg_anc is None:
+                missing = [to_node(r) for r in cl]
+            else:
+                missing_rev = repo.revs('::%ln', missingroots, ancestorsof)
+                missing = [to_node(r) for r in missing_rev]
+        elif missingroots is not None:
             # TODO remove call to nodesbetween.
-            # TODO populate attributes on outgoing instance instead of setting
-            # discbases.
-            csets, roots, heads = cl.nodesbetween(missingroots, ancestorsof)
-            included = set(csets)
-            discbases = []
-            for n in csets:
-                discbases.extend([p for p in cl.parents(n) if p != repo.nullid])
-            ancestorsof = heads
-            commonheads = [n for n in discbases if n not in included]
+            missing_rev = repo.revs('%ln::%ln', missingroots, ancestorsof)
+            ancestorsof = [to_node(r) for r in ucl.headrevs(missing_rev)]
+            parent_revs = ucl.parentrevs
+            common_legs = set()
+            for r in missing_rev:
+                p1, p2 = parent_revs(r)
+                if p1 not in missing_rev:
+                    common_legs.add(p1)
+                if p2 not in missing_rev:
+                    common_legs.add(p2)
+            common_legs.discard(nodemod.nullrev)
+            if not common_legs:
+                commonheads = [repo.nullid]
+                common = set()
+            else:
+                commonheads_revs = unfi.revs(
+                    'heads(%ld::%ld)',
+                    common_legs,
+                    common_legs,
+                )
+                commonheads = [to_node(r) for r in commonheads_revs]
+                common = ucl.ancestors(commonheads_revs, inclusive=True)
+            missing = [to_node(r) for r in missing_rev]
         elif not commonheads:
             commonheads = [repo.nullid]
         self.commonheads = commonheads
         self.ancestorsof = ancestorsof
         self._revlog = cl
-        self._common = None
-        self._missing = None
+        self._common = common
+        self._missing = missing
         self.excluded = []
 
     def _computecommonmissing(self):
@@ -190,7 +224,12 @@
         if len(missing) == len(allmissing):
             ancestorsof = onlyheads
         else:  # update missing heads
-            ancestorsof = phases.newheads(repo, onlyheads, excluded)
+            to_rev = repo.changelog.index.rev
+            to_node = repo.changelog.node
+            excluded_revs = [to_rev(r) for r in excluded]
+            onlyheads_revs = [to_rev(r) for r in onlyheads]
+            new_heads = phases.new_heads(repo, onlyheads_revs, excluded_revs)
+            ancestorsof = [to_node(r) for r in new_heads]
         og.ancestorsof = ancestorsof
     if portable:
         # recompute common and ancestorsof as if -r<rev> had been given for