# HG changeset patch # User Pulkit Goyal <7895pulkit@gmail.com> # Date 1516354452 -19800 # Node ID e147c18ed06418cb8d8ab251bdf6230d4861ae6a # Parent 6475d2046f87a234fe970333731993dc30cf1018 evolvecmd: move more functions from __init__.py to evolvecmd.py If things are looking ugly, hold on. diff -r 6475d2046f87 -r e147c18ed064 hgext3rd/evolve/__init__.py --- a/hgext3rd/evolve/__init__.py Fri Jan 19 14:42:46 2018 +0530 +++ b/hgext3rd/evolve/__init__.py Fri Jan 19 15:04:12 2018 +0530 @@ -285,7 +285,6 @@ cmdutil, commands, context, - copies, dirstate, error, extensions, @@ -1701,329 +1700,6 @@ result.add(unstable) return sorted(result - target) -def _solveunstable(ui, repo, orig, dryrun=False, confirm=False, - progresscb=None): - """ Tries to stabilize the changeset orig which is orphan. - - returns a tuple (bool, newnode) where, - bool: a boolean value indicating whether the instability was solved - newnode: if bool is True, then the newnode of the resultant commit - formed. newnode can be node, when resolution led to no new - commit. If bool is False, this is ''. - """ - pctx = orig.p1() - keepbranch = orig.p1().branch() != orig.branch() - if len(orig.parents()) == 2: - if not pctx.obsolete(): - pctx = orig.p2() # second parent is obsolete ? - keepbranch = orig.p2().branch() != orig.branch() - elif orig.p2().obsolete(): - hint = _("Redo the merge (%s) and use `hg prune " - "--succ ` to obsolete the old one") % orig.hex()[:12] - ui.warn(_("warning: no support for evolving merge changesets " - "with two obsolete parents yet\n") + - _("(%s)\n") % hint) - return (False, '') - - if not pctx.obsolete(): - ui.warn(_("cannot solve instability of %s, skipping\n") % orig) - return (False, '') - obs = pctx - newer = compat.successorssets(repo, obs.node()) - # search of a parent which is not killed - while not newer or newer == [()]: - ui.debug("stabilize target %s is plain dead," - " trying to stabilize on its parent\n" % - obs) - obs = obs.parents()[0] - newer = compat.successorssets(repo, obs.node()) - if len(newer) > 1: - msg = _("skipping %s: divergent rewriting. can't choose " - "destination\n") % obs - ui.write_err(msg) - return (False, '') - targets = newer[0] - assert targets - if len(targets) > 1: - # split target, figure out which one to pick, are they all in line? - targetrevs = [repo[r].rev() for r in targets] - roots = repo.revs('roots(%ld)', targetrevs) - heads = repo.revs('heads(%ld)', targetrevs) - if len(roots) > 1 or len(heads) > 1: - msg = "cannot solve split across two branches\n" - ui.write_err(msg) - return (False, '') - target = repo[heads.first()] - else: - target = targets[0] - displayer = cmdutil.show_changeset(ui, repo, {'template': shorttemplate}) - target = repo[target] - if not ui.quiet or confirm: - repo.ui.write(_('move:')) - displayer.show(orig) - repo.ui.write(_('atop:')) - displayer.show(target) - if confirm and ui.prompt('perform evolve? [Ny]', 'n') != 'y': - raise error.Abort(_('evolve aborted by user')) - if progresscb: - progresscb() - todo = 'hg rebase -r %s -d %s\n' % (orig, target) - if dryrun: - repo.ui.write(todo) - return (False, '') - else: - repo.ui.note(todo) - if progresscb: - progresscb() - try: - newid = relocate(repo, orig, target, pctx, keepbranch) - return (True, newid) - except MergeFailure: - ops = {'current': orig.node()} - evolvestate = state.cmdstate(repo, opts=ops) - evolvestate.save() - repo.ui.write_err(_('evolve failed!\n')) - repo.ui.write_err( - _("fix conflict and run 'hg evolve --continue'" - " or use 'hg update -C .' to abort\n")) - raise - -def _solvebumped(ui, repo, bumped, dryrun=False, confirm=False, - progresscb=None): - """Stabilize a bumped changeset - - returns a tuple (bool, newnode) where, - bool: a boolean value indicating whether the instability was solved - newnode: if bool is True, then the newnode of the resultant commit - formed. newnode can be node, when resolution led to no new - commit. If bool is False, this is ''. - """ - repo = repo.unfiltered() - bumped = repo[bumped.rev()] - # For now we deny bumped merge - if len(bumped.parents()) > 1: - msg = _('skipping %s : we do not handle merge yet\n') % bumped - ui.write_err(msg) - return (False, '') - prec = repo.set('last(allprecursors(%d) and public())', bumped).next() - # For now we deny target merge - if len(prec.parents()) > 1: - msg = _('skipping: %s: public version is a merge, ' - 'this is not handled yet\n') % prec - ui.write_err(msg) - return (False, '') - - displayer = cmdutil.show_changeset(ui, repo, {'template': shorttemplate}) - if not ui.quiet or confirm: - repo.ui.write(_('recreate:')) - displayer.show(bumped) - repo.ui.write(_('atop:')) - displayer.show(prec) - if confirm and ui.prompt('perform evolve? [Ny]', 'n') != 'y': - raise error.Abort(_('evolve aborted by user')) - if dryrun: - todo = 'hg rebase --rev %s --dest %s;\n' % (bumped, prec.p1()) - repo.ui.write(todo) - repo.ui.write(('hg update %s;\n' % prec)) - repo.ui.write(('hg revert --all --rev %s;\n' % bumped)) - repo.ui.write(('hg commit --msg "%s update to %s"\n' % - (TROUBLES['PHASEDIVERGENT'], bumped))) - return (False, '') - if progresscb: - progresscb() - newid = tmpctx = None - tmpctx = bumped - # Basic check for common parent. Far too complicated and fragile - tr = repo.currenttransaction() - assert tr is not None - bmupdate = _bookmarksupdater(repo, bumped.node(), tr) - if not list(repo.set('parents(%d) and parents(%d)', bumped, prec)): - # Need to rebase the changeset at the right place - repo.ui.status( - _('rebasing to destination parent: %s\n') % prec.p1()) - try: - tmpid = relocate(repo, bumped, prec.p1()) - if tmpid is not None: - tmpctx = repo[tmpid] - obsolete.createmarkers(repo, [(bumped, (tmpctx,))]) - except MergeFailure: - repo.vfs.write('graftstate', bumped.hex() + '\n') - repo.ui.write_err(_('evolution failed!\n')) - msg = _("fix conflict and run 'hg evolve --continue'\n") - repo.ui.write_err(msg) - raise - # Create the new commit context - repo.ui.status(_('computing new diff\n')) - files = set() - copied = copies.pathcopies(prec, bumped) - precmanifest = prec.manifest().copy() - # 3.3.2 needs a list. - # future 3.4 don't detect the size change during iteration - # this is fishy - for key, val in list(bumped.manifest().iteritems()): - precvalue = precmanifest.get(key, None) - if precvalue is not None: - del precmanifest[key] - if precvalue != val: - files.add(key) - files.update(precmanifest) # add missing files - # commit it - if files: # something to commit! - def filectxfn(repo, ctx, path): - if path in bumped: - fctx = bumped[path] - flags = fctx.flags() - mctx = compat.memfilectx(repo, ctx, fctx, flags, copied, path) - return mctx - return None - text = '%s update to %s:\n\n' % (TROUBLES['PHASEDIVERGENT'], prec) - text += bumped.description() - - new = context.memctx(repo, - parents=[prec.node(), node.nullid], - text=text, - files=files, - filectxfn=filectxfn, - user=bumped.user(), - date=bumped.date(), - extra=bumped.extra()) - - newid = repo.commitctx(new) - if newid is None: - obsolete.createmarkers(repo, [(tmpctx, ())]) - newid = prec.node() - else: - phases.retractboundary(repo, tr, bumped.phase(), [newid]) - obsolete.createmarkers(repo, [(tmpctx, (repo[newid],))], - flag=obsolete.bumpedfix) - bmupdate(newid) - repo.ui.status(_('committed as %s\n') % node.short(newid)) - # reroute the working copy parent to the new changeset - with repo.dirstate.parentchange(): - repo.dirstate.setparents(newid, node.nullid) - return (True, newid) - -def _solvedivergent(ui, repo, divergent, dryrun=False, confirm=False, - progresscb=None): - """tries to solve content-divergence of a changeset - - returns a tuple (bool, newnode) where, - bool: a boolean value indicating whether the instability was solved - newnode: if bool is True, then the newnode of the resultant commit - formed. newnode can be node, when resolution led to no new - commit. If bool is False, this is ''. - """ - repo = repo.unfiltered() - divergent = repo[divergent.rev()] - base, others = divergentdata(divergent) - if len(others) > 1: - othersstr = "[%s]" % (','.join([str(i) for i in others])) - msg = _("skipping %d:%s with a changeset that got split" - " into multiple ones:\n" - "|[%s]\n" - "| This is not handled by automatic evolution yet\n" - "| You have to fallback to manual handling with commands " - "such as:\n" - "| - hg touch -D\n" - "| - hg prune\n" - "| \n" - "| You should contact your local evolution Guru for help.\n" - ) % (divergent, TROUBLES['CONTENTDIVERGENT'], othersstr) - ui.write_err(msg) - return (False, '') - other = others[0] - if len(other.parents()) > 1: - msg = _("skipping %s: %s changeset can't be " - "a merge (yet)\n") % (divergent, TROUBLES['CONTENTDIVERGENT']) - ui.write_err(msg) - hint = _("You have to fallback to solving this by hand...\n" - "| This probably means redoing the merge and using \n" - "| `hg prune` to kill older version.\n") - ui.write_err(hint) - return (False, '') - if other.p1() not in divergent.parents(): - msg = _("skipping %s: have a different parent than %s " - "(not handled yet)\n") % (divergent, other) - hint = _("| %(d)s, %(o)s are not based on the same changeset.\n" - "| With the current state of its implementation, \n" - "| evolve does not work in that case.\n" - "| rebase one of them next to the other and run \n" - "| this command again.\n" - "| - either: hg rebase --dest 'p1(%(d)s)' -r %(o)s\n" - "| - or: hg rebase --dest 'p1(%(o)s)' -r %(d)s\n" - ) % {'d': divergent, 'o': other} - ui.write_err(msg) - ui.write_err(hint) - return (False, '') - - displayer = cmdutil.show_changeset(ui, repo, {'template': shorttemplate}) - if not ui.quiet or confirm: - ui.write(_('merge:')) - displayer.show(divergent) - ui.write(_('with: ')) - displayer.show(other) - ui.write(_('base: ')) - displayer.show(base) - if confirm and ui.prompt(_('perform evolve? [Ny]'), 'n') != 'y': - raise error.Abort(_('evolve aborted by user')) - if dryrun: - ui.write(('hg update -c %s &&\n' % divergent)) - ui.write(('hg merge %s &&\n' % other)) - ui.write(('hg commit -m "auto merge resolving conflict between ' - '%s and %s"&&\n' % (divergent, other))) - ui.write(('hg up -C %s &&\n' % base)) - ui.write(('hg revert --all --rev tip &&\n')) - ui.write(('hg commit -m "`hg log -r %s --template={desc}`";\n' - % divergent)) - return (False, '') - if divergent not in repo[None].parents(): - repo.ui.status(_('updating to "local" conflict\n')) - hg.update(repo, divergent.rev()) - repo.ui.note(_('merging %s changeset\n') % TROUBLES['CONTENTDIVERGENT']) - if progresscb: - progresscb() - stats = merge.update(repo, - other.node(), - branchmerge=True, - force=False, - ancestor=base.node(), - mergeancestor=True) - hg._showstats(repo, stats) - if stats[3]: - repo.ui.status(_("use 'hg resolve' to retry unresolved file merges " - "or 'hg update -C .' to abort\n")) - if stats[3] > 0: - raise error.Abort('merge conflict between several amendments ' - '(this is not automated yet)', - hint="""/!\ You can try: -/!\ * manual merge + resolve => new cset X -/!\ * hg up to the parent of the amended changeset (which are named W and Z) -/!\ * hg revert --all -r X -/!\ * hg ci -m "same message as the amended changeset" => new cset Y -/!\ * hg prune -n Y W Z -""") - if progresscb: - progresscb() - emtpycommitallowed = repo.ui.backupconfig('ui', 'allowemptycommit') - tr = repo.currenttransaction() - assert tr is not None - try: - repo.ui.setconfig('ui', 'allowemptycommit', True, 'evolve') - with repo.dirstate.parentchange(): - repo.dirstate.setparents(divergent.node(), node.nullid) - oldlen = len(repo) - cmdrewrite.amend(ui, repo, message='', logfile='') - if oldlen == len(repo): - new = divergent - # no changes - else: - new = repo['.'] - obsolete.createmarkers(repo, [(other, (new,))]) - phases.retractboundary(repo, tr, other.phase(), [new.node()]) - return (True, new.node()) - finally: - repo.ui.restoreconfig(emtpycommitallowed) - def divergentdata(ctx): """return base, other part of a conflict diff -r 6475d2046f87 -r e147c18ed064 hgext3rd/evolve/evolvecmd.py --- a/hgext3rd/evolve/evolvecmd.py Fri Jan 19 14:42:46 2018 +0530 +++ b/hgext3rd/evolve/evolvecmd.py Fri Jan 19 15:04:12 2018 +0530 @@ -9,10 +9,33 @@ """logic related to hg evolve command""" from mercurial import ( + cmdutil, + context, + copies, + error, + hg, lock as lockmod, + merge, + node, + obsolete, + phases, ) -from . import _solveunstable, _solvebumped, _solvedivergent +from mercurial.i18n import _ + +from . import ( + cmdrewrite, + compat, + rewriteutil, + state, + utility, +) + +TROUBLES = compat.TROUBLES +shorttemplate = utility.shorttemplate +_bookmarksupdater = rewriteutil.bookmarksupdater + +from . import relocate, divergentdata, MergeFailure def _solveone(ui, repo, ctx, dryrun, confirm, progresscb, category): """Resolve the troubles affecting one revision @@ -41,3 +64,326 @@ return result finally: lockmod.release(tr, lock, wlock) + +def _solveunstable(ui, repo, orig, dryrun=False, confirm=False, + progresscb=None): + """ Tries to stabilize the changeset orig which is orphan. + + returns a tuple (bool, newnode) where, + bool: a boolean value indicating whether the instability was solved + newnode: if bool is True, then the newnode of the resultant commit + formed. newnode can be node, when resolution led to no new + commit. If bool is False, this is ''. + """ + pctx = orig.p1() + keepbranch = orig.p1().branch() != orig.branch() + if len(orig.parents()) == 2: + if not pctx.obsolete(): + pctx = orig.p2() # second parent is obsolete ? + keepbranch = orig.p2().branch() != orig.branch() + elif orig.p2().obsolete(): + hint = _("Redo the merge (%s) and use `hg prune " + "--succ ` to obsolete the old one") % orig.hex()[:12] + ui.warn(_("warning: no support for evolving merge changesets " + "with two obsolete parents yet\n") + + _("(%s)\n") % hint) + return (False, '') + + if not pctx.obsolete(): + ui.warn(_("cannot solve instability of %s, skipping\n") % orig) + return (False, '') + obs = pctx + newer = compat.successorssets(repo, obs.node()) + # search of a parent which is not killed + while not newer or newer == [()]: + ui.debug("stabilize target %s is plain dead," + " trying to stabilize on its parent\n" % + obs) + obs = obs.parents()[0] + newer = compat.successorssets(repo, obs.node()) + if len(newer) > 1: + msg = _("skipping %s: divergent rewriting. can't choose " + "destination\n") % obs + ui.write_err(msg) + return (False, '') + targets = newer[0] + assert targets + if len(targets) > 1: + # split target, figure out which one to pick, are they all in line? + targetrevs = [repo[r].rev() for r in targets] + roots = repo.revs('roots(%ld)', targetrevs) + heads = repo.revs('heads(%ld)', targetrevs) + if len(roots) > 1 or len(heads) > 1: + msg = "cannot solve split across two branches\n" + ui.write_err(msg) + return (False, '') + target = repo[heads.first()] + else: + target = targets[0] + displayer = cmdutil.show_changeset(ui, repo, {'template': shorttemplate}) + target = repo[target] + if not ui.quiet or confirm: + repo.ui.write(_('move:')) + displayer.show(orig) + repo.ui.write(_('atop:')) + displayer.show(target) + if confirm and ui.prompt('perform evolve? [Ny]', 'n') != 'y': + raise error.Abort(_('evolve aborted by user')) + if progresscb: + progresscb() + todo = 'hg rebase -r %s -d %s\n' % (orig, target) + if dryrun: + repo.ui.write(todo) + return (False, '') + else: + repo.ui.note(todo) + if progresscb: + progresscb() + try: + newid = relocate(repo, orig, target, pctx, keepbranch) + return (True, newid) + except MergeFailure: + ops = {'current': orig.node()} + evolvestate = state.cmdstate(repo, opts=ops) + evolvestate.save() + repo.ui.write_err(_('evolve failed!\n')) + repo.ui.write_err( + _("fix conflict and run 'hg evolve --continue'" + " or use 'hg update -C .' to abort\n")) + raise + +def _solvebumped(ui, repo, bumped, dryrun=False, confirm=False, + progresscb=None): + """Stabilize a bumped changeset + + returns a tuple (bool, newnode) where, + bool: a boolean value indicating whether the instability was solved + newnode: if bool is True, then the newnode of the resultant commit + formed. newnode can be node, when resolution led to no new + commit. If bool is False, this is ''. + """ + repo = repo.unfiltered() + bumped = repo[bumped.rev()] + # For now we deny bumped merge + if len(bumped.parents()) > 1: + msg = _('skipping %s : we do not handle merge yet\n') % bumped + ui.write_err(msg) + return (False, '') + prec = repo.set('last(allprecursors(%d) and public())', bumped).next() + # For now we deny target merge + if len(prec.parents()) > 1: + msg = _('skipping: %s: public version is a merge, ' + 'this is not handled yet\n') % prec + ui.write_err(msg) + return (False, '') + + displayer = cmdutil.show_changeset(ui, repo, {'template': shorttemplate}) + if not ui.quiet or confirm: + repo.ui.write(_('recreate:')) + displayer.show(bumped) + repo.ui.write(_('atop:')) + displayer.show(prec) + if confirm and ui.prompt('perform evolve? [Ny]', 'n') != 'y': + raise error.Abort(_('evolve aborted by user')) + if dryrun: + todo = 'hg rebase --rev %s --dest %s;\n' % (bumped, prec.p1()) + repo.ui.write(todo) + repo.ui.write(('hg update %s;\n' % prec)) + repo.ui.write(('hg revert --all --rev %s;\n' % bumped)) + repo.ui.write(('hg commit --msg "%s update to %s"\n' % + (TROUBLES['PHASEDIVERGENT'], bumped))) + return (False, '') + if progresscb: + progresscb() + newid = tmpctx = None + tmpctx = bumped + # Basic check for common parent. Far too complicated and fragile + tr = repo.currenttransaction() + assert tr is not None + bmupdate = _bookmarksupdater(repo, bumped.node(), tr) + if not list(repo.set('parents(%d) and parents(%d)', bumped, prec)): + # Need to rebase the changeset at the right place + repo.ui.status( + _('rebasing to destination parent: %s\n') % prec.p1()) + try: + tmpid = relocate(repo, bumped, prec.p1()) + if tmpid is not None: + tmpctx = repo[tmpid] + obsolete.createmarkers(repo, [(bumped, (tmpctx,))]) + except MergeFailure: + repo.vfs.write('graftstate', bumped.hex() + '\n') + repo.ui.write_err(_('evolution failed!\n')) + msg = _("fix conflict and run 'hg evolve --continue'\n") + repo.ui.write_err(msg) + raise + # Create the new commit context + repo.ui.status(_('computing new diff\n')) + files = set() + copied = copies.pathcopies(prec, bumped) + precmanifest = prec.manifest().copy() + # 3.3.2 needs a list. + # future 3.4 don't detect the size change during iteration + # this is fishy + for key, val in list(bumped.manifest().iteritems()): + precvalue = precmanifest.get(key, None) + if precvalue is not None: + del precmanifest[key] + if precvalue != val: + files.add(key) + files.update(precmanifest) # add missing files + # commit it + if files: # something to commit! + def filectxfn(repo, ctx, path): + if path in bumped: + fctx = bumped[path] + flags = fctx.flags() + mctx = compat.memfilectx(repo, ctx, fctx, flags, copied, path) + return mctx + return None + text = '%s update to %s:\n\n' % (TROUBLES['PHASEDIVERGENT'], prec) + text += bumped.description() + + new = context.memctx(repo, + parents=[prec.node(), node.nullid], + text=text, + files=files, + filectxfn=filectxfn, + user=bumped.user(), + date=bumped.date(), + extra=bumped.extra()) + + newid = repo.commitctx(new) + if newid is None: + obsolete.createmarkers(repo, [(tmpctx, ())]) + newid = prec.node() + else: + phases.retractboundary(repo, tr, bumped.phase(), [newid]) + obsolete.createmarkers(repo, [(tmpctx, (repo[newid],))], + flag=obsolete.bumpedfix) + bmupdate(newid) + repo.ui.status(_('committed as %s\n') % node.short(newid)) + # reroute the working copy parent to the new changeset + with repo.dirstate.parentchange(): + repo.dirstate.setparents(newid, node.nullid) + return (True, newid) + +def _solvedivergent(ui, repo, divergent, dryrun=False, confirm=False, + progresscb=None): + """tries to solve content-divergence of a changeset + + returns a tuple (bool, newnode) where, + bool: a boolean value indicating whether the instability was solved + newnode: if bool is True, then the newnode of the resultant commit + formed. newnode can be node, when resolution led to no new + commit. If bool is False, this is ''. + """ + repo = repo.unfiltered() + divergent = repo[divergent.rev()] + base, others = divergentdata(divergent) + if len(others) > 1: + othersstr = "[%s]" % (','.join([str(i) for i in others])) + msg = _("skipping %d:%s with a changeset that got split" + " into multiple ones:\n" + "|[%s]\n" + "| This is not handled by automatic evolution yet\n" + "| You have to fallback to manual handling with commands " + "such as:\n" + "| - hg touch -D\n" + "| - hg prune\n" + "| \n" + "| You should contact your local evolution Guru for help.\n" + ) % (divergent, TROUBLES['CONTENTDIVERGENT'], othersstr) + ui.write_err(msg) + return (False, '') + other = others[0] + if len(other.parents()) > 1: + msg = _("skipping %s: %s changeset can't be " + "a merge (yet)\n") % (divergent, TROUBLES['CONTENTDIVERGENT']) + ui.write_err(msg) + hint = _("You have to fallback to solving this by hand...\n" + "| This probably means redoing the merge and using \n" + "| `hg prune` to kill older version.\n") + ui.write_err(hint) + return (False, '') + if other.p1() not in divergent.parents(): + msg = _("skipping %s: have a different parent than %s " + "(not handled yet)\n") % (divergent, other) + hint = _("| %(d)s, %(o)s are not based on the same changeset.\n" + "| With the current state of its implementation, \n" + "| evolve does not work in that case.\n" + "| rebase one of them next to the other and run \n" + "| this command again.\n" + "| - either: hg rebase --dest 'p1(%(d)s)' -r %(o)s\n" + "| - or: hg rebase --dest 'p1(%(o)s)' -r %(d)s\n" + ) % {'d': divergent, 'o': other} + ui.write_err(msg) + ui.write_err(hint) + return (False, '') + + displayer = cmdutil.show_changeset(ui, repo, {'template': shorttemplate}) + if not ui.quiet or confirm: + ui.write(_('merge:')) + displayer.show(divergent) + ui.write(_('with: ')) + displayer.show(other) + ui.write(_('base: ')) + displayer.show(base) + if confirm and ui.prompt(_('perform evolve? [Ny]'), 'n') != 'y': + raise error.Abort(_('evolve aborted by user')) + if dryrun: + ui.write(('hg update -c %s &&\n' % divergent)) + ui.write(('hg merge %s &&\n' % other)) + ui.write(('hg commit -m "auto merge resolving conflict between ' + '%s and %s"&&\n' % (divergent, other))) + ui.write(('hg up -C %s &&\n' % base)) + ui.write(('hg revert --all --rev tip &&\n')) + ui.write(('hg commit -m "`hg log -r %s --template={desc}`";\n' + % divergent)) + return (False, '') + if divergent not in repo[None].parents(): + repo.ui.status(_('updating to "local" conflict\n')) + hg.update(repo, divergent.rev()) + repo.ui.note(_('merging %s changeset\n') % TROUBLES['CONTENTDIVERGENT']) + if progresscb: + progresscb() + stats = merge.update(repo, + other.node(), + branchmerge=True, + force=False, + ancestor=base.node(), + mergeancestor=True) + hg._showstats(repo, stats) + if stats[3]: + repo.ui.status(_("use 'hg resolve' to retry unresolved file merges " + "or 'hg update -C .' to abort\n")) + if stats[3] > 0: + raise error.Abort('merge conflict between several amendments ' + '(this is not automated yet)', + hint="""/!\ You can try: +/!\ * manual merge + resolve => new cset X +/!\ * hg up to the parent of the amended changeset (which are named W and Z) +/!\ * hg revert --all -r X +/!\ * hg ci -m "same message as the amended changeset" => new cset Y +/!\ * hg prune -n Y W Z +""") + if progresscb: + progresscb() + emtpycommitallowed = repo.ui.backupconfig('ui', 'allowemptycommit') + tr = repo.currenttransaction() + assert tr is not None + try: + repo.ui.setconfig('ui', 'allowemptycommit', True, 'evolve') + with repo.dirstate.parentchange(): + repo.dirstate.setparents(divergent.node(), node.nullid) + oldlen = len(repo) + cmdrewrite.amend(ui, repo, message='', logfile='') + if oldlen == len(repo): + new = divergent + # no changes + else: + new = repo['.'] + obsolete.createmarkers(repo, [(other, (new,))]) + phases.retractboundary(repo, tr, other.phase(), [new.node()]) + return (True, new.node()) + finally: + repo.ui.restoreconfig(emtpycommitallowed)