[PATCH] graphlog: add glog --ancestors to see paths to common ancestor
Peter Arrenbrecht
peter.arrenbrecht at gmail.com
Wed Apr 7 04:11:18 CDT 2010
# HG changeset patch
# User Peter Arrenbrecht <peter.arrenbrecht at gmail.com>
# Date 1270631415 -7200
graphlog: add glog --ancestors to see paths to common ancestor
Adds the --ancestors/-a option to glog. It plots just the paths
from two nodes to their common ancestor. It takes either two
explicit nodes as arguments, or a merge node which is graphed
together with its parents and the paths to their ancestor, or
'.' to graph the parents of an uncommitted merge.
diff --git a/hgext/graphlog.py b/hgext/graphlog.py
--- a/hgext/graphlog.py
+++ b/hgext/graphlog.py
@@ -17,9 +17,29 @@
from mercurial.commands import templateopts
from mercurial.i18n import _
from mercurial.node import nullrev
+from mercurial.graphmod import CHANGESET
from mercurial import bundlerepo, changegroup, cmdutil, commands, extensions
from mercurial import hg, url, util, graphmod
+def ancestors(repo, a, b, child=None):
+ """cset DAG generator yielding (id, CHANGESET, ctx, [parentids]) tuples
+
+ This generator function walks from the given nodes a and b back to their
+ closest common ancestor. If child is given, it must be a direct child of both
+ a and b and is displayed too.
+ """
+ cl = repo.changelog
+ commonnode = cl.ancestor(a, b)
+ nodes, _oh, _oc = cl.nodesbetween(roots=[commonnode], heads=[a, b])
+ revs = [cl.rev(n) for n in nodes]
+ if child:
+ revs.append(cl.rev(child))
+ revset = set(revs)
+ for r in reversed(revs):
+ ncx = repo[r]
+ parents = [p.rev() for p in ncx.parents() if p.rev() in revset]
+ yield (r, CHANGESET, ncx, sorted(parents))
+
ASCIIDATA = 'ASC'
def asciiedges(seen, rev, parents):
@@ -229,7 +249,7 @@
lines = displayer.hunk.pop(rev).split('\n')[:-1]
ascii(ui, state, type, char, lines, edgefn(seen, rev, parents))
-def graphlog(ui, repo, path=None, **opts):
+def graphlog(ui, repo, *pathOrRevs, **opts):
"""show revision history alongside an ASCII revision graph
Print a revision history alongside a revision graph drawn with
@@ -237,22 +257,55 @@
Nodes printed as an @ character are parents of the working
directory.
+
+ If --ancestors is given, you must specify either two nodes, or a single merge
+ node, or . to select the two parents of the current uncommitted merge.
"""
check_unsupported_flags(opts)
limit = cmdutil.loglimit(opts)
- start, stop = get_revs(repo, opts["rev"])
- if start == nullrev:
- return
- if path:
- path = util.canonpath(repo.root, os.getcwd(), path)
- if path: # could be reset in canonpath
- revdag = graphmod.filerevs(repo, path, start, stop, limit)
+ ancs = opts.get("ancestors")
+ if ancs:
+ revs = pathOrRevs
+ if len(revs) == 1:
+ if revs[0] == '.':
+ # dirstate must be merge
+ ds = repo.dirstate
+ ps = ds.parents()
+ if len(ps) != 2:
+ raise util.Abort(_('not an uncommitted merge'))
+ a, b = ps
+ child = None
+ else:
+ # must be merge node
+ cx = repo[revs[0]]
+ ps = [p.node() for p in cx.parents()]
+ if len(ps) != 2:
+ raise util.Abort(_('not a merge node'))
+ a, b = ps
+ child = cx.node()
+ elif len(revs) == 2:
+ a, b = [repo[a].node() for a in revs]
+ child = None
+ else:
+ raise util.Abort(_('must specify exactly two nodes (or one merge node)'))
+ revdag = ancestors(repo, a, b, child)
else:
- if limit is not None:
- stop = max(stop, start - limit + 1)
- revdag = graphmod.revisions(repo, start, stop)
+ start, stop = get_revs(repo, opts["rev"])
+ if start == nullrev:
+ return
+ path = None
+ if pathOrRevs:
+ if len(pathOrRevs) > 1:
+ raise util.Abort(_('specify exactly one file'))
+ path = util.canonpath(repo.root, os.getcwd(), pathOrRevs[0])
+ if path: # could be reset in canonpath
+ revdag = graphmod.filerevs(repo, path, start, stop, limit)
+ else:
+ if limit is not None:
+ stop = max(stop, start - limit + 1)
+ revdag = graphmod.revisions(repo, start, stop)
displayer = show_changeset(ui, repo, opts, buffered=True)
showparents = [ctx.node() for ctx in repo[None].parents()]
@@ -372,6 +425,7 @@
[('l', 'limit', '', _('limit number of changes displayed')),
('p', 'patch', False, _('show patch')),
('r', 'rev', [], _('show the specified revision or range')),
+ ('a', 'ancestors', None, _('show path to common ancestor of two nodes')),
] + templateopts,
- _('hg glog [OPTION]... [FILE]')),
+ _('hg glog [OPTION]... [FILE] | [REV]...')),
}
diff --git a/tests/test-glog b/tests/test-glog
--- a/tests/test-glog
+++ b/tests/test-glog
@@ -146,6 +146,19 @@
echo % unused arguments
hg glog -q foo bar || echo failed
+echo % ancestry of merge
+hg glog -a 21
+
+echo % ancestry of two nodes
+hg glog -a 20 19
+
+echo % ancestry of uncommitted merge
+hg clone . ../pendmerge
+cd ../pendmerge
+hg up 19
+HGMERGE=internal:local hg merge 20
+hg glog -a .
+
echo % from outer space
cd ..
hg glog -l1 repo
diff --git a/tests/test-glog.out b/tests/test-glog.out
--- a/tests/test-glog.out
+++ b/tests/test-glog.out
@@ -543,11 +543,107 @@
summary: (0) root
% unused arguments
-hg glog: invalid arguments
-hg glog [OPTION]... [FILE]
+abort: specify exactly one file
+failed
+% ancestry of merge
+o changeset: 21:d42a756af44d
+|\ parent: 19:31ddc2c1573b
+| | parent: 20:d30ed6450e32
+| | user: test
+| | date: Thu Jan 01 00:00:21 1970 +0000
+| | summary: (21) expand
+| |
+| o changeset: 20:d30ed6450e32
+| | parent: 0:e6eb3150255d
+| | parent: 18:1aa84d96232a
+| | user: test
+| | date: Thu Jan 01 00:00:20 1970 +0000
+| | summary: (20) merge two known; two far right
+| |
+o | changeset: 19:31ddc2c1573b
+| | parent: 15:1dda3f72782d
+| | parent: 17:44765d7c06e0
+| | user: test
+| | date: Thu Jan 01 00:00:19 1970 +0000
+| | summary: (19) expand
+| |
+| o changeset: 18:1aa84d96232a
+|/ parent: 1:6db2ef61d156
+| parent: 15:1dda3f72782d
+| user: test
+| date: Thu Jan 01 00:00:18 1970 +0000
+| summary: (18) merge two known; two far left
+|
+o changeset: 15:1dda3f72782d
+ parent: 13:22d8966a97e3
+ parent: 14:8eac370358ef
+ user: test
+ date: Thu Jan 01 00:00:15 1970 +0000
+ summary: (15) expand
-show revision history alongside an ASCII revision graph
-failed
+% ancestry of two nodes
+o changeset: 20:d30ed6450e32
+| parent: 0:e6eb3150255d
+| parent: 18:1aa84d96232a
+| user: test
+| date: Thu Jan 01 00:00:20 1970 +0000
+| summary: (20) merge two known; two far right
+|
+| o changeset: 19:31ddc2c1573b
+| | parent: 15:1dda3f72782d
+| | parent: 17:44765d7c06e0
+| | user: test
+| | date: Thu Jan 01 00:00:19 1970 +0000
+| | summary: (19) expand
+| |
+o | changeset: 18:1aa84d96232a
+|/ parent: 1:6db2ef61d156
+| parent: 15:1dda3f72782d
+| user: test
+| date: Thu Jan 01 00:00:18 1970 +0000
+| summary: (18) merge two known; two far left
+|
+o changeset: 15:1dda3f72782d
+ parent: 13:22d8966a97e3
+ parent: 14:8eac370358ef
+ user: test
+ date: Thu Jan 01 00:00:15 1970 +0000
+ summary: (15) expand
+
+% ancestry of uncommitted merge
+updating to branch default
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+@ changeset: 20:d30ed6450e32
+| parent: 0:e6eb3150255d
+| parent: 18:1aa84d96232a
+| user: test
+| date: Thu Jan 01 00:00:20 1970 +0000
+| summary: (20) merge two known; two far right
+|
+| @ changeset: 19:31ddc2c1573b
+| | parent: 15:1dda3f72782d
+| | parent: 17:44765d7c06e0
+| | user: test
+| | date: Thu Jan 01 00:00:19 1970 +0000
+| | summary: (19) expand
+| |
+o | changeset: 18:1aa84d96232a
+|/ parent: 1:6db2ef61d156
+| parent: 15:1dda3f72782d
+| user: test
+| date: Thu Jan 01 00:00:18 1970 +0000
+| summary: (18) merge two known; two far left
+|
+o changeset: 15:1dda3f72782d
+ parent: 13:22d8966a97e3
+ parent: 14:8eac370358ef
+ user: test
+ date: Thu Jan 01 00:00:15 1970 +0000
+ summary: (15) expand
+
% from outer space
@ changeset: 34:fea3ac5810e0
| tag: tip
More information about the Mercurial-devel
mailing list