groupbranchiter: support for non-contiguous revsets

The algorithm now works when some revisions are skipped. We now use "first
included ancestors" instead of just "parent" to link changesets with each other.
This commit is contained in:
Pierre-Yves David 2014-09-04 19:05:36 +02:00
parent 401e3ad848
commit 31b9015754
2 changed files with 58 additions and 14 deletions

View File

@ -20,6 +20,8 @@ Data depends on type.
from mercurial.node import nullrev
import util
import heapq
CHANGESET = 'C'
def groupbranchiter(revs, parentsfunc):
@ -40,8 +42,6 @@ def groupbranchiter(revs, parentsfunc):
|/
o 0
Currently does not handle non-contiguous <revs> input.
Currently consider every changeset under a merge to be on the same branch
using revision number to sort them.
@ -103,16 +103,27 @@ def groupbranchiter(revs, parentsfunc):
#
# You could pre-seed the <parents> set of groups[0] to a specific
# changesets to select what the first emitted branch should be.
#
# We do not support revisions will hole yet, but adding such support would
# be easy. The iteration will have to be done using both input revision and
# parents (see cl.ancestors function + a few tweaks) but only revisions
# parts of the initial set should be emitted.
groups = [([], unblocked)]
for current in revs:
if True:
pendingheap = []
pendingset = set()
heapq.heapify(pendingheap)
heappop = heapq.heappop
heappush = heapq.heappush
for currentrev in revs:
# Heap works with smallest element, we want highest so we invert
if currentrev not in pendingset:
heappush(pendingheap, -currentrev)
pendingset.add(currentrev)
# iterates on pending rev until after the current rev have been
# processeed.
rev = None
while rev != currentrev:
rev = -heappop(pendingheap)
pendingset.remove(rev)
# Seek for a subgroup blocked, waiting for the current revision.
matching = [i for i, g in enumerate(groups) if current in g[1]]
matching = [i for i, g in enumerate(groups) if rev in g[1]]
if matching:
# The main idea is to gather together all sets that await on
@ -140,7 +151,7 @@ def groupbranchiter(revs, parentsfunc):
else:
# This is a new head. We create a new subgroup for it.
targetidx = len(groups)
groups.append(([], set([current])))
groups.append(([], set([rev])))
gr = groups[targetidx]
@ -150,9 +161,15 @@ def groupbranchiter(revs, parentsfunc):
#
# we also update the <parents> set to includes the parents on the
# new nodes.
gr[0].append(current)
gr[1].remove(current)
gr[1].update([p for p in parentsfunc(current) if p > nullrev])
if rev == currentrev: # only display stuff in rev
gr[0].append(rev)
gr[1].remove(rev)
parents = [p for p in parentsfunc(rev) if p > nullrev]
gr[1].update(parents)
for p in parents:
if p not in pendingset:
pendingset.add(p)
heappush(pendingheap, -p)
# Look for a subgroup to display
#
@ -185,6 +202,11 @@ def groupbranchiter(revs, parentsfunc):
del groups[targetidx]
else:
gr[0][:] = []
# Check if we have some subgroup waiting for revision we are not going to
# iterate over
for g in groups:
for r in g[0]:
yield r
def dagwalker(repo, revs):
"""cset DAG generator yielding (id, CHANGESET, ctx, [parentids]) tuples

View File

@ -37,6 +37,9 @@ later.
|/
o 0
(display all nodes)
$ hg --config experimental.graph-topological=1 log -G
o 8
|
@ -56,3 +59,22 @@ later.
|/
o 0
(revset skipping nodes)
$ hg --config experimental.graph-topological=1 log -G --rev 'not (2+6)'
o 8
|
o 3
|
o 1
|
| o 7
| |
| o 5
| |
| o 4
|/
o 0