changeset 1576:526253198860

evolve: handle merge commit with single obsolete parent (issue4389) This handles evolving merge commits with a single obsolete parent. Merge commits with two obsolete parents are still unsupported. Note this depends on a change to merge.graft in core. Older versions of mercurial will not have this functionality. Also, test-unstable.t will fail with older versions.
author Andrew Halberstadt <ahalberstadt@mozilla.com>
date Thu, 26 Nov 2015 20:38:31 -0500
parents 0c8548df67fe
children 4f83b2d2d20d
files README hgext/evolve.py tests/test-unstable.t
diffstat 3 files changed, 41 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
--- a/README	Tue Dec 22 14:11:09 2015 +0000
+++ b/README	Thu Nov 26 20:38:31 2015 -0500
@@ -62,6 +62,7 @@
 - tests: drop our copy of 'run-tests.py' use core one instead,
 - bookmark: do all bookmark movement within a transaction.
 - evolve: compatibility with Mercurial 3.7
+- evolve: support merge with a single obsolete parent.
 
 5.2.2 --
 
--- a/hgext/evolve.py	Tue Dec 22 14:11:09 2015 +0000
+++ b/hgext/evolve.py	Thu Nov 26 20:38:31 2015 -0500
@@ -896,7 +896,7 @@
 class MergeFailure(error.Abort):
     pass
 
-def relocate(repo, orig, dest, keepbranch=False):
+def relocate(repo, orig, dest, pctx=None, keepbranch=False):
     """rewrite <rev> on dest"""
     if orig.rev() == dest.rev():
         raise error.Abort(_('tried to relocate a node on top of itself'),
@@ -905,11 +905,13 @@
                                 "manually with nothing to rebase - working "
                                 "directory parent is also destination"))
 
-    if not orig.p2().rev() == node.nullrev:
-        raise error.Abort(
-            'no support for evolving merge changesets yet',
-            hint="Redo the merge and use `hg prune <old> --succ <new>` "
-                 "to obsolete the old one")
+    if pctx is None:
+        if len(orig.parents()) == 2:
+            raise error.Abort(_("tried to relocate a merge commit without "
+                                "specifying which parent should be moved"),
+                              hint=_("Specify the parent by passing in pctx"))
+        pctx = orig.p1()
+
     destbookmarks = repo.nodebookmarks(dest.node())
     nodesrc = orig.node()
     destphase = repo[nodesrc].phase()
@@ -949,7 +951,19 @@
             bmdeactivate(repo)
             if keepbranch:
                 repo.dirstate.setbranch(orig.branch())
-            r = merge.graft(repo, orig, orig.p1(), ['local', 'graft'])
+
+            try:
+                r = merge.graft(repo, orig, pctx, ['local', 'graft'], True)
+            except TypeError:
+                # not using recent enough mercurial
+                if len(orig.parents()) == 2:
+                    raise error.Abort(
+                        _("no support for evolving merge changesets yet"),
+                        hint=_("Redo the merge and use `hg prune <old> --succ "
+                               "<new>` to obsolete the old one"))
+
+                r = merge.graft(repo, orig, pctx, ['local', 'graft'])
+
             if r[-1]:  #some conflict
                 raise error.Abort(
                         'unresolved merge conflicts (see hg help resolve)')
@@ -1734,13 +1748,20 @@
 def _solveunstable(ui, repo, orig, dryrun=False, confirm=False,
                    progresscb=None):
     """Stabilize an unstable changeset"""
-    obs = orig.parents()[0]
-    if not obs.obsolete() and len(orig.parents()) == 2:
-        obs = orig.parents()[1] # second parent is obsolete ?
-
-    if not obs.obsolete():
+    pctx = orig.p1()
+    if len(orig.parents()) == 2:
+        if not pctx.obsolete():
+            pctx = orig.p2()  # second parent is obsolete ?
+        elif orig.p2().obsolete():
+            raise error.Abort(_("no support for evolving merge changesets "
+                                "with two obsolete parents yet"),
+                              hint=_("Redo the merge and use `hg prune <old> "
+                                   "--succ <new>` to obsolete the old one"))
+
+    if not pctx.obsolete():
         ui.warn(_("cannot solve instability of %s, skipping\n") % orig)
         return False
+    obs = pctx
     newer = obsolete.successorssets(repo, obs.node())
     # search of a parent which is not killed
     while not newer or newer == [()]:
@@ -1786,7 +1807,7 @@
         if progresscb: progresscb()
         keepbranch = orig.p1().branch() != orig.branch()
         try:
-            relocate(repo, orig, target, keepbranch)
+            relocate(repo, orig, target, pctx, keepbranch)
         except MergeFailure:
             repo.opener.write('graftstate', orig.hex() + '\n')
             repo.ui.write_err(_('evolve failed!\n'))
--- a/tests/test-unstable.t	Tue Dec 22 14:11:09 2015 +0000
+++ b/tests/test-unstable.t	Thu Nov 26 20:38:31 2015 -0500
@@ -103,17 +103,13 @@
   $ hg evo --all --any --unstable
   move:[3] merge
   atop:[4] aprime
-  abort: no support for evolving merge changesets yet
-  (Redo the merge and use `hg prune <old> --succ <new>` to obsolete the old one)
-  [255]
+  working directory is now at 0bf3f3a59c8c
   $ hg log -G
-  @  4:47127ea62e5f@default(draft) aprime
-  |
-  | o    3:6b4280e33286@default(draft) merge
-  | |\
-  +---o  2:474da87dd33b@default(draft) add _c
+  @    5:0bf3f3a59c8c@default(draft) merge
+  |\
+  | o  4:47127ea62e5f@default(draft) aprime
   | |
-  | x  1:b3264cec9506@default(draft) add _a
+  o |  2:474da87dd33b@default(draft) add _c
   |/
   o  0:b4952fcf48cf@default(draft) add base
   
@@ -158,9 +154,7 @@
   
 
   $ hg evo --all --any --unstable
-  move:[3] merge
-  atop:[5] cprime
-  abort: no support for evolving merge changesets yet
+  abort: no support for evolving merge changesets with two obsolete parents yet
   (Redo the merge and use `hg prune <old> --succ <new>` to obsolete the old one)
   [255]
   $ hg log -G