# HG changeset patch # User Pulkit Goyal <7895pulkit@gmail.com> # Date 1516370554 -19800 # Node ID ece5cd58147d660ddaac67f7ef0bdef031147772 # Parent e97bfd529e72a1e9c027cd0b19b61d13c25620ab evolve: move the evolve command to evolvecmd.py This patch moves finishes the code movement by moving the evolve command to evolvecmd.py. diff -r e97bfd529e72 -r ece5cd58147d hgext3rd/evolve/__init__.py --- a/hgext3rd/evolve/__init__.py Sun Jan 21 20:33:39 2018 +0530 +++ b/hgext3rd/evolve/__init__.py Fri Jan 19 19:32:34 2018 +0530 @@ -292,12 +292,10 @@ node, obsolete, patch, - phases, revset, scmutil, ) -from mercurial.commands import mergetoolopts from mercurial.i18n import _ from mercurial.node import nullid @@ -357,6 +355,7 @@ eh = exthelper.exthelper() eh.merge(debugcmd.eh) +eh.merge(evolvecmd.eh) eh.merge(obsexchange.eh) eh.merge(checkheads.eh) eh.merge(safeguard.eh) @@ -946,216 +945,6 @@ _deprecatealias('gup', 'next') _deprecatealias('gdown', 'previous') -@eh.command( - '^evolve|stabilize|solve', - [('n', 'dry-run', False, - _('do not perform actions, just print what would be done')), - ('', 'confirm', False, - _('ask for confirmation before performing the action')), - ('A', 'any', False, - _('also consider troubled changesets unrelated to current working ' - 'directory')), - ('r', 'rev', [], _('solves troubles of these revisions')), - ('', 'bumped', False, _('solves only bumped changesets')), - ('', 'phase-divergent', False, _('solves only phase-divergent changesets')), - ('', 'divergent', False, _('solves only divergent changesets')), - ('', 'content-divergent', False, _('solves only content-divergent changesets')), - ('', 'unstable', False, _('solves only unstable changesets')), - ('', 'orphan', False, _('solves only orphan changesets (default)')), - ('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): - """solve troubled changesets in your repository - - Modifying history can lead to various types of troubled changesets: - unstable, bumped, or divergent. The evolve command resolves your troubles - by executing one of the following actions: - - - update working copy to a successor - - rebase an unstable changeset - - extract the desired changes from a bumped changeset - - fuse divergent changesets back together - - If you pass no arguments, evolve works in automatic mode: it will execute a - single action to reduce instability related to your working copy. There are - two cases for this action. First, if the parent of your working copy is - obsolete, evolve updates to the parent's successor. Second, if the working - copy parent is not obsolete but has obsolete predecessors, then evolve - determines if there is an unstable changeset that can be rebased onto the - working copy parent in order to reduce instability. - If so, evolve rebases that changeset. If not, evolve refuses to guess your - intention, and gives a hint about what you might want to do next. - - Any time evolve creates a changeset, it updates the working copy to the new - changeset. (Currently, every successful evolve operation involves an update - as well; this may change in future.) - - Automatic mode only handles common use cases. For example, it avoids taking - action in the case of ambiguity, and it ignores unstable changesets that - are not related to your working copy. - It also refuses to solve bumped or divergent changesets unless you - explicitly request such behavior (see below). - - Eliminating all instability around your working copy may require multiple - invocations of :hg:`evolve`. Alternately, use ``--all`` to recursively - select and evolve all unstable changesets that can be rebased onto the - working copy parent. - This is more powerful than successive invocations, since ``--all`` handles - ambiguous cases (e.g. unstable changesets with multiple children) by - evolving all branches. - - When your repository cannot be handled by automatic mode, you might need to - use ``--rev`` to specify a changeset to evolve. For example, if you have - an unstable changeset that is not related to the working copy parent, - you could use ``--rev`` to evolve it. Or, if some changeset has multiple - unstable children, evolve in automatic mode refuses to guess which one to - evolve; you have to use ``--rev`` in that case. - - Alternately, ``--any`` makes evolve search for the next evolvable changeset - regardless of whether it is related to the working copy parent. - - You can supply multiple revisions to evolve multiple troubled changesets - in a single invocation. In revset terms, ``--any`` is equivalent to ``--rev - first(unstable())``. ``--rev`` and ``--all`` are mutually exclusive, as are - ``--rev`` and ``--any``. - - ``hg evolve --any --all`` is useful for cleaning up instability across all - branches, letting evolve figure out the appropriate order and destination. - - When you have troubled changesets that are not unstable, :hg:`evolve` - refuses to consider them unless you specify the category of trouble you - wish to resolve, with ``--bumped`` or ``--divergent``. These options are - currently mutually exclusive with each other and with ``--unstable`` - (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. - """ - - opts = evolvecmd._checkevolveopts(repo, opts) - # Options - contopt = opts['continue'] - anyopt = opts['any'] - allopt = opts['all'] - startnode = repo['.'] - dryrunopt = opts['dry_run'] - confirmopt = opts['confirm'] - revopt = opts['rev'] - - troublecategories = ['phase_divergent', 'content_divergent', 'orphan'] - specifiedcategories = [t.replace('_', '') - for t in troublecategories - if opts[t]] - if opts['list']: - compat.startpager(ui, 'evolve') - evolvecmd.listtroubles(ui, repo, specifiedcategories, **opts) - return - - targetcat = 'orphan' - if 1 < len(specifiedcategories): - msg = _('cannot specify more than one trouble category to solve (yet)') - raise error.Abort(msg) - elif len(specifiedcategories) == 1: - targetcat = specifiedcategories[0] - elif repo['.'].obsolete(): - displayer = cmdutil.show_changeset(ui, repo, - {'template': shorttemplate}) - # no args and parent is obsolete, update to successors - try: - ctx = repo[utility._singlesuccessor(repo, repo['.'])] - except utility.MultipleSuccessorsError as exc: - repo.ui.write_err('parent is obsolete with multiple successors:\n') - for ln in exc.successorssets: - for n in ln: - displayer.show(repo[n]) - return 2 - - ui.status(_('update:')) - if not ui.quiet: - displayer.show(ctx) - - if dryrunopt: - return 0 - res = hg.update(repo, ctx.rev()) - if ctx != startnode: - ui.status(_('working directory is now at %s\n') % ctx) - return res - - ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'evolve') - troubled = set(repo.revs('troubled()')) - - # Progress handling - seen = 1 - count = allopt and len(troubled) or 1 - showprogress = allopt - - def progresscb(): - if revopt or allopt: - ui.progress(_('evolve'), seen, unit=_('changesets'), total=count) - - # Continuation handling - if contopt: - evolvestate = state.cmdstate(repo) - if not evolvestate: - raise error.Abort('no evolve to continue') - evolvestate.load() - orig = repo[evolvestate['current']] - with repo.wlock(), repo.lock(): - ctx = orig - source = ctx.extra().get('source') - extra = {} - if source: - extra['source'] = source - extra['intermediate-source'] = ctx.hex() - else: - extra['source'] = ctx.hex() - user = ctx.user() - date = ctx.date() - message = ctx.description() - ui.status(_('evolving %d:%s "%s"\n') % (ctx.rev(), ctx, - message.split('\n', 1)[0])) - targetphase = max(ctx.phase(), phases.draft) - overrides = {('phases', 'new-commit'): targetphase} - - with repo.ui.configoverride(overrides, 'evolve-continue'): - node = repo.commit(text=message, user=user, - date=date, extra=extra) - - obsolete.createmarkers(repo, [(ctx, (repo[node],))]) - evolvestate.delete() - return - - cmdutil.bailifchanged(repo) - - revs = evolvecmd._selectrevs(repo, allopt, revopt, anyopt, targetcat) - - if not revs: - return evolvecmd._handlenotrouble(ui, repo, allopt, revopt, anyopt, targetcat) - - # For the progress bar to show - count = len(revs) - replacements = {} - # Order the revisions - if targetcat == 'orphan': - revs = evolvecmd._orderrevs(repo, revs) - for rev in revs: - curctx = repo[rev] - progresscb() - ret = evolvecmd._solveone(ui, repo, curctx, dryrunopt, confirmopt, - progresscb, targetcat) - seen += 1 - if ret[0]: - replacements[curctx.node()] = [ret[1]] - progresscb() - evolvecmd._cleanup(ui, repo, startnode, showprogress) - def _gettopic(ctx): """handle topic fetching with or without the extension""" return getattr(ctx, 'topic', lambda: '')() diff -r e97bfd529e72 -r ece5cd58147d hgext3rd/evolve/evolvecmd.py --- a/hgext3rd/evolve/evolvecmd.py Sun Jan 21 20:33:39 2018 +0530 +++ b/hgext3rd/evolve/evolvecmd.py Fri Jan 19 19:32:34 2018 +0530 @@ -32,6 +32,7 @@ from . import ( cmdrewrite, compat, + exthelper, rewriteutil, state, utility, @@ -42,7 +43,9 @@ _bookmarksupdater = rewriteutil.bookmarksupdater sha1re = re.compile(r'\b[0-9a-f]{6,40}\b') +eh = exthelper.exthelper() _bookmarksupdater = rewriteutil.bookmarksupdater +mergetoolopts = cmdutil.mergetoolopts def _solveone(ui, repo, ctx, dryrun, confirm, progresscb, category): """Resolve the troubles affecting one revision @@ -949,3 +952,213 @@ }) return divergence + +@eh.command( + '^evolve|stabilize|solve', + [('n', 'dry-run', False, + _('do not perform actions, just print what would be done')), + ('', 'confirm', False, + _('ask for confirmation before performing the action')), + ('A', 'any', False, + _('also consider troubled changesets unrelated to current working ' + 'directory')), + ('r', 'rev', [], _('solves troubles of these revisions')), + ('', 'bumped', False, _('solves only bumped changesets')), + ('', 'phase-divergent', False, _('solves only phase-divergent changesets')), + ('', 'divergent', False, _('solves only divergent changesets')), + ('', 'content-divergent', False, _('solves only content-divergent changesets')), + ('', 'unstable', False, _('solves only unstable changesets')), + ('', 'orphan', False, _('solves only orphan changesets (default)')), + ('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): + """solve troubled changesets in your repository + + Modifying history can lead to various types of troubled changesets: + unstable, bumped, or divergent. The evolve command resolves your troubles + by executing one of the following actions: + + - update working copy to a successor + - rebase an unstable changeset + - extract the desired changes from a bumped changeset + - fuse divergent changesets back together + + If you pass no arguments, evolve works in automatic mode: it will execute a + single action to reduce instability related to your working copy. There are + two cases for this action. First, if the parent of your working copy is + obsolete, evolve updates to the parent's successor. Second, if the working + copy parent is not obsolete but has obsolete predecessors, then evolve + determines if there is an unstable changeset that can be rebased onto the + working copy parent in order to reduce instability. + If so, evolve rebases that changeset. If not, evolve refuses to guess your + intention, and gives a hint about what you might want to do next. + + Any time evolve creates a changeset, it updates the working copy to the new + changeset. (Currently, every successful evolve operation involves an update + as well; this may change in future.) + + Automatic mode only handles common use cases. For example, it avoids taking + action in the case of ambiguity, and it ignores unstable changesets that + are not related to your working copy. + It also refuses to solve bumped or divergent changesets unless you + explicitly request such behavior (see below). + + Eliminating all instability around your working copy may require multiple + invocations of :hg:`evolve`. Alternately, use ``--all`` to recursively + select and evolve all unstable changesets that can be rebased onto the + working copy parent. + This is more powerful than successive invocations, since ``--all`` handles + ambiguous cases (e.g. unstable changesets with multiple children) by + evolving all branches. + + When your repository cannot be handled by automatic mode, you might need to + use ``--rev`` to specify a changeset to evolve. For example, if you have + an unstable changeset that is not related to the working copy parent, + you could use ``--rev`` to evolve it. Or, if some changeset has multiple + unstable children, evolve in automatic mode refuses to guess which one to + evolve; you have to use ``--rev`` in that case. + + Alternately, ``--any`` makes evolve search for the next evolvable changeset + regardless of whether it is related to the working copy parent. + + You can supply multiple revisions to evolve multiple troubled changesets + in a single invocation. In revset terms, ``--any`` is equivalent to ``--rev + first(unstable())``. ``--rev`` and ``--all`` are mutually exclusive, as are + ``--rev`` and ``--any``. + + ``hg evolve --any --all`` is useful for cleaning up instability across all + branches, letting evolve figure out the appropriate order and destination. + + When you have troubled changesets that are not unstable, :hg:`evolve` + refuses to consider them unless you specify the category of trouble you + wish to resolve, with ``--bumped`` or ``--divergent``. These options are + currently mutually exclusive with each other and with ``--unstable`` + (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. + """ + + opts = _checkevolveopts(repo, opts) + # Options + contopt = opts['continue'] + anyopt = opts['any'] + allopt = opts['all'] + startnode = repo['.'] + dryrunopt = opts['dry_run'] + confirmopt = opts['confirm'] + revopt = opts['rev'] + + troublecategories = ['phase_divergent', 'content_divergent', 'orphan'] + specifiedcategories = [t.replace('_', '') + for t in troublecategories + if opts[t]] + if opts['list']: + compat.startpager(ui, 'evolve') + listtroubles(ui, repo, specifiedcategories, **opts) + return + + targetcat = 'orphan' + if 1 < len(specifiedcategories): + msg = _('cannot specify more than one trouble category to solve (yet)') + raise error.Abort(msg) + elif len(specifiedcategories) == 1: + targetcat = specifiedcategories[0] + elif repo['.'].obsolete(): + displayer = cmdutil.show_changeset(ui, repo, + {'template': shorttemplate}) + # no args and parent is obsolete, update to successors + try: + ctx = repo[utility._singlesuccessor(repo, repo['.'])] + except utility.MultipleSuccessorsError as exc: + repo.ui.write_err('parent is obsolete with multiple successors:\n') + for ln in exc.successorssets: + for n in ln: + displayer.show(repo[n]) + return 2 + + ui.status(_('update:')) + if not ui.quiet: + displayer.show(ctx) + + if dryrunopt: + return 0 + res = hg.update(repo, ctx.rev()) + if ctx != startnode: + ui.status(_('working directory is now at %s\n') % ctx) + return res + + ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'evolve') + troubled = set(repo.revs('troubled()')) + + # Progress handling + seen = 1 + count = allopt and len(troubled) or 1 + showprogress = allopt + + def progresscb(): + if revopt or allopt: + ui.progress(_('evolve'), seen, unit=_('changesets'), total=count) + + # Continuation handling + if contopt: + evolvestate = state.cmdstate(repo) + if not evolvestate: + raise error.Abort('no evolve to continue') + evolvestate.load() + orig = repo[evolvestate['current']] + with repo.wlock(), repo.lock(): + ctx = orig + source = ctx.extra().get('source') + extra = {} + if source: + extra['source'] = source + extra['intermediate-source'] = ctx.hex() + else: + extra['source'] = ctx.hex() + user = ctx.user() + date = ctx.date() + message = ctx.description() + ui.status(_('evolving %d:%s "%s"\n') % (ctx.rev(), ctx, + message.split('\n', 1)[0])) + targetphase = max(ctx.phase(), phases.draft) + overrides = {('phases', 'new-commit'): targetphase} + + with repo.ui.configoverride(overrides, 'evolve-continue'): + node = repo.commit(text=message, user=user, + date=date, extra=extra) + + obsolete.createmarkers(repo, [(ctx, (repo[node],))]) + evolvestate.delete() + return + + cmdutil.bailifchanged(repo) + + revs = _selectrevs(repo, allopt, revopt, anyopt, targetcat) + + if not revs: + return _handlenotrouble(ui, repo, allopt, revopt, anyopt, targetcat) + + # For the progress bar to show + count = len(revs) + replacements = {} + # Order the revisions + if targetcat == 'orphan': + revs = _orderrevs(repo, revs) + for rev in revs: + curctx = repo[rev] + progresscb() + ret = _solveone(ui, repo, curctx, dryrunopt, confirmopt, + progresscb, targetcat) + seen += 1 + if ret[0]: + replacements[curctx.node()] = [ret[1]] + progresscb() + _cleanup(ui, repo, startnode, showprogress)