[PATCH V2] filemerge: add non-interactive internal:merge-local and internal:merge-other

Pierre-Yves David pierre-yves.david at ens-lyon.org
Mon Aug 18 17:22:22 CDT 2014



On 08/13/2014 12:00 PM, Jordi Gutiérrez Hermoso wrote:
> # HG changeset patch
> # User Jordi Gutiérrez Hermoso <jordigh at octave.org>
> # Date 1407783206 14400
> #      Mon Aug 11 14:53:26 2014 -0400
> # Node ID e125a4ec265f9207667e82a62754dfd96f17c0a4
> # Parent  fff8e1cec90f64b356c66aa068d3810f7efea0ac
> filemerge: add non-interactive internal:merge-local and internal:merge-other
>
> There are two non-interactive internal merge tools, internal:other and
> internal:local, but they don't really merge, they just pick all
> changes from the local or other version of the file. In some
> situations, it is known that we want a merge and also know that all
> merge conflicts should be resolved in one direction. Although external
> merge tools can do this, sometimes it can be convenient to do so from
> within hg, without invoking a merge tool. These new
> internal:merge-local and internal:merge-other tools can do just that.

While I kindof like the idea and could see myself use it from time to 
time, I'm a bit worried about the name of this pair and the 
proliferation of this kind of variant in general.

We already have:

  - internal:other
  - internal:local

It is not clear how user will be able to distinct between your two new 
additions

  - internal:merge-other
  - internal:merge-local

Also, I can see a third type of tool that will take the content of side 
X even when there was no manifest level conflict.

I think we need to think harder about a proper UI to hand all those case.

>
> diff --git a/mercurial/filemerge.py b/mercurial/filemerge.py
> --- a/mercurial/filemerge.py
> +++ b/mercurial/filemerge.py
> @@ -229,6 +229,40 @@ def _imerge(repo, mynode, orig, fcd, fco
>           return True, r
>       return False, 0
>
> +def _imergeauto(repo, mynode, orig, fcd, fco, fca, toolconf, files,
> +                labels=None, localorother=None):
> +    """
> +    Generic driver for _imergelocal and _imergeother
> +    """
> +    assert localorother is not None
> +    tool, toolpath, binary, symlink = toolconf
> +    if symlink:
> +        repo.ui.warn(_('warning: internal:merge-%s cannot merge symlinks '
> +                       'for %s\n') % (localorother, fcd.path()))
> +        return False, 1
> +    a, b, c, back = files
> +    r = simplemerge.simplemerge(repo.ui, a, b, c, label=labels,
> +                                localorother=localorother)
> +    return True, r
> +
> + at internaltool('merge-local', True)
> +def _imergelocal(*args, **kwargs):
> +    """
> +    Like internal:merge, but resolve all conflicts non-interactively
> +    in favor of the local changes.
> +    """
> +    success, status = _imergeauto(localorother='local', *args, **kwargs)
> +    return success, status
> +
> + at internaltool('merge-other', True)
> +def _imergelocal(*args, **kwargs):

You forgot to update the function name.

> +    """
> +    Like internal:merge, but resolve all conflicts non-interactively
> +    in favor of the other changes.
> +    """
> +    success, status = _imergeauto(localorother='other', *args, **kwargs)
> +    return success, status
> +
>   @internaltool('merge3', True,
>                 _("merging %s incomplete! "
>                   "(edit conflicts, then use 'hg resolve --mark')\n"))
> diff --git a/mercurial/simplemerge.py b/mercurial/simplemerge.py
> --- a/mercurial/simplemerge.py
> +++ b/mercurial/simplemerge.py
> @@ -82,7 +82,8 @@ class Merge3Text(object):
>                       start_marker='<<<<<<<',
>                       mid_marker='=======',
>                       end_marker='>>>>>>>',
> -                    base_marker=None):
> +                    base_marker=None,
> +                    localorother=None):
>           """Return merge in cvs-like form.

Slicing the change to simple merge in a dedicated commit would make it 
simpler to review.

>           """
>           self.conflicts = False
> @@ -111,18 +112,25 @@ class Merge3Text(object):
>                   for i in range(t[1], t[2]):
>                       yield self.b[i]
>               elif what == 'conflict':
> -                self.conflicts = True
> -                yield start_marker + newline
> -                for i in range(t[3], t[4]):
> -                    yield self.a[i]
> -                if base_marker is not None:
> -                    yield base_marker + newline
> -                    for i in range(t[1], t[2]):
> -                        yield self.base[i]
> -                yield mid_marker + newline
> -                for i in range(t[5], t[6]):
> -                    yield self.b[i]
> -                yield end_marker + newline
> +                if localorother == 'local':
> +                    for i in range(t[3], t[4]):
> +                        yield self.a[i]
> +                elif localorother == 'other':
> +                    for i in range(t[5], t[6]):
> +                        yield self.b[i]
> +                else:
> +                    self.conflicts = True
> +                    yield start_marker + newline
> +                    for i in range(t[3], t[4]):
> +                        yield self.a[i]
> +                    if base_marker is not None:
> +                        yield base_marker + newline
> +                        for i in range(t[1], t[2]):
> +                            yield self.base[i]
> +                    yield mid_marker + newline
> +                    for i in range(t[5], t[6]):
> +                        yield self.b[i]
> +                    yield end_marker + newline
>               else:
>                   raise ValueError(what)
>
> @@ -373,7 +381,7 @@ def simplemerge(ui, local, base, other,
>           out = sys.stdout
>
>       m3 = Merge3Text(basetext, localtext, othertext)
> -    extrakwargs = {}
> +    extrakwargs = {"localorother": opts.get("localorother", None)}
>       if name_base is not None:
>           extrakwargs['base_marker'] = '|||||||'
>           extrakwargs['name_base'] = name_base
> diff --git a/tests/test-conflict.t b/tests/test-conflict.t
> --- a/tests/test-conflict.t
> +++ b/tests/test-conflict.t
> @@ -232,3 +232,66 @@ internal:merge3
>     5
>     >>>>>>> other
>     Hop we are done.
> +
> +
> +Add some unconflicting changes on each head, to make sure we really
> +are merging, unlike internal:local and internal:other
> +
> +  $ hg up -C
> +  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
> +  $ printf "\n\nEnd of file\n" >> a
> +  $ hg ci -m "Add some stuff at the end"
> +  $ hg up -r 1
> +  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
> +  $ printf "Start of file\n\n\n" > tmp
> +  $ cat a >> tmp
> +  $ mv tmp a
> +  $ hg ci -m "Add some stuff at the beginning"
> +
> +Now test internal:merge-other and internal:merge-local
> +
> +  $ hg merge
> +  merging a
> +  warning: conflicts during merge.
> +  merging a incomplete! (edit conflicts, then use 'hg resolve --mark')
> +  1 files updated, 0 files merged, 0 files removed, 1 files unresolved
> +  use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
> +  [1]
> +  $ hg resolve --tool internal:merge-other a
> +  merging a
> +  (no more unresolved files)
> +  $ cat a
> +  Start of file
> +
> +
> +  Small Mathematical Series.
> +  1
> +  2
> +  3
> +  6
> +  8
> +  Hop we are done.
> +
> +
> +  End of file
> +
> +  $ hg up -C
> +  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
> +  $ hg merge --tool internal:merge-local
> +  merging a
> +  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
> +  (branch merge, don't forget to commit)
> +  $ cat a
> +  Start of file
> +
> +
> +  Small Mathematical Series.
> +  1
> +  2
> +  300:12 < stantonk> so how would roots ever return anything?

> +  4
> +  5
> +  Hop we are done.
> +
> +
> +  End of file
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at selenic.com
> http://selenic.com/mailman/listinfo/mercurial-devel
>

-- 
Pierre-Yves David


More information about the Mercurial-devel mailing list