changeset 5222:ba53591d4aab stable

head-checking: filter out obsolete heads when checking for new heads This does not affect any tests right now, but this will be useful for the next changeset. This is also the start of a more aggressive removal of obsolete heads in places where it does not make sense to take them into account.
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Mon, 06 Apr 2020 04:01:58 +0200
parents af9f40236037
children 11c359b4071d
files hgext3rd/topic/discovery.py
diffstat 1 files changed, 43 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/hgext3rd/topic/discovery.py	Mon Apr 06 05:05:07 2020 +0200
+++ b/hgext3rd/topic/discovery.py	Mon Apr 06 04:01:58 2020 +0200
@@ -139,6 +139,46 @@
         repo.__class__ = oldrepo
 
 
+def _get_branch_name(ctx):
+    # make it easy for extension with the branch logic there
+    return ctx.branch()
+
+
+def _filter_obsolete_heads(repo, heads):
+    """filter heads to return non-obsolete ones
+
+    Given a list of heads (on the same named branch) return a new list of heads
+    where the obsolete part have been skimmed out.
+    """
+    new_heads = []
+    old_heads = heads[:]
+    while old_heads:
+        rh = old_heads.pop()
+        ctx = repo[rh]
+        current_name = _get_branch_name(ctx)
+        # run this check early to skip the evaluation of the whole branch
+        if not ctx.obsolete():
+            new_heads.append(rh)
+            continue
+
+        # Get all revs/nodes on the branch exclusive to this head
+        # (already filtered heads are "ignored"))
+        sections_revs = repo.revs(
+            b'only(%d, (%ld+%ld))', rh, old_heads, new_heads,
+        )
+        keep_revs = []
+        for r in sections_revs:
+            ctx = repo[r]
+            if ctx.obsolete():
+                continue
+            if _get_branch_name(ctx) != current_name:
+                continue
+            keep_revs.append(r)
+        for h in repo.revs(b'heads(%ld and (::%ld))', sections_revs, keep_revs):
+            new_heads.append(h)
+    new_heads.sort()
+    return new_heads
+
 # Discovery have deficiency around phases, branch can get new heads with pure
 # phases change. This happened with a changeset was allowed to be pushed
 # because it had a topic, but it later become public and create a new branch
@@ -150,7 +190,9 @@
     for b in repo.branchmap().iterbranches():
         if b':' in b[0]:
             continue
-        data[b[0]] = len(b[1])
+        oldheads = [repo[n].rev() for n in b[1]]
+        newheads = _filter_obsolete_heads(repo, oldheads)
+        data[b[0]] = len(newheads)
     return data
 
 def handlecheckheads(orig, op, inpart):