[PATCH 5 of 8] graphlog: fix --follow-first --rev combinations
Patrick Mezard
patrick at mezard.eu
Wed Apr 11 05:08:42 CDT 2012
# HG changeset patch
# User Patrick Mezard <patrick at mezard.eu>
# Date 1334136334 -7200
# Node ID 5f0a8afe7fbf4ddc3a49f8976d01a20f8dc80350
# Parent ad9d7e769dedbfce2b48ae19d26ecf2009bca7a1
graphlog: fix --follow-first --rev combinations
This solves a similar problem than the previous --follow/--rev patch. This time
we need changelog.ancestors()/descendants() filtering on first parent.
Duplicating the code looked better than introducing keyword arguments. Besides,
the ancestors() version was already implemented in follow() revset.
diff --git a/hgext/graphlog.py b/hgext/graphlog.py
--- a/hgext/graphlog.py
+++ b/hgext/graphlog.py
@@ -279,11 +279,12 @@
the files to be detailed when displaying the revision.
"""
opt2revset = {
- 'follow_first': ('_followfirst()', None),
'no_merges': ('not merge()', None),
'only_merges': ('merge()', None),
'_ancestors': ('ancestors(%(val)s)', None),
+ '_fancestors': ('_firstancestors(%(val)s)', None),
'_descendants': ('descendants(%(val)s)', None),
+ '_fdescendants': ('_firstdescendants(%(val)s)', None),
'_matchfiles': ('_matchfiles(%(val)s)', None),
'date': ('date(%(val)r)', None),
'branch': ('branch(%(val)r)', ' or '),
@@ -299,8 +300,6 @@
# follow or not follow?
follow = opts.get('follow') or opts.get('follow_first')
followfirst = opts.get('follow_first')
- if 'follow_first' in opts:
- del opts['follow_first']
# --follow with FILE behaviour depends on revs...
startrev = revs[0]
followdescendants = len(revs) > 1 and revs[0] < revs[1]
@@ -356,7 +355,10 @@
if pats:
opts['_patsfollowfirst'] = list(pats)
else:
- opts['follow_first'] = True
+ if followdescendants:
+ opts['_fdescendants'] = str(startrev)
+ else:
+ opts['_fancestors'] = str(startrev)
else:
if pats:
opts['_patsfollow'] = list(pats)
diff --git a/mercurial/revset.py b/mercurial/revset.py
--- a/mercurial/revset.py
+++ b/mercurial/revset.py
@@ -13,6 +13,39 @@
from i18n import _
import encoding
+def _revancestors(repo, revs, followfirst):
+ """Like revlog.ancestors(), but supports followfirst."""
+ cut = followfirst and 1 or None
+ cl = repo.changelog
+ visit = list(revs)
+ seen = set([nodemod.nullrev])
+ while visit:
+ for parent in cl.parentrevs(visit.pop(0))[:cut]:
+ if parent not in seen:
+ visit.append(parent)
+ seen.add(parent)
+ yield parent
+
+def _revdescendants(repo, revs, followfirst):
+ """Like revlog.descendants() but supports followfirst."""
+ cut = followfirst and 1 or None
+ cl = repo.changelog
+ first = min(revs)
+ if first == nodemod.nullrev:
+ # Are there nodes with a null first parent and a non-null
+ # second one? Maybe. Do we care? Probably not.
+ for i in cl:
+ yield i
+ return
+
+ seen = set(revs)
+ for i in xrange(first + 1, len(cl)):
+ for x in cl.parentrevs(i)[:cut]:
+ if x != nodemod.nullrev and x in seen:
+ seen.add(i)
+ yield i
+ break
+
elements = {
"(": (20, ("group", 1, ")"), ("func", 1, ")")),
"~": (18, None, ("ancestor", 18)),
@@ -203,15 +236,23 @@
return [r for r in an if r in subset]
+def _ancestors(repo, subset, x, followfirst=False):
+ args = getset(repo, range(len(repo)), x)
+ if not args:
+ return []
+ s = set(_revancestors(repo, args, followfirst)) | set(args)
+ return [r for r in subset if r in s]
+
def ancestors(repo, subset, x):
"""``ancestors(set)``
Changesets that are ancestors of a changeset in set.
"""
- args = getset(repo, range(len(repo)), x)
- if not args:
- return []
- s = set(repo.changelog.ancestors(*args)) | set(args)
- return [r for r in subset if r in s]
+ return _ancestors(repo, subset, x)
+
+def _firstancestors(repo, subset, x):
+ # ``_firstancestors(set)``
+ # Like ``ancestors(set)`` but follows only the first parents.
+ return _ancestors(repo, subset, x, followfirst=True)
def ancestorspec(repo, subset, x, n):
"""``set~n``
@@ -394,15 +435,23 @@
l.append(r)
return l
+def _descendants(repo, subset, x, followfirst=False):
+ args = getset(repo, range(len(repo)), x)
+ if not args:
+ return []
+ s = set(_revdescendants(repo, args, followfirst)) | set(args)
+ return [r for r in subset if r in s]
+
def descendants(repo, subset, x):
"""``descendants(set)``
Changesets which are descendants of changesets in set.
"""
- args = getset(repo, range(len(repo)), x)
- if not args:
- return []
- s = set(repo.changelog.descendants(*args)) | set(args)
- return [r for r in subset if r in s]
+ return _descendants(repo, subset, x)
+
+def _firstdescendants(repo, subset, x):
+ # ``_firstdescendants(set)``
+ # Like ``descendants(set)`` but follows only the first parents.
+ return _descendants(repo, subset, x, followfirst=True)
def draft(repo, subset, x):
"""``draft()``
@@ -453,16 +502,7 @@
else:
return []
else:
- cut = followfirst and 1 or None
- cl = repo.changelog
- s = set()
- visit = [c.rev()]
- while visit:
- for prev in cl.parentrevs(visit.pop(0))[:cut]:
- if prev not in s and prev != nodemod.nullrev:
- visit.append(prev)
- s.add(prev)
- s.add(c.rev())
+ s = set(_revancestors(repo, [c.rev()], followfirst)) | set([c.rev()])
return [r for r in subset if r in s]
@@ -977,6 +1017,7 @@
"all": getall,
"ancestor": ancestor,
"ancestors": ancestors,
+ "_firstancestors": _firstancestors,
"author": author,
"bisect": bisect,
"bisected": bisected,
@@ -988,6 +1029,7 @@
"date": date,
"desc": desc,
"descendants": descendants,
+ "_firstdescendants": _firstdescendants,
"draft": draft,
"file": hasfile,
"filelog": filelog,
diff --git a/tests/test-glog.t b/tests/test-glog.t
--- a/tests/test-glog.t
+++ b/tests/test-glog.t
@@ -1746,8 +1746,8 @@
[]
(group
(func
- ('symbol', '_followfirst')
- None))
+ ('symbol', '_firstancestors')
+ ('symbol', '6')))
Cannot compare with log --follow-first FILE as it never worked
@@ -1967,6 +1967,23 @@
+nodetag 6
[1]
+Test --follow-first and forward --rev
+
+ $ testlog --follow-first -r6 -r8 -r5 -r7 -r4
+ ['6', '8', '5', '7', '4']
+ (group
+ (func
+ ('symbol', '_firstdescendants')
+ ('symbol', '6')))
+ --- log.nodes * (glob)
+ +++ glog.nodes * (glob)
+ @@ -1,3 +1,3 @@
+ -nodetag 6
+ nodetag 8
+ nodetag 7
+ +nodetag 6
+ [1]
+
Test --follow and backward --rev
$ testlog --follow -r6 -r5 -r7 -r8 -r4
@@ -1976,3 +1993,11 @@
('symbol', 'ancestors')
('symbol', '6')))
+Test --follow-first and backward --rev
+
+ $ testlog --follow-first -r6 -r5 -r7 -r8 -r4
+ ['6', '5', '7', '8', '4']
+ (group
+ (func
+ ('symbol', '_firstancestors')
+ ('symbol', '6')))
More information about the Mercurial-devel
mailing list