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

login
register
mail settings
Submitter Andrew Halberstadt
Date Dec. 5, 2015, 1:33 a.m.
Message ID <51adab56f47c124702d2.1449279238@localhost.localdomain>
Download mbox | patch
Permalink /patch/11839/
State Accepted
Headers show

Comments

Andrew Halberstadt - Dec. 5, 2015, 1:33 a.m.
# HG changeset patch
# User Andrew Halberstadt <ahalberstadt@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.
Andrew Halberstadt - Dec. 5, 2015, 1:37 a.m.
On 04/12/15 08:33 PM, Andrew Halberstadt wrote:
> # HG changeset patch
> # User Andrew Halberstadt <ahalberstadt@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.

There are still two "problems" with this patch I could use some advice on.

1. test-unstable.t fails with versions of mercurial that don't have the
merge.graft change I submitted earlier. Is that ok?

2. This seems to change the sha1's in a lot of tests. I'm not sure why,
or what to do about it.

-Andrew


> 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@default(draft) add _a
>     |/
>     o  0:b4952fcf48cf@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@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
>
>
>     $ cd ..
>
>   ===============================================================================
>   Test instability resolution for a merge changeset unstable because both
> @@ -153,19 +149,17 @@ Not supported yet
>     +---x  2:474da87dd33b@default(draft) add _c
>     | |
>     | x  1:b3264cec9506@default(draft) add _a
>     |/
>     o  0:b4952fcf48cf@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@default(draft) cprime
>     |
>     | o  4:47127ea62e5f@default(draft) aprime
>     |/
>     | o    3:6b4280e33286@default(draft) merge
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel@selenic.com
> https://selenic.com/mailman/listinfo/mercurial-devel
>
Pierre-Yves David - Dec. 5, 2015, 1:58 a.m.
On 12/04/2015 05:37 PM, Andrew Halberstadt wrote:
> 2. This seems to change the sha1's in a lot of tests. I'm not sure why,
> or what to do about it.

The sha change is unrelated, I just pushed Laurent fix for it.
Pierre-Yves David - Dec. 7, 2015, 6:17 p.m.
On 12/04/2015 05:33 PM, Andrew Halberstadt wrote:
> # HG changeset patch
> # User Andrew Halberstadt <ahalberstadt@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)

That patch is close to be ready. I just have a small feedback on the way 
we handle pctx=None

(btw, is it even possible to have pctx to None now? should we forbid it?)

> 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()

We should still detect case where pctx is None and orig has two parents 
and bail out. This would catch bad API usage.

Also, if you are testing, please explicitly test for None

The mercurial blessed patter for this assignement is:

if pctx is None:
     pctx = 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")
> +

Fun fact: the next step to be able to handle merge is to evolve unstable 
merge twice, one time for each parents. That will be further 
modification in:
1) this very block
2) the logic scheduling resolution to schedule these two steps.

(not that this would be the most simple way to be able to evolve such 
merge, a nicer way probably involves a consensus merge like approach).
Andrew Halberstadt - Dec. 7, 2015, 6:39 p.m.
On 07/12/15 01:17 PM, Pierre-Yves David wrote:
>
>
> On 12/04/2015 05:33 PM, Andrew Halberstadt wrote:
>> # HG changeset patch
>> # User Andrew Halberstadt <ahalberstadt@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)
>
> That patch is close to be ready. I just have a small feedback on the way
> we handle pctx=None
>
> (btw, is it even possible to have pctx to None now? should we forbid it?)

There is another call to relocate in _solvebumped that doesn't pass in 
pctx. I'm not 100% sure what a bumped changeset is, but if that's 
something that should be solved as part of issue4389, I can look into it.

Thanks. I'm about to head out to a work week and going on vacation 
after, so may be a couple weeks until I have time for a new patch.

-Andrew

>> 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()
>
> We should still detect case where pctx is None and orig has two parents
> and bail out. This would catch bad API usage.
>
> Also, if you are testing, please explicitly test for None
>
> The mercurial blessed patter for this assignement is:
>
> if pctx is None:
>      pctx = 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")
>> +
>
> Fun fact: the next step to be able to handle merge is to evolve unstable
> merge twice, one time for each parents. That will be further
> modification in:
> 1) this very block
> 2) the logic scheduling resolution to schedule these two steps.
>
> (not that this would be the most simple way to be able to evolve such
> merge, a nicer way probably involves a consensus merge like approach).
>

Patch

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@default(draft) add _a
   |/
   o  0:b4952fcf48cf@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@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
   
 
   $ cd ..
 
 ===============================================================================
 Test instability resolution for a merge changeset unstable because both
@@ -153,19 +149,17 @@  Not supported yet
   +---x  2:474da87dd33b@default(draft) add _c
   | |
   | x  1:b3264cec9506@default(draft) add _a
   |/
   o  0:b4952fcf48cf@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@default(draft) cprime
   |
   | o  4:47127ea62e5f@default(draft) aprime
   |/
   | o    3:6b4280e33286@default(draft) merge