Mercurial > evolve
comparison hgext/evolve.py @ 1634:9ae4e79a28f3
evolve--list: initial implementation
This implementation does not work with '-T json' since it needs multiple levels
of depth.
There is various small issue with the current data, the test coverage is a bit
low and the output is likely to change, but this is a good step forward.
Sample output:
01a3e66ba030: e (amended)
unstable: 1995fc658ad6 (unstable parent)
divergent: 84e1c6ae319d d3b90e9c84ab (precursor 3efa43a7427b)
divergent: add9a356b8cf (precursor 3efa43a7427b)
add9a356b8cf: e (rebased)
divergent: 84e1c6ae319d d3b90e9c84ab (precursor 3efa43a7427b)
divergent: 01a3e66ba030 (precursor 3efa43a7427b)
84e1c6ae319d: e (e+f split)
unstable: 1995fc658ad6 (unstable parent)
divergent: 01a3e66ba030 (precursor 3efa43a7427b)
divergent: add9a356b8cf (precursor 3efa43a7427b)
d3b90e9c84ab: f (e+f split)
unstable: 84e1c6ae319d (unstable parent)
divergent: 01a3e66ba030 (precursor 3efa43a7427b)
divergent: add9a356b8cf (precursor 3efa43a7427b)
8febfaee0dd1: c
unstable: 43765473b851 (obsolete parent)
bumped: b36d99df9f41 (immutable precursor)
1995fc658ad6: d: commit with a long happy message, ababagalamaga, ababagal...
unstable: 8febfaee0dd1 (unstable parent)
fa8498ad030f: aa
unstable: d3b90e9c84ab (unstable parent)
author | Kostia Balytskyi <ikostia@fb.com> |
---|---|
date | Tue, 22 Mar 2016 14:08:16 -0700 |
parents | 9bcb24c3ba8d |
children | 91ba7e0daff6 |
comparison
equal
deleted
inserted
replaced
1633:9bcb24c3ba8d | 1634:9ae4e79a28f3 |
---|---|
1512 ordering.append(rev) | 1512 ordering.append(rev) |
1513 | 1513 |
1514 ordering.extend(sorted(dependencies)) | 1514 ordering.extend(sorted(dependencies)) |
1515 return ordering | 1515 return ordering |
1516 | 1516 |
1517 def divergentsets(repo, ctx): | |
1518 """Compute sets of commits divergent with a given one""" | |
1519 cache = {} | |
1520 succsets = {} | |
1521 base = {} | |
1522 for n in obsolete.allprecursors(repo.obsstore, [ctx.node()]): | |
1523 if n == ctx.node(): | |
1524 # a node can't be a base for divergence with itself | |
1525 continue | |
1526 nsuccsets = obsolete.successorssets(repo, n, cache) | |
1527 for nsuccset in nsuccsets: | |
1528 if ctx.node() in nsuccset: | |
1529 # we are only interested in *other* successor sets | |
1530 continue | |
1531 if tuple(nsuccset) in base: | |
1532 # we already know the latest base for this divergency | |
1533 continue | |
1534 base[tuple(nsuccset)] = n | |
1535 divergence = [] | |
1536 for divset, b in base.iteritems(): | |
1537 divergence.append({ | |
1538 'divergentnodes': divset, | |
1539 'commonprecursor': b | |
1540 }) | |
1541 | |
1542 return divergence | |
1543 | |
1544 def _preparelistctxs(items, condition): | |
1545 return [item.hex() for item in items if condition(item)] | |
1546 | |
1547 def _formatctx(fm, ctx): | |
1548 fm.data(node=ctx.hex()) | |
1549 fm.data(desc=ctx.description()) | |
1550 fm.data(date=ctx.date()) | |
1551 fm.data(user=ctx.user()) | |
1552 | |
1553 def listtroubles(ui, repo, troublecategories, **opts): | |
1554 """Print all the troubles for the repo (or given revset)""" | |
1555 troublecategories = troublecategories or ['divergent', 'unstable', 'bumped'] | |
1556 showunstable = 'unstable' in troublecategories | |
1557 showbumped = 'bumped' in troublecategories | |
1558 showdivergent = 'divergent' in troublecategories | |
1559 | |
1560 revs = repo.revs('+'.join("%s()" % t for t in troublecategories)) | |
1561 if opts.get('rev'): | |
1562 revs = revs & repo.revs(opts.get('rev')) | |
1563 | |
1564 fm = ui.formatter('evolvelist', opts) | |
1565 for rev in revs: | |
1566 ctx = repo[rev] | |
1567 unpars = _preparelistctxs(ctx.parents(), lambda p: p.unstable()) | |
1568 obspars = _preparelistctxs(ctx.parents(), lambda p: p.obsolete()) | |
1569 imprecs = _preparelistctxs(repo.set("allprecursors(%n)", ctx.node()), | |
1570 lambda p: not p.mutable()) | |
1571 dsets = divergentsets(repo, ctx) | |
1572 | |
1573 fm.startitem() | |
1574 # plain formatter section | |
1575 hashlen, desclen = 12, 60 | |
1576 desc = ctx.description() | |
1577 desc = (desc[:desclen] + '...') if len(desc) > desclen else desc | |
1578 fm.plain('%s: ' % ctx.hex()[:hashlen]) | |
1579 fm.plain('%s\n' % desc) | |
1580 | |
1581 for unpar in unpars if showunstable else []: | |
1582 fm.plain(' unstable: %s (unstable parent)\n' % unpar[:hashlen]) | |
1583 for obspar in obspars if showunstable else []: | |
1584 fm.plain(' unstable: %s (obsolete parent)\n' % obspar[:hashlen]) | |
1585 for imprec in imprecs if showbumped else []: | |
1586 fm.plain(' bumped: %s (immutable precursor)\n' % imprec[:hashlen]) | |
1587 | |
1588 if dsets and showdivergent: | |
1589 for dset in dsets: | |
1590 fm.plain(' divergent: ') | |
1591 first = True | |
1592 for n in dset['divergentnodes']: | |
1593 t = "%s" if first else " %s" | |
1594 first = False | |
1595 fm.plain(t % node.hex(n)[:hashlen]) | |
1596 comprec = node.hex(dset['commonprecursor'])[:hashlen] | |
1597 fm.plain(" (precursor %s)\n" % comprec) | |
1598 fm.plain("\n") | |
1599 | |
1600 # templater-friendly section | |
1601 _formatctx(fm, ctx) | |
1602 troubles = [] | |
1603 for unpar in unpars: | |
1604 troubles.append({'troubletype': 'unstable', 'sourcenode': unpar, | |
1605 'sourcetype': 'unstableparent'}) | |
1606 for obspar in obspars: | |
1607 troubles.append({'troubletype': 'unstable', 'sourcenode': obspar, | |
1608 'sourcetype': 'obsoleteparent'}) | |
1609 for imprec in imprecs: | |
1610 troubles.append({'troubletype': 'bumped', 'sourcenode': imprec, | |
1611 'sourcetype': 'immutableprecursor'}) | |
1612 for dset in dsets: | |
1613 divnodes = [{'node': n} for n in dset['divergentnodes']] | |
1614 troubles.append({'troubletype': 'divergent', | |
1615 'commonprecursor': dset['commonprecursor'], | |
1616 'divergentnodes': divnodes}) | |
1617 fm.data(troubles=troubles) | |
1618 | |
1619 fm.end() | |
1620 | |
1517 @command('^evolve|stabilize|solve', | 1621 @command('^evolve|stabilize|solve', |
1518 [('n', 'dry-run', False, | 1622 [('n', 'dry-run', False, |
1519 _('do not perform actions, just print what would be done')), | 1623 _('do not perform actions, just print what would be done')), |
1520 ('', 'confirm', False, | 1624 ('', 'confirm', False, |
1521 _('ask for confirmation before performing the action')), | 1625 _('ask for confirmation before performing the action')), |
1527 ('', 'divergent', False, _('solves only divergent changesets')), | 1631 ('', 'divergent', False, _('solves only divergent changesets')), |
1528 ('', 'unstable', False, _('solves only unstable changesets (default)')), | 1632 ('', 'unstable', False, _('solves only unstable changesets (default)')), |
1529 ('a', 'all', False, _('evolve all troubled changesets related to the ' | 1633 ('a', 'all', False, _('evolve all troubled changesets related to the ' |
1530 'current working directory and its descendants')), | 1634 'current working directory and its descendants')), |
1531 ('c', 'continue', False, _('continue an interrupted evolution')), | 1635 ('c', 'continue', False, _('continue an interrupted evolution')), |
1636 ('l', 'list', False, 'provide details on troubled changesets in the repo'), | |
1532 ] + mergetoolopts, | 1637 ] + mergetoolopts, |
1533 _('[OPTIONS]...')) | 1638 _('[OPTIONS]...')) |
1534 def evolve(ui, repo, **opts): | 1639 def evolve(ui, repo, **opts): |
1535 """solve troubled changesets in your repository | 1640 """solve troubled changesets in your repository |
1536 | 1641 |
1594 wish to resolve, with ``--bumped`` or ``--divergent``. These options are | 1699 wish to resolve, with ``--bumped`` or ``--divergent``. These options are |
1595 currently mutually exclusive with each other and with ``--unstable`` | 1700 currently mutually exclusive with each other and with ``--unstable`` |
1596 (the default). You can combine ``--bumped`` or ``--divergent`` with | 1701 (the default). You can combine ``--bumped`` or ``--divergent`` with |
1597 ``--rev``, ``--all``, or ``--any``. | 1702 ``--rev``, ``--all``, or ``--any``. |
1598 | 1703 |
1704 You can also use the evolve command to list the troubles affecting your | |
1705 repository by using the --list flag. You can choose to display only some | |
1706 categories of troubles with the --unstable, --divergent or --bumped flags. | |
1599 """ | 1707 """ |
1600 | 1708 |
1601 # Options | 1709 # Options |
1710 listopt = opts['list'] | |
1602 contopt = opts['continue'] | 1711 contopt = opts['continue'] |
1603 anyopt = opts['any'] | 1712 anyopt = opts['any'] |
1604 allopt = opts['all'] | 1713 allopt = opts['all'] |
1605 startnode = repo['.'] | 1714 startnode = repo['.'] |
1606 dryrunopt = opts['dry_run'] | 1715 dryrunopt = opts['dry_run'] |
1607 confirmopt = opts['confirm'] | 1716 confirmopt = opts['confirm'] |
1608 revopt = opts['rev'] | 1717 revopt = opts['rev'] |
1609 troublecategories = ['bumped', 'divergent', 'unstable'] | 1718 troublecategories = ['bumped', 'divergent', 'unstable'] |
1610 specifiedcategories = [t for t in troublecategories if opts[t]] | 1719 specifiedcategories = [t for t in troublecategories if opts[t]] |
1720 if listopt: | |
1721 listtroubles(ui, repo, specifiedcategories, **opts) | |
1722 return | |
1723 | |
1611 targetcat = 'unstable' | 1724 targetcat = 'unstable' |
1612 if 1 < len(specifiedcategories): | 1725 if 1 < len(specifiedcategories): |
1613 msg = _('cannot specify more than one trouble category to solve (yet)') | 1726 msg = _('cannot specify more than one trouble category to solve (yet)') |
1614 raise error.Abort(msg) | 1727 raise error.Abort(msg) |
1615 elif len(specifiedcategories) == 1: | 1728 elif len(specifiedcategories) == 1: |