[PATCH evolve-ext] evolve: handle merge commit with single obsolete parent (issue4389)
Andrew Halberstadt
ahalberstadt at mozilla.com
Mon Dec 7 12:39:10 CST 2015
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 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)
>
> 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).
>
More information about the Mercurial-devel
mailing list