--- a/hgext/evolve.py Fri Mar 18 23:49:32 2016 -0700
+++ b/hgext/evolve.py Tue Mar 22 14:08:16 2016 -0700
@@ -1514,6 +1514,110 @@
ordering.extend(sorted(dependencies))
return ordering
+def divergentsets(repo, ctx):
+ """Compute sets of commits divergent with a given one"""
+ cache = {}
+ succsets = {}
+ base = {}
+ for n in obsolete.allprecursors(repo.obsstore, [ctx.node()]):
+ if n == ctx.node():
+ # a node can't be a base for divergence with itself
+ continue
+ nsuccsets = obsolete.successorssets(repo, n, cache)
+ for nsuccset in nsuccsets:
+ if ctx.node() in nsuccset:
+ # we are only interested in *other* successor sets
+ continue
+ if tuple(nsuccset) in base:
+ # we already know the latest base for this divergency
+ continue
+ base[tuple(nsuccset)] = n
+ divergence = []
+ for divset, b in base.iteritems():
+ divergence.append({
+ 'divergentnodes': divset,
+ 'commonprecursor': b
+ })
+
+ return divergence
+
+def _preparelistctxs(items, condition):
+ return [item.hex() for item in items if condition(item)]
+
+def _formatctx(fm, ctx):
+ fm.data(node=ctx.hex())
+ fm.data(desc=ctx.description())
+ fm.data(date=ctx.date())
+ fm.data(user=ctx.user())
+
+def listtroubles(ui, repo, troublecategories, **opts):
+ """Print all the troubles for the repo (or given revset)"""
+ troublecategories = troublecategories or ['divergent', 'unstable', 'bumped']
+ showunstable = 'unstable' in troublecategories
+ showbumped = 'bumped' in troublecategories
+ showdivergent = 'divergent' in troublecategories
+
+ revs = repo.revs('+'.join("%s()" % t for t in troublecategories))
+ if opts.get('rev'):
+ revs = revs & repo.revs(opts.get('rev'))
+
+ fm = ui.formatter('evolvelist', opts)
+ for rev in revs:
+ ctx = repo[rev]
+ unpars = _preparelistctxs(ctx.parents(), lambda p: p.unstable())
+ obspars = _preparelistctxs(ctx.parents(), lambda p: p.obsolete())
+ imprecs = _preparelistctxs(repo.set("allprecursors(%n)", ctx.node()),
+ lambda p: not p.mutable())
+ dsets = divergentsets(repo, ctx)
+
+ fm.startitem()
+ # plain formatter section
+ hashlen, desclen = 12, 60
+ desc = ctx.description()
+ desc = (desc[:desclen] + '...') if len(desc) > desclen else desc
+ fm.plain('%s: ' % ctx.hex()[:hashlen])
+ fm.plain('%s\n' % desc)
+
+ for unpar in unpars if showunstable else []:
+ fm.plain(' unstable: %s (unstable parent)\n' % unpar[:hashlen])
+ for obspar in obspars if showunstable else []:
+ fm.plain(' unstable: %s (obsolete parent)\n' % obspar[:hashlen])
+ for imprec in imprecs if showbumped else []:
+ fm.plain(' bumped: %s (immutable precursor)\n' % imprec[:hashlen])
+
+ if dsets and showdivergent:
+ for dset in dsets:
+ fm.plain(' divergent: ')
+ first = True
+ for n in dset['divergentnodes']:
+ t = "%s" if first else " %s"
+ first = False
+ fm.plain(t % node.hex(n)[:hashlen])
+ comprec = node.hex(dset['commonprecursor'])[:hashlen]
+ fm.plain(" (precursor %s)\n" % comprec)
+ fm.plain("\n")
+
+ # templater-friendly section
+ _formatctx(fm, ctx)
+ troubles = []
+ for unpar in unpars:
+ troubles.append({'troubletype': 'unstable', 'sourcenode': unpar,
+ 'sourcetype': 'unstableparent'})
+ for obspar in obspars:
+ troubles.append({'troubletype': 'unstable', 'sourcenode': obspar,
+ 'sourcetype': 'obsoleteparent'})
+ for imprec in imprecs:
+ troubles.append({'troubletype': 'bumped', 'sourcenode': imprec,
+ 'sourcetype': 'immutableprecursor'})
+ for dset in dsets:
+ divnodes = [{'node': n} for n in dset['divergentnodes']]
+ troubles.append({'troubletype': 'divergent',
+ 'commonprecursor': dset['commonprecursor'],
+ 'divergentnodes': divnodes})
+ fm.data(troubles=troubles)
+
+ fm.end()
+
@command('^evolve|stabilize|solve',
[('n', 'dry-run', False,
_('do not perform actions, just print what would be done')),
@@ -1529,6 +1633,7 @@
('a', 'all', False, _('evolve all troubled changesets related to the '
'current working directory and its descendants')),
('c', 'continue', False, _('continue an interrupted evolution')),
+ ('l', 'list', False, 'provide details on troubled changesets in the repo'),
] + mergetoolopts,
_('[OPTIONS]...'))
def evolve(ui, repo, **opts):
@@ -1596,9 +1701,13 @@
(the default). You can combine ``--bumped`` or ``--divergent`` with
``--rev``, ``--all``, or ``--any``.
+ You can also use the evolve command to list the troubles affecting your
+ repository by using the --list flag. You can choose to display only some
+ categories of troubles with the --unstable, --divergent or --bumped flags.
"""
# Options
+ listopt = opts['list']
contopt = opts['continue']
anyopt = opts['any']
allopt = opts['all']
@@ -1608,6 +1717,10 @@
revopt = opts['rev']
troublecategories = ['bumped', 'divergent', 'unstable']
specifiedcategories = [t for t in troublecategories if opts[t]]
+ if listopt:
+ listtroubles(ui, repo, specifiedcategories, **opts)
+ return
+
targetcat = 'unstable'
if 1 < len(specifiedcategories):
msg = _('cannot specify more than one trouble category to solve (yet)')