Patchwork [3,of,6,V2] obsolete: detect divergent changesets

login
register
mail settings
Submitter Pierre-Yves David
Date Dec. 13, 2012, 2:51 p.m.
Message ID <cfc7306dbdc75659ca4c.1355410310@crater1.logilab.fr>
Download mbox | patch
Permalink /patch/77/
State Accepted
Commit af632936d3d97fa052cf50f9cb73b798e38f74e6
Headers show

Comments

Pierre-Yves David - Dec. 13, 2012, 2:51 p.m.
# HG changeset patch
# User Pierre-Yves David <pierre-yves.david at logilab.fr>
# Date 1355278770 -3600
# Node ID cfc7306dbdc75659ca4c85a14720f8de87cd797e
# Parent  a63af12dc0cdf8e7c828f2278427b3beea1220c2
obsolete: detect divergent changesets

Divergent changeset are final successors (non obsolete) of a changeset who
compete with another set of final successors for this same changeset.

For example if you have two obsolescence markers A -> B and A -> C, B and C are
both "divergent" because they compete to be the one true successors of A.

Public revision can't be divergent.

This function is used and tested in the next changeset.

Patch

diff --git a/mercurial/obsolete.py b/mercurial/obsolete.py
--- a/mercurial/obsolete.py
+++ b/mercurial/obsolete.py
@@ -684,10 +684,32 @@  def _computebumpedset(repo):
                                ignoreflags=bumpedfix)
     # revision public or already obsolete don't count as bumped
     query = '%ld - obsolete() - public()'
     return set(repo.revs(query, _knownrevs(repo, successors)))
 
+ at cachefor('divergent')
+def _computedivergentset(repo):
+    """the set of rev that compete to be the final successors of some revision.
+    """
+    divergent = set()
+    obsstore = repo.obsstore
+    newermap = {}
+    for ctx in repo.set('(not public()) - obsolete()'):
+        mark = obsstore.precursors.get(ctx.node(), ())
+        toprocess = set(mark)
+        while toprocess:
+            prec = toprocess.pop()[0]
+            if prec not in newermap:
+                successorssets(repo, prec, newermap)
+            newer = [n for n in newermap[prec] if n]
+            if len(newer) > 1:
+                divergent.add(ctx.rev())
+                break
+            toprocess.update(obsstore.precursors.get(prec, ()))
+    return divergent
+
+
 def createmarkers(repo, relations, flag=0, metadata=None):
     """Add obsolete markers between changesets in a repo
 
     <relations> must be an iterable of (<old>, (<new>, ...)) tuple.
     `old` and `news` are changectx.