[PATCH evolve-ext] evolve: handle merge commit with single obsolete parent (issue4389)

Andrew Halberstadt halbersa at gmail.com
Fri Dec 4 19:33:58 CST 2015


# HG changeset patch
# User Andrew Halberstadt <ahalberstadt at mozilla.com>
# Date 1448588311 18000
#      Thu Nov 26 20:38:31 2015 -0500
# Node ID 51adab56f47c124702d2b7f2df1030a16c49678d
# Parent  333e056b3034aa328bc7a260b0cdcf641fe3d323
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.

diff --git a/hgext/evolve.py b/hgext/evolve.py
--- a/hgext/evolve.py
+++ b/hgext/evolve.py
@@ -890,29 +890,26 @@ def rewrite(repo, old, updates, head, ne
         tr.close()
         return newid, created
     finally:
         lockmod.release(lock, wlock, tr)
 
 class MergeFailure(util.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 util.Abort(_('tried to relocate a node on top of itself'),
                          hint=_("This shouldn't happen. If you still "
                                 "need to move changesets, please do so "
                                 "manually with nothing to rebase - working "
                                 "directory parent is also destination"))
 
-    if not orig.p2().rev() == node.nullrev:
-        raise util.Abort(
-            'no support for evolving merge changesets yet',
-            hint="Redo the merge and use `hg prune <old> --succ <new>` to obsolete the old one")
+    pctx = pctx or orig.p1()
     destbookmarks = repo.nodebookmarks(dest.node())
     nodesrc = orig.node()
     destphase = repo[nodesrc].phase()
     commitmsg = orig.description()
 
     cache = {}
     sha1s = re.findall(sha1re, commitmsg)
     unfi = repo.unfiltered()
@@ -942,17 +939,28 @@ def relocate(repo, orig, dest, keepbranc
         try:
             if repo['.'].rev() != dest.rev():
                 merge.update(repo, dest, False, True, False)
             if bmactive(repo):
                 repo.ui.status(_("(leaving bookmark %s)\n") % bmactive(repo))
             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 util.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 util.Abort(
                         'unresolved merge conflicts (see hg help resolve)')
             if commitmsg is None:
                 commitmsg = orig.description()
             extra = dict(orig.extra())
             if 'branch' in extra:
                 del extra['branch']
@@ -1743,23 +1751,29 @@ def _aspiringdescendant(repo, revs):
             if unstable not in result:
                 tovisit.append(unstable)
                 result.add(unstable)
     return sorted(result - target)
 
 def _solveunstable(ui, repo, orig, dryrun=False, confirm=False,
                    progresscb=None):
     """Stabilize a 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 util.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 == [()]:
         ui.debug("stabilize target %s is plain dead,"
                  " trying to stabilize on its parent\n" %
                  obs)
         obs = obs.parents()[0]
         newer = obsolete.successorssets(repo, obs.node())
@@ -1794,17 +1808,17 @@ def _solveunstable(ui, repo, orig, dryru
     todo = 'hg rebase -r %s -d %s\n' % (orig, target)
     if dryrun:
         repo.ui.write(todo)
     else:
         repo.ui.note(todo)
         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'))
             repo.ui.write_err(
                 _('fix conflict and run "hg evolve --continue"'
                   ' or use "hg update -C" to abort\n'))
             raise
 
diff --git a/tests/test-unstable.t b/tests/test-unstable.t
--- a/tests/test-unstable.t
+++ b/tests/test-unstable.t
@@ -98,27 +98,23 @@ Not supported yet
   | x  1:b3264cec9506 at default(draft) add _a
   |/
   o  0:b4952fcf48cf at default(draft) add base
   
 
   $ 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 at default(draft) aprime
-  |
-  | o    3:6b4280e33286 at default(draft) merge
-  | |\
-  +---o  2:474da87dd33b at default(draft) add _c
+  @    5:0bf3f3a59c8c at default(draft) merge
+  |\
+  | o  4:47127ea62e5f at default(draft) aprime
   | |
-  | x  1:b3264cec9506 at default(draft) add _a
+  o |  2:474da87dd33b at default(draft) add _c
   |/
   o  0:b4952fcf48cf at default(draft) add base
   
 
   $ cd ..
 
 ===============================================================================
 Test instability resolution for a merge changeset unstable because both
@@ -153,19 +149,17 @@ Not supported yet
   +---x  2:474da87dd33b at default(draft) add _c
   | |
   | x  1:b3264cec9506 at default(draft) add _a
   |/
   o  0:b4952fcf48cf at default(draft) add base
   
 
   $ 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
   @  5:2db39fda7e2f at default(draft) cprime
   |
   | o  4:47127ea62e5f at default(draft) aprime
   |/
   | o    3:6b4280e33286 at default(draft) merge


More information about the Mercurial-devel mailing list