diff -r fcdd9b8c970b -r 97d8a652f9b9 hgext/evolve.py --- a/hgext/evolve.py Mon Mar 03 19:27:42 2014 -0800 +++ b/hgext/evolve.py Tue Mar 04 11:02:42 2014 -0800 @@ -569,6 +569,7 @@ # XXX this could wrap transaction code # XXX (but this is a bit a layer violation) @eh.wrapcommand("commit") +@eh.wrapcommand("import") @eh.wrapcommand("push") @eh.wrapcommand("pull") @eh.wrapcommand("graft") @@ -620,8 +621,7 @@ return result repo.__class__ = evolvingrepo -@eh.wrapcommand("summary") -def obssummary(orig, ui, repo, *args, **kwargs): +def summaryhook(ui, repo): def write(fmt, count): s = fmt % count if count: @@ -629,14 +629,16 @@ else: ui.note(s) - ret = orig(ui, repo, *args, **kwargs) nbunstable = len(getrevs(repo, 'unstable')) nbbumped = len(getrevs(repo, 'bumped')) nbdivergent = len(getrevs(repo, 'divergent')) write('unstable: %i changesets\n', nbunstable) write('bumped: %i changesets\n', nbbumped) write('divergent: %i changesets\n', nbdivergent) - return ret + +@eh.extsetup +def obssummarysetup(ui): + cmdutil.summaryhooks.add('evolve', summaryhook) ##################################################################### @@ -766,7 +768,10 @@ try: rebase = extensions.find('rebase') # dummy state to trick rebase node - assert orig.p2().rev() == node.nullrev, 'no support yet' + if not orig.p2().rev() == node.nullrev: + raise util.Abort( + 'no support for evolution merge changesets yet', + hint="Redo the merge a use `hg prune` to obsolete the old one") destbookmarks = repo.nodebookmarks(dest.node()) cmdutil.duplicatecopies(repo, orig.node(), dest.node()) nodesrc = orig.node() @@ -925,31 +930,53 @@ ui.write_err(_('no troubled changesets\n')) return 1 + def progresscb(): + if allopt: + ui.progress('evolve', seen, unit='changesets', total=count) + seen = 1 + count = allopt and _counttroubled(ui, repo) or 1 + while tr is not None: - result = _evolveany(ui, repo, tr, dryrunopt) + progresscb() + result = _evolveany(ui, repo, tr, dryrunopt, progresscb=progresscb) + progresscb() + seen += 1 if not allopt: return result + progresscb() tr = _picknexttroubled(ui, repo, anyopt or allopt) + if allopt: + ui.progress('evolve', None) -def _evolveany(ui, repo, tr, dryrunopt): + +def _evolveany(ui, repo, tr, dryrunopt, progresscb): repo = repo.unfiltered() tr = repo[tr.rev()] cmdutil.bailifchanged(repo) troubles = tr.troubles() if 'unstable' in troubles: - return _solveunstable(ui, repo, tr, dryrunopt) + return _solveunstable(ui, repo, tr, dryrunopt, progresscb) elif 'bumped' in troubles: - return _solvebumped(ui, repo, tr, dryrunopt) + return _solvebumped(ui, repo, tr, dryrunopt, progresscb) elif 'divergent' in troubles: repo = repo.unfiltered() tr = repo[tr.rev()] - return _solvedivergent(ui, repo, tr, dryrunopt) + return _solvedivergent(ui, repo, tr, dryrunopt, progresscb) else: assert False # WHAT? unknown troubles -def _picknexttroubled(ui, repo, pickany=False): +def _counttroubled(ui, repo): + """Count the amount of troubled changesets""" + troubled = set() + troubled.update(getrevs(repo, 'unstable')) + troubled.update(getrevs(repo, 'bumped')) + troubled.update(getrevs(repo, 'divergent')) + return len(troubled) + +def _picknexttroubled(ui, repo, pickany=False, progresscb=None): """Pick a the next trouble changeset to solve""" + if progresscb: progresscb() tr = _stabilizableunstable(repo, repo['.']) if tr is None: wdp = repo['.'] @@ -988,7 +1015,7 @@ return child return None -def _solveunstable(ui, repo, orig, dryrun=False): +def _solveunstable(ui, repo, orig, dryrun=False, progresscb=None): """Stabilize a unstable changeset""" obs = orig.parents()[0] if not obs.obsolete(): @@ -1019,11 +1046,13 @@ repo.ui.status(_('atop:')) if not ui.quiet: displayer.show(target) + if progresscb: progresscb() todo = 'hg rebase -r %s -d %s\n' % (orig, target) if dryrun: repo.ui.write(todo) else: repo.ui.note(todo) + if progresscb: progresscb() lock = repo.lock() try: relocate(repo, orig, target) @@ -1035,7 +1064,7 @@ finally: lock.release() -def _solvebumped(ui, repo, bumped, dryrun=False): +def _solvebumped(ui, repo, bumped, dryrun=False, progresscb=None): """Stabilize a bumped changeset""" # For now we deny bumped merge if len(bumped.parents()) > 1: @@ -1061,6 +1090,7 @@ repo.ui.write('hg revert --all --rev %s;\n' % bumped) repo.ui.write('hg commit --msg "bumped update to %s"') return 0 + if progresscb: progresscb() wlock = repo.wlock() try: newid = tmpctx = None @@ -1137,17 +1167,40 @@ finally: wlock.release() -def _solvedivergent(ui, repo, divergent, dryrun=False): +def _solvedivergent(ui, repo, divergent, dryrun=False, progresscb=None): base, others = divergentdata(divergent) if len(others) > 1: - raise util.Abort("We do not handle split yet") + othersstr = "[%s]" % (','.join([str(i) for i in others])) + hint = ("changeset %d is divergent with a changeset that got splitted " + "| into multiple ones:\n[%s]\n" + "| This is not handled by automatic evolution yet\n" + "| You have to fallback to manual handling with commands as:\n" + "| - hg touch -D\n" + "| - hg prune\n" + "| \n" + "| You should contact your local evolution Guru for help.\n" + % (divergent, othersstr)) + raise util.Abort("We do not handle divergence with split yet", + hint='') other = others[0] if divergent.phase() <= phases.public: - raise util.Abort("We can't resolve this conflict from the public side") + raise util.Abort("We can't resolve this conflict from the public side", + hint="%s is public, try from %s" % (divergent, other)) if len(other.parents()) > 1: - raise util.Abort("divergent changeset can't be a merge (yet)") + raise util.Abort("divergent changeset can't be a merge (yet)", + hint="You have to fallback to solving this by hand...\n" + "| This probably mean to redo the merge and use " + "| `hg prune` to kill older version.") if other.p1() not in divergent.parents(): - raise util.Abort("parents are not common (not handled yet)") + raise util.Abort("parents are not common (not handled yet)", + hint="| %(d)s, %(o)s are not based on the same changeset." + "| With the current state of its implementation, " + "| evolve does not work in that case.\n" + "| rebase one of them next to the other and run " + "| this command again.\n" + "| - either: hg rebase -dest 'p1(%(d)s)' -r %(o)s" + "| - or: hg rebase -dest 'p1(%(d)s)' -r %(o)s" + % {'d': divergent, 'o': other}) displayer = cmdutil.show_changeset(ui, repo, {'template': shorttemplate}) ui.status(_('merge:')) @@ -1177,6 +1230,7 @@ repo.ui.status(_('updating to "local" conflict\n')) hg.update(repo, divergent.rev()) repo.ui.note(_('merging divergent changeset\n')) + if progresscb: progresscb() stats = merge.update(repo, other.node(), branchmerge=True, @@ -1197,6 +1251,7 @@ /!\ * hg ci -m "same message as the amended changeset" => new cset Y /!\ * hg kill -n Y W Z """) + if progresscb: progresscb() tr = repo.transaction('stabilize-divergent') try: repo.dirstate.setparents(divergent.node(), node.nullid) @@ -1332,6 +1387,7 @@ [('n', 'new', [], _("successor changeset (DEPRECATED)")), ('s', 'succ', [], _("successor changeset")), ('r', 'rev', [], _("revisions to prune")), + ('', 'biject', False, _("do a 1-1 map between rev and successor ranges")), ('B', 'bookmark', '', _("remove revs only reachable from given" " bookmark"))] + metadataopts, _('[OPTION] [-r] REV...')) @@ -1347,13 +1403,19 @@ When the working directory parent is pruned the repository is updated to a non obsolete parents. - you can use the ``--succ`` option to informs mercurial that a newer version + You can use the ``--succ`` option to informs mercurial that a newer version of the pruned changeset exists. + + You can use the ``--biject`` option to specify a 1-1 (bijection) between + revisions to prune and successor changesets. This option may be removed in + a future release (with the functionality absored automatically). + """ revs = set(scmutil.revrange(repo, list(revs) + opts.get('rev'))) succs = opts['new'] + opts['succ'] bookmark = opts.get('bookmark') metadata = _getmetadata(**opts) + biject = opts.get('biject') if bookmark: marks,revs = _reachablefrombookmark(repo, revs, bookmark) @@ -1383,11 +1445,20 @@ # defines successors changesets sucs = tuple(repo[n] for n in sortedrevs(succs)) - if len(sucs) > 1 and len(precs) > 1: + if not biject and len(sucs) > 1 and len(precs) > 1: msg = "Can't use multiple successors for multiple precursors" raise util.Abort(msg) + + if biject and len(sucs) != len(precs): + msg = "Can't use %d successors for %d precursors" % (len(sucs), len(precs)) + raise util.Abort(msg) + + relations = [(p, sucs) for p in precs] + if biject: + relations = [(p, (s,)) for p, s in zip(precs, sucs)] + # create markers - createmarkers(repo, [(p, sucs) for p in precs], metadata=metadata) + createmarkers(repo, relations, metadata=metadata) # informs that changeset have been pruned ui.status(_('%i changesets pruned\n') % len(precs))