[PATCH 2 of 5 v4] mergecopies: add logic to process incomplete data

Pierre-Yves David pierre-yves.david at ens-lyon.org
Mon Oct 17 17:40:05 EDT 2016



On 10/17/2016 08:42 PM, Gábor Stefanik wrote:
> # HG changeset patch
> # User Gábor Stefanik <gabor.stefanik at nng.com>
> # Date 1475578314 -7200
> #      Tue Oct 04 12:51:54 2016 +0200
> # Node ID f5f046a680e6730485df1760f82a0e0084305873
> # Parent  d8379d11021b681a06cda08a07da237eaca520b2
> mergecopies: add logic to process incomplete data
>
> We first combine incomplete copies on the two sides of the topological CA
> into complete copies.
> Any leftover incomplete copies are then combined with the incomplete
> divergences to reconstruct divergences spanning over the topological CA.
> Finally we promote any divergences falsely flagged as incomplete to full
> divergences.
>
> Right now, there is nothing generating incomplete copy/divergence data,
> so this code does nothing. Changes to _checkcopies to populate these
> dicts are coming later in this series.
>
> diff -r d8379d11021b -r f5f046a680e6 mercurial/copies.py
> --- a/mercurial/copies.py	Wed Oct 12 11:54:03 2016 +0200
> +++ b/mercurial/copies.py	Tue Oct 04 12:51:54 2016 +0200
> @@ -289,6 +289,22 @@
>          return fctx
>      return util.lrucachefunc(makectx)
>
> +def _combinecopies(copyfrom, copyto, finalcopy, diverge, incompletediverge):
> +    """combine partial copy paths"""
> +    remainder = {}
> +    for f in copyfrom:
> +        if f in copyto:
> +            finalcopy[copyto[f]] = copyfrom[f]
> +            del copyto[f]
> +    for f in incompletediverge:
> +        assert f not in diverge
> +        ic = incompletediverge[f]
> +        if ic[0] in copyto:
> +            diverge[f] = [copyto[ic[0]], ic[1]]
> +        else:
> +            remainder[f] = ic
> +    return remainder
> +
>  def mergecopies(repo, c1, c2, base):
>      """
>      Find moves and copies between context c1 and c2 that are relevant
> @@ -360,14 +376,21 @@
>      # - diverge = record all diverges in this dict
>      # - copy = record all non-divergent copies in this dict
>      # - fullcopy = record all copies in this dict
> +    # - incomplete = record non-divergent partial copies here
> +    # - incompletediverge = record divergent partial copies here
>      diverge = {} # divergence data is shared
> +    incompletediverge  = {}
>      data1 = {'copy': {},
>               'fullcopy': {},
> +             'incomplete': {},
>               'diverge': diverge,
> +             'incompletediverge': incompletediverge,
>              }
>      data2 = {'copy': {},
>               'fullcopy': {},
> +             'incomplete': {},
>               'diverge': diverge,
> +             'incompletediverge': incompletediverge,
>              }
>
>      # find interesting file sets from manifests
> @@ -398,6 +421,13 @@
>      copy = dict(data1['copy'].items() + data2['copy'].items())
>      fullcopy = dict(data1['fullcopy'].items() + data2['fullcopy'].items())
>
> +    if dirtyc1:
> +        _combinecopies(data2['incomplete'], data1['incomplete'], copy, diverge,
> +                       incompletediverge)
> +    else:
> +        _combinecopies(data1['incomplete'], data2['incomplete'], copy, diverge,
> +                       incompletediverge)
> +
>      renamedelete = {}
>      renamedeleteset = set()
>      divergeset = set()
> @@ -416,13 +446,36 @@
>          repo.ui.debug("  unmatched files new in both:\n   %s\n"
>                        % "\n   ".join(bothnew))
>      bothdiverge = {}
> -    bothdata = {'copy': {},
> -                'fullcopy': {},
> -                'diverge': bothdiverge,
> -               }
> +    bothincompletediverge = {}
> +    both1 = {'copy': {},
> +             'fullcopy': {},
> +             'incomplete': {},
> +             'diverge': bothdiverge,
> +             'incompletediverge': bothincompletediverge
> +            }
> +    both2 = {'copy': {},
> +             'fullcopy': {},
> +             'incomplete': {},
> +             'diverge': bothdiverge,
> +             'incompletediverge': bothincompletediverge
> +            }
>      for f in bothnew:
> -        _checkcopies(c1, f, m1, m2, base, tca, limit, bothdata)
> -        _checkcopies(c2, f, m2, m1, base, tca, limit, bothdata)
> +        _checkcopies(c1, f, m1, m2, base, tca, limit, both1)
> +        _checkcopies(c2, f, m2, m1, base, tca, limit, both2)
> +    if dirtyc1:
> +        assert both2['incomplete'] == {}

nits, this could be the more pythonic:

   assert not both2['incomplete']

Please consider updating this in a follow up

> +        remainder = _combinecopies({}, both1['incomplete'], copy, bothdiverge,
> +                                   bothincompletediverge)
> +    else:
> +        assert both1['incomplete'] == {}
> +        remainder = _combinecopies({}, both2['incomplete'], copy, bothdiverge,
> +                                   bothincompletediverge)

It looks like this step is only relevant if dirtyc2 is True.

Can we use a "elif dirtyc2" for the next block and a final

   else:
       assert not both1['incomplete']
       assert not both2['incomplete']

If so, I would be happy to take a follow up cleaning this up.

> +    for f in remainder:
> +        assert f not in bothdiverge
> +        ic = remainder[f]
> +        if ic[0] in (m1 if dirtyc1 else m2):
> +            # backed-out rename on one side, but watch out for deleted files
> +            bothdiverge[f] = ic
>      for of, fl in bothdiverge.items():
>          if len(fl) == 2 and fl[0] == fl[1]:
>              copy[fl[0]] = of # not actually divergent, just matching renames

-- 
Pierre-Yves David


More information about the Mercurial-devel mailing list