--- 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'