[PATCH] in/out --summary
Alexis S. L. Carvalho
alexis at cecm.usp.br
Tue Feb 12 19:18:59 CST 2008
Thus spake Jesse Glick:
> Alexis S. L. Carvalho wrote:
> >> There ought to be a command (out --summary?) which folds all
> >> non-merge outgoing changesets and displays the result as a patch.
>
> By the way see
>
> http://www.selenic.com/mercurial/bts/issue28
>
> and
>
> http://www.selenic.com/mercurial/bts/issue219
Hmm...
> > Maybe something like this?
>
> It doesn't work for me; it folds in merge changesets too, making the
> output misleading. E.g. in the following example I expected out -s to
> show only the patch to r:
As I said, "lightly tested" ;) . The version below should be better.
(I would've sent this faster, but my ISP decided to make my connection
"a bit" unstable for the last hour or so).
Alexis
diff -r ea34059b89de mercurial/cmdutil.py
--- a/mercurial/cmdutil.py Tue Feb 12 11:35:06 2008 +0100
+++ b/mercurial/cmdutil.py Tue Feb 12 23:17:13 2008 -0200
@@ -1157,3 +1157,105 @@ def commit(ui, repo, commitfunc, pats, o
return commitfunc(ui, repo, files, message, match, opts)
except ValueError, inst:
raise util.Abort(str(inst))
+
+def summaryrevs(repo, nodes, opts={}):
+ '''returns (base, head) nodes that can be compared to summarize changes
+
+ See the docstring for summaryrevpair for information about the nodes
+ argument.
+
+ opts['base'] can be used to override the calculation of the base node.
+
+ opts['rev] can be used to override the calculation of the head node.
+ Note that opts['rev'] is expected to be a list with a single element.
+
+ '''
+ head = opts.get('rev')
+ if len(head) > 1:
+ raise util.Abort(_('please specify a single revision with --rev'))
+ elif head:
+ head = repo.lookup(head[0])
+
+ base = opts.get('base')
+ if base:
+ base = repo.lookup(base)
+
+ return summaryrevpair(repo, nodes, base, head)
+
+def summaryrevpair(repo, nodes, base=None, head=None):
+ '''returns (base, head) nodes that can be compared to summarize changes
+
+ nodes is usually a list of nodes returned by nodesbetween
+
+ The caller can specify base and head nodes that should be used.
+ '''
+ def show(revs):
+ displayer = show_changeset(ui, repo, {})
+ revs.sort()
+ for r in revs:
+ displayer.show(rev=r)
+
+ ui = repo.ui
+ cl = repo.changelog
+
+ if not base:
+ # The repo we're comparing with doesn't know anything about the
+ # nodes in the nodes list.
+ # So we first determine the "boundary" of this set of nodes by
+ # looking at the parents of each node and saving the ones that
+ # are not in the set.
+ # If there's only one such parent, we use it as the base.
+ # If there's more than one, we try to find one that is a descendant
+ # of all the others and use it as the base. If there's no such
+ # parent, abort.
+ parents = {}
+ revs = dict.fromkeys([cl.rev(n) for n in nodes])
+ revs[nullrev] = 1
+ for r in revs:
+ for p in cl.parentrevs(r):
+ if p not in revs:
+ parents[p] = 1
+ if len(parents) > 1:
+ seen = {}
+ for r in xrange(max(parents), min(parents) - 1, -1):
+ if r in seen and r in parents:
+ del parents[r]
+ for p in cl.parentrevs(r):
+ seen[p] = 1
+ if len(parents) > 1:
+ if not ui.quiet:
+ ui.write("there's more than one possible base revision.\n")
+ ui.write("please choose one using --base.\n")
+ ui.write('base revisions found:\n')
+ show(parents.keys())
+ raise util.Abort(_('unable to find a unique base revision'))
+ if not parents:
+ # other repo is empty
+ parents[nullrev] = 1
+ base = cl.node(parents.keys()[0])
+
+ if not head:
+ # just find all heads that descend from the base revision
+ heads = cl.heads(base)
+ if len(heads) > 1:
+ if not ui.quiet:
+ ui.write("there's more than one possible head revision.\n")
+ ui.write("please choose one using --rev.\n")
+ ui.write('head revisions found:\n')
+ show([cl.rev(n) for n in heads])
+ raise util.Abort(_('unable to find a unique head revision'))
+ head = heads[0]
+ else:
+ # sanity check: if a head revision was specified, it must be a
+ # descendant of whatever base revision we have.
+ seen = {}
+ baserev = cl.rev(base)
+ for r in xrange(cl.rev(head), baserev, -1):
+ for p in cl.parentrevs(r):
+ seen[p] = 1
+ if baserev not in seen:
+ raise util.Abort(_('the specified head revision is not a '
+ 'descendant of the base revision'))
+
+ return base, head
+
diff -r ea34059b89de mercurial/commands.py
--- a/mercurial/commands.py Tue Feb 12 11:35:06 2008 +0100
+++ b/mercurial/commands.py Tue Feb 12 23:17:13 2008 -0200
@@ -1562,6 +1562,10 @@ def incoming(ui, repo, source="default",
other = bundlerepo.bundlerepository(ui, repo.root, fname)
o = other.changelog.nodesbetween(incoming, revs)[0]
+ if opts.get('summary'):
+ base, head = cmdutil.summaryrevs(other, o, opts)
+ patch.diff(other, base, head, opts=patch.diffopts(ui, opts))
+ return
if opts['newest_first']:
o.reverse()
displayer = cmdutil.show_changeset(ui, other, opts)
@@ -1853,6 +1857,10 @@ def outgoing(ui, repo, dest=None, **opts
ui.status(_("no changes found\n"))
return 1
o = repo.changelog.nodesbetween(o, revs)[0]
+ if opts.get('summary'):
+ base, head = cmdutil.summaryrevs(repo, o, opts)
+ patch.diff(repo, base, head, opts=patch.diffopts(ui, opts))
+ return
if opts['newest_first']:
o.reverse()
displayer = cmdutil.show_changeset(ui, repo, opts)
@@ -2906,6 +2914,8 @@ table = {
('p', 'patch', None, _('show patch')),
('r', 'rev', [], _('a specific revision up to which you would like to pull')),
('', 'template', '', _('display with template')),
+ ('s', 'summary', None, _('display only a single diff containing all changes')),
+ ('', 'base', '', _('force a base revision for --summary')),
] + remoteopts,
_('hg incoming [-p] [-n] [-M] [-f] [-r REV]...'
' [--bundle FILENAME] [SOURCE]')),
@@ -2964,6 +2974,8 @@ table = {
('r', 'rev', [], _('a specific revision you would like to push')),
('n', 'newest-first', None, _('show newest record first')),
('', 'template', '', _('display with template')),
+ ('s', 'summary', None, _('display only a single diff containing all changes')),
+ ('', 'base', '', _('force a base revision for --summary')),
] + remoteopts,
_('hg outgoing [-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
"^parents":
More information about the Mercurial-devel
mailing list