[PATCH 1 of 4 evolve-ext] evolve: make --all use the same code path than --rev without filtering

Pierre-Yves David pierre-yves.david at ens-lyon.org
Wed May 6 12:28:47 CDT 2015

On 05/05/2015 06:22 PM, Laurent Charignon wrote:
> # HG changeset patch
> # User Laurent Charignon <lcharignon at fb.com>
> # Date 1430506124 25200
> #      Fri May 01 11:48:44 2015 -0700
> # Node ID 9a6285b42bd3e81c107c3ba3a4e7a3bbe7c975db
> # Parent  1fe3da0b4601c690815f7e247a18067ef002cd6f
> evolve: make --all use the same code path than --rev without filtering
> This simplifies the code of the evolve function to make it easier to understand
> and more reusable in other context.

This options is nice, but it is going to regress/break in two cases:

1) If a revision is affect by multiple trouble, we will only solve one.
2) If revision are evolved in the wrong order, some will end up unstable 
after evolve --all.

There is multiple ways to fix (1) (some being more creative than other) 
I can think you can get with a test case and some simple fix by yourself.

(2) is a bit more tricky It happen when your stack of unstable changeset 
is not linear itself. Given three changesets:

    1:A -- 2:B -- 3:C

You amend B and get C unstable:

    1:A -- 2xB -- 3:C
        \- 4:B'

Then you amend A and get B' unstable

    1:A -- 2xB -- 3:C
        \- 4:B'

Now, both B' and C are unstable and needs to get stabilised on A'. 
However, evolving all troubled changeset in ascending order (behavior of 
old implementation and "maybe yours") is going to evolve 3:C before 
4:B'. So 3:C is going to be rebased above 4:B' and will become obsolete 
once 4:B' itself is rebased. The current implementation eventually reach 
a stable point because it's approach is: "Let's beat this poney hard 
until we have them all in the dead horses pile" leading to C being 
stabilized twice. Your (better) implementation will fail there because 
it touch everything only once. I think we needs either some sort of 
smart reordering of the list of revs to process or a delay mechanism 
that push back the resolution a troubled changeset if it going to evolve 
it about another troubled one.

> diff --git a/hgext/evolve.py b/hgext/evolve.py
> --- a/hgext/evolve.py
> +++ b/hgext/evolve.py
> @@ -1287,11 +1287,14 @@
>               raise util.Abort('cannot specify both "--all" and "--continue"')
>           graftcmd = commands.table['graft'][0]
>           return graftcmd(ui, repo, old_obsolete=True, **{'continue': True})
> -    # Rev specified on the commands line
> -    if revopt:
> -        revs = set(repo.revs(revopt))
> +    # Rev specified on the commands line or solving all the troubles
> +    if revopt or allopt:
>           troubled = set(repo.revs('troubled()'))

> -        _revs = revs & troubled
> +        if allopt:
> +            _revs = troubled
> +        else:
> +            revs = set(repo.revs(revopt))

I overlooked this use of `repo.revs` with user input. You should use 
revrange instead that will properly handle users input specific thing 
(revset alias, bookmark with -).

Also, having both _revs and revs is "meh" expecially is the 
super-short-lived-and-only-in-one-branch one is getting the clean (rev) one.

Usually, _variable are used for return value are are not going to be 
used (or for very local variable). Using it for "the list of revs we'll 
fix" seem inappropriate.

> +            _revs = revs & troubled

You should not need to turn everything to set since two smartsets should 
combine together smartly.

But his could simply be

   revs = repo.revs('%ld and troubled()', scmutil.revrange(revopt))

Pierre-Yves David

More information about the Mercurial-devel mailing list