evolve: stabilize now handle conflicting changeset
authorPierre-Yves David <pierre-yves.david@logilab.fr>
Thu, 23 Aug 2012 17:40:28 +0200
changeset 485 41bf6c27a122
parent 484 20e2f2dd71f1
child 486 2111c655b4f5
evolve: stabilize now handle conflicting changeset Some a lot of rough edge but it just damn work.
hgext/evolve.py
tests/test-stabilize-result.t
--- 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'
 
--- 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