changeset 2919:5b514ab2ab4e

stack: properly order stack when gaps existing inside it We transitively search for the next "stack" ancestors, of changeset in the stack not based on other revision of the stack. This should help having a consistent display when topic are interleaved.
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Sat, 09 Sep 2017 22:32:50 +0530
parents 0437158e0ed6
children ef4832faaf09
files hgext3rd/topic/stack.py tests/test-topic-stack.t
diffstat 2 files changed, 110 insertions(+), 35 deletions(-) [+]
line wrap: on
line diff
--- a/hgext3rd/topic/stack.py	Thu Sep 07 19:43:07 2017 +0200
+++ b/hgext3rd/topic/stack.py	Sat Sep 09 22:32:50 2017 +0530
@@ -8,9 +8,10 @@
     context,
     error,
     node,
+    phases,
     util,
 )
-from .evolvebits import builddependencies, _orderrevs, _singlesuccessor
+from .evolvebits import builddependencies, _singlesuccessor
 
 short = node.short
 
@@ -50,11 +51,84 @@
 
     @util.propertycache
     def _dependencies(self):
-        return builddependencies(self._repo, self.revs[1:])
+        deps, rdeps = builddependencies(self._repo, self._revs)
+
+        repo = self._repo
+        srcpfunc = repo.changelog.parentrevs
+
+        ### post process to skip over possible gaps in the stack
+        #
+        # For example in the following situation, we need to detect that "t3"
+        # indirectly depends on t2.
+        #
+        #  o t3
+        #  |
+        #  o other
+        #  |
+        #  o t2
+        #  |
+        #  o t1
+
+        pmap = {}
+
+        def pfuncrev(repo, rev):
+            """a special "parent func" that also consider successors"""
+            parents = pmap.get(rev)
+            if parents is None:
+                parents = [repo[_singlesuccessor(repo, repo[p])].rev()
+                           for p in srcpfunc(rev) if 0 <= p]
+                pmap[rev] = parents
+            return parents
+
+        revs = self._revs
+        stackrevs = set(self._revs)
+        for root in [r for r in revs if not deps[r]]:
+            seen = set()
+            stack = [root]
+            while stack:
+                current = stack.pop()
+                for p in pfuncrev(repo, current):
+                    if p in seen:
+                        continue
+                    seen.add(p)
+                    if p in stackrevs:
+                        rdeps[p].add(root)
+                        deps[root].add(p)
+                    elif phases.public < repo[p].phase():
+                        # traverse only if we did not found a proper candidate
+                        stack.append(p)
+
+        return deps, rdeps
 
     @util.propertycache
     def revs(self):
-        revs = _orderrevs(self._repo, self._revs)
+        # some duplication/change from _orderrevs because we use a post
+        # processed dependency graph.
+
+        # Step 1: compute relation of revision with each other
+        dependencies, rdependencies = self._dependencies
+        dependencies = dependencies.copy()
+        rdependencies = rdependencies.copy()
+        # Step 2: Build the ordering
+        # Remove the revisions with no dependency(A) and add them to the ordering.
+        # Removing these revisions leads to new revisions with no dependency (the
+        # one depending on A) that we can remove from the dependency graph and add
+        # to the ordering. We progress in a similar fashion until the ordering is
+        # built
+        solvablerevs = [r for r in sorted(dependencies.keys())
+                        if not dependencies[r]]
+        revs = []
+        while solvablerevs:
+            rev = solvablerevs.pop()
+            for dependent in rdependencies[rev]:
+                dependencies[dependent].remove(rev)
+                if not dependencies[dependent]:
+                    solvablerevs.append(dependent)
+            del dependencies[rev]
+            revs.append(rev)
+
+        revs.extend(sorted(dependencies))
+        # step 3: add t0
         if revs:
             pt1 = self._repo[revs[0]].p1()
             if pt1.obsolete():
--- a/tests/test-topic-stack.t	Thu Sep 07 19:43:07 2017 +0200
+++ b/tests/test-topic-stack.t	Sat Sep 09 22:32:50 2017 +0530
@@ -532,24 +532,26 @@
   o  0 default {} public c_a
   
 XXX: The following should show single heads
+XXX: The behind count is weird, because the topic are interleaved.
+
   $ hg stack
-  ### topic: foobar (2 heads)
+  ### topic: foobar
   ### branch: default, 3 behind
-  t2: c_D
-    ^ c_c
-  t1@ c_e (current)
-  t0^ c_h (base)
+  t2@ c_e (current)
+    ^ c_h
+  t1: c_D
+  t0^ c_c (base)
 
   $ hg stack foo
-  ### topic: foo (3 heads)
+  ### topic: foo
   ### branch: default, ambigious rebase destination
-  t4: c_c
-    ^ c_b
+  t4: c_f
+    ^ c_e
   t3: c_h
   t2: c_g
     ^ c_D
-  t1: c_f
-  t0^ c_e (base)
+  t1: c_c
+  t0^ c_b (base)
 
 case involving a merge
 ----------------------
@@ -618,27 +620,26 @@
   
 
   $ hg stack red
-  ### topic: red (3 heads)
+  ### topic: red
   ### branch: default, 6 behind
-  t5: c_C
-  t2^ c_B (base)
-  t4: c_F
-  t3: c_E
-  t2: c_B
-    ^ c_A
-  t1: c_H
+  t5: c_H
     ^ c_G
     ^ c_D
-  t0^ c_D (base)
+  t4: c_C
+  t1^ c_B (base)
+  t3: c_F
+  t2: c_E
+  t1: c_B
+  t0^ c_A (base)
   $ hg stack blue
-  ### topic: blue (3 heads)
+  ### topic: blue
   ### branch: default, ambigious rebase destination
-  t3: c_D
+  t3@ c_I (current)
+    ^ c_H
+  t2: c_D
     ^ c_C
-  t2: c_G
-    ^ c_F
-  t1@ c_I (current)
-  t0^ c_H (base)
+  t1: c_G
+  t0^ c_F (base)
 
 Even with some obsolete and orphan changesets
 
@@ -684,7 +685,7 @@
   
 
   $ hg stack red
-  ### topic: red (3 heads)
+  ### topic: red
   ### branch: default, ambigious rebase destination
   t5$ c_H (unstable)
     ^ c_G
@@ -696,12 +697,12 @@
   t1: c_B
   t0^ c_A (base)
   $ hg stack blue
-  ### topic: blue (3 heads)
+  ### topic: blue
   ### branch: default, ambigious rebase destination
-  t3$ c_G (unstable)
+  t3$ c_I (unstable)
+    ^ c_H
+  t2$ c_G (unstable)
     ^ c_F
-  t2$ c_I (unstable)
-    ^ c_H
   t1$ c_D (current unstable)
   t0^ c_C (base)
 
@@ -758,7 +759,7 @@
   
 
   $ hg stack red
-  ### topic: red (3 heads)
+  ### topic: red
   ### branch: default, ambigious rebase destination
   t5$ c_H (unstable)
     ^ c_G
@@ -770,7 +771,7 @@
   t1: c_B
   t0^ c_A (base)
   $ hg stack blue
-  ### topic: blue (3 heads)
+  ### topic: blue
   ### branch: default, ambigious rebase destination
   t3$ c_I (unstable)
     ^ c_H