# HG changeset patch # User Pierre-Yves David # Date 1345736428 -7200 # Node ID 41bf6c27a12209ab2aa33e077190081437cdc6fb # Parent 20e2f2dd71f1f1dc6201ec768af18d99f97e073f evolve: stabilize now handle conflicting changeset Some a lot of rough edge but it just damn work. diff -r 20e2f2dd71f1 -r 41bf6c27a122 hgext/evolve.py --- a/hgext/evolve.py Thu Aug 23 14:15:36 2012 +0200 +++ b/hgext/evolve.py Thu Aug 23 17:40:28 2012 +0200 @@ -22,6 +22,7 @@ from mercurial import context from mercurial import copies from mercurial import util +from mercurial import merge from mercurial.i18n import _ from mercurial.commands import walkopts, commitopts, commitopts2 from mercurial import hg @@ -264,14 +265,14 @@ else: ui.write_err(_('no troubled changeset\n')) return 1 + cmdutil.bailifchanged(repo) troubles = tr.troubles() if 'unstable' in troubles: return _solveunstable(ui, repo, tr, opts['dry_run']) elif 'latecomer' in troubles: return _solvelatecomer(ui, repo, tr, opts['dry_run']) elif 'conflicting' in troubles: - ui.write_err(_('conflicting not handled yet\n')) - return 4 + return _solveconflicting(ui, repo, tr, opts['dry_run']) else: assert False # WHAT? unknown troubles @@ -444,6 +445,99 @@ finally: wlock.release() +def _solveconflicting(ui, repo, conflicting, dryrun=False): + obsolete = extensions.find('obsolete') + base, others = conflictingdata(conflicting) + if len(others) > 1: + raise util.Abort("We do not handle split yet") + other = others[0] + if conflicting.phase() <= phases.public: + raise util.Abort("We can't resolve this conflict from the public side") + if len(other.parents()) > 1: + raise util.Abort("conflicting changeset can't be a merge (yet)") + if other.p1() not in conflicting.parents(): + raise util.Abort("parent are not common (not handled yet)") + + displayer = cmdutil.show_changeset(ui, repo, {'template': shorttemplate}) + ui.status(_('merge:')) + if not ui.quiet: + displayer.show(conflicting) + ui.status(_('with: ')) + if not ui.quiet: + displayer.show(other) + ui.status(_('base: ')) + if not ui.quiet: + displayer.show(base) + if dryrun: + ui.write('hg update -c %s &&\n' % conflicting) + ui.write('hg merge %s && \n' % other) + ui.write('hg commit -m "auto merge resolving conflict between %s and %s"&&\n' + % (conflicting, 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' % conflicting) + return + #oldphase = max(conflicting.phase(), other.phase()) + wlock = repo.wlock() + try: + lock = repo.lock() + try: + if conflicting not in repo[None].parents(): + repo.ui.status(_('updating to "local" conflict\n')) + hg.update(repo, conflicting.rev()) + repo.ui.note(_('merging conflicting changeset\n')) + stats = merge.update(repo, + other.node(), + branchmerge=True, + force=False, + partial=None, + 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 abandon\n")) + #repo.dirstate.write() + if stats[3] > 0: + raise util.Abort('GASP! Merge Conflict! You are on you own chap!') + tr = repo.transaction('stabilize-conflicting') + try: + repo.dirstate.setparents(conflicting.node(), node.nullid) + oldlen = len(repo) + amend(ui, repo) + if oldlen == len(repo): + new = conflicting + # no changes + else: + new = repo['.'] + obsolete.createmarkers(repo, [(other, (new,))]) + phases.retractboundary(repo, other.phase(), [new.node()]) + tr.close() + finally: + tr.release() + finally: + lock.release() + finally: + wlock.release() + + +def conflictingdata(ctx): + """return base, other part of a conflict + + This only return the first one. + + XXX this woobly function won't survive XXX + """ + obsolete = extensions.find('obsolete') + for base in ctx._repo.set('reverse(precursors(%d))', ctx): + newer = obsolete.newerversion(ctx._repo, base.node()) + # drop filter and solution including the original ctx + newer = [n for n in newer if n and ctx.node() not in n] + if newer: + return base, tuple(ctx._repo[o] for o in newer[0]) + raise KeyError('Base seem unknown. This case is not handled yet.') + + shorttemplate = '[{rev}] {desc|firstline}\n' diff -r 20e2f2dd71f1 -r 41bf6c27a122 tests/test-stabilize-result.t --- a/tests/test-stabilize-result.t Thu Aug 23 14:15:36 2012 +0200 +++ b/tests/test-stabilize-result.t Thu Aug 23 17:40:28 2012 +0200 @@ -175,15 +175,27 @@ Stabilize of conflicting changeset with same parent ==================================================== - + $ rm a.orig $ hg up 9 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ cat << EOF >> a + > flore + > arthur + > zephir + > some + > less + > conflict + > EOF + $ hg ci -m 'More addition' + created new head $ glog - o 14:1d94fef80e85@default(draft) bk:[] latecomer update to e3183e9c0961: + @ 15:7391601a4bfa@default(draft) bk:[] More addition | - | @ 9:355c5cda4de1@default(draft) bk:[] add c + | o 14:1d94fef80e85@default(draft) bk:[] latecomer update to e3183e9c0961: | | - o | 8:e3183e9c0961@default(public) bk:[] newer a + o | 9:355c5cda4de1@default(draft) bk:[] add c + | | + | o 8:e3183e9c0961@default(public) bk:[] newer a |/ o 7:e8cc1b534401@default(public) bk:[changea] changea | @@ -191,7 +203,7 @@ $ echo 'babar' >> a $ hg amend - $ hg up 9 + $ hg up 15 1 files updated, 0 files merged, 0 files removed, 0 files unresolved Working directory parent is obsolete $ mv a a.old @@ -201,12 +213,14 @@ $ hg amend 2 new conflictings changesets $ glog - @ 18:5d568f72d576@default(draft) bk:[] add c + @ 19:3883461cc228@default(draft) bk:[] More addition | - | o 16:a311193de6c8@default(draft) bk:[] add c + | o 17:4754d61bc2db@default(draft) bk:[] More addition |/ | o 14:1d94fef80e85@default(draft) bk:[] latecomer update to e3183e9c0961: | | + o | 9:355c5cda4de1@default(draft) bk:[] add c + | | | o 8:e3183e9c0961@default(public) bk:[] newer a |/ o 7:e8cc1b534401@default(public) bk:[changea] changea @@ -216,6 +230,62 @@ Stabilize It - $ hg stabilize - conflicting not handled yet - [4] + $ hg stabilize -qn + hg update -c 3883461cc228 && + hg merge 4754d61bc2db && + hg commit -m "auto merge resolving conflict between 3883461cc228 and 4754d61bc2db"&& + hg up -C 7391601a4bfa && + hg revert --all --rev tip && + hg commit -m "`hg log -r 3883461cc228 --template={desc}`"; + $ hg stabilize -v + merge:[19] More addition + with: [17] More addition + base: [15] More addition + merging conflicting changeset + resolving manifests + merging a + 0 files updated, 1 files merged, 0 files removed, 0 files unresolved + a + a + $ hg st + $ hg amend -d '0 0' -m 'More addition' # kill date variation XXX should be done in stabilize + $ glog + @ 22:ac6d600735a4@default(draft) bk:[] More addition + | + | o 14:1d94fef80e85@default(draft) bk:[] latecomer update to e3183e9c0961: + | | + o | 9:355c5cda4de1@default(draft) bk:[] add c + | | + | o 8:e3183e9c0961@default(public) bk:[] newer a + |/ + o 7:e8cc1b534401@default(public) bk:[changea] changea + | + o 0:07f494440405@default(public) bk:[] adda + + $ hg summary + parent: 22:ac6d600735a4 tip + More addition + branch: default + commit: (clean) + update: 19 new changesets, 14 branch heads (merge) + $ hg export . + # HG changeset patch + # User test + # Date 0 0 + # Node ID ac6d600735a49ee377e29d1f74a0576e8c972e7b + # Parent 355c5cda4de162658ed9f961a98a73a10b3167b1 + More addition + + diff -r 355c5cda4de1 -r ac6d600735a4 a + --- a/a Thu Jan 01 00:00:00 1970 +0000 + +++ b/a Thu Jan 01 00:00:00 1970 +0000 + @@ -1,1 +1,9 @@ + +jungle + a + +flore + +arthur + +zephir + +some + +less + +conflict + +babar