[PATCH 1 of 4 V4] update: accept --merge to allow merging across topo branches (issue5125)

Martin von Zweigbergk martinvonz at google.com
Tue Feb 21 17:27:02 EST 2017


Sure. I'm on vacation, so I can do that next week, or in a follow-up.
Whichever the person considering queuing prefers.

On Tue, Feb 21, 2017, 14:18 Jun Wu <quark at fb.com> wrote:

> I like the behavior change (didn't check the implementation details
> carefully).
>
> Could you also update the table in the docstring of merge.update? I think
> that's very helpful to explain the behavior cleanly. Thanks!
>
> Excerpts from Martin von Zweigbergk's message of 2017-02-16 08:59:12 -0800:
> > # HG changeset patch
> > # User Martin von Zweigbergk <martinvonz at google.com>
> > # Date 1487019517 28800
> > #      Mon Feb 13 12:58:37 2017 -0800
> > # Node ID 19f471c814809099b5452b1174a2ecb0699cb76a
> > # Parent  1ee685defe80117cf6aafea1ede6c33c478abceb
> > update: accept --merge to allow merging across topo branches (issue5125)
> >
> > diff -r 1ee685defe80 -r 19f471c81480 mercurial/commands.py
> > --- a/mercurial/commands.py    Wed Feb 15 16:29:58 2017 -0800
> > +++ b/mercurial/commands.py    Mon Feb 13 12:58:37 2017 -0800
> > @@ -5286,12 +5286,13 @@
> >  @command('^update|up|checkout|co',
> >      [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
> >      ('c', 'check', None, _('require clean working directory')),
> > +    ('m', 'merge', None, _('merge local changes')),
> >      ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
> >      ('r', 'rev', '', _('revision'), _('REV'))
> >       ] + mergetoolopts,
> > -    _('[-C|-c] [-d DATE] [[-r] REV]'))
> > +    _('[-C|-c|-m] [-d DATE] [[-r] REV]'))
> >  def update(ui, repo, node=None, rev=None, clean=False, date=None,
> check=False,
> > -           tool=None):
> > +           merge=None, tool=None):
> >      """update working directory (or switch revisions)
> >
> >      Update the repository's working directory to the specified
> > @@ -5310,8 +5311,8 @@
> >
> >      .. container:: verbose
> >
> > -      The -C/--clean and -c/--check options control what happens if the
> > -      working directory contains uncommitted changes.
> > +      The -C/--clean, -c/--check, and -m/--merge options control what
> > +      happens if the working directory contains uncommitted changes.
> >        At most of one of them can be specified.
> >
> >        1. If no option is specified, and if
> > @@ -5323,10 +5324,14 @@
> >           branch), the update is aborted and the uncommitted changes
> >           are preserved.
> >
> > -      2. With the -c/--check option, the update is aborted and the
> > +      2. With the -m/--merge option, the update is allowed even if the
> > +         requested changeset is not an ancestor or descendant of
> > +         the working directory's parent.
> > +
> > +      3. With the -c/--check option, the update is aborted and the
> >           uncommitted changes are preserved.
> >
> > -      3. With the -C/--clean option, uncommitted changes are discarded
> and
> > +      4. With the -C/--clean option, uncommitted changes are discarded
> and
> >           the working directory is updated to the requested changeset.
> >
> >      To cancel an uncommitted merge (and lose your changes), use
> > @@ -5351,8 +5356,15 @@
> >      if date and rev is not None:
> >          raise error.Abort(_("you can't specify a revision and a date"))
> >
> > -    if check and clean:
> > -        raise error.Abort(_("cannot specify both -c/--check and
> -C/--clean"))
> > +    if len([x for x in (clean, check, merge) if x]) > 1:
> > +        raise error.Abort(_("can only specify one of -C/--clean,
> -c/--check, "
> > +                            "or -m/merge"))
> > +
> > +    updatecheck = None
> > +    if check:
> > +        updatecheck = 'abort'
> > +    elif merge:
> > +        updatecheck = 'none'
> >
> >      with repo.wlock():
> >          cmdutil.clearunfinished(repo)
> > @@ -5366,7 +5378,8 @@
> >
> >          repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
> >
> > -        return hg.updatetotally(ui, repo, rev, brev, clean=clean,
> check=check)
> > +        return hg.updatetotally(ui, repo, rev, brev, clean=clean,
> > +                                updatecheck=updatecheck)
> >
> >  @command('verify', [])
> >  def verify(ui, repo):
> > diff -r 1ee685defe80 -r 19f471c81480 mercurial/hg.py
> > --- a/mercurial/hg.py    Wed Feb 15 16:29:58 2017 -0800
> > +++ b/mercurial/hg.py    Mon Feb 13 12:58:37 2017 -0800
> > @@ -681,18 +681,19 @@
> >      repo.ui.status(_("%d files updated, %d files merged, "
> >                       "%d files removed, %d files unresolved\n") % stats)
> >
> > -def updaterepo(repo, node, overwrite):
> > +def updaterepo(repo, node, overwrite, updatecheck=None):
> >      """Update the working directory to node.
> >
> >      When overwrite is set, changes are clobbered, merged else
> >
> >      returns stats (see pydoc mercurial.merge.applyupdates)"""
> >      return mergemod.update(repo, node, False, overwrite,
> > -                           labels=['working copy', 'destination'])
> > +                           labels=['working copy', 'destination'],
> > +                           updatecheck=updatecheck)
> >
> > -def update(repo, node, quietempty=False):
> > -    """update the working directory to node, merging linear changes"""
> > -    stats = updaterepo(repo, node, False)
> > +def update(repo, node, quietempty=False, updatecheck=None):
> > +    """update the working directory to node"""
> > +    stats = updaterepo(repo, node, False, updatecheck=updatecheck)
> >      _showstats(repo, stats, quietempty)
> >      if stats[3]:
> >          repo.ui.status(_("use 'hg resolve' to retry unresolved file
> merges\n"))
> > @@ -712,7 +713,7 @@
> >  # naming conflict in updatetotally()
> >  _clean = clean
> >
> > -def updatetotally(ui, repo, checkout, brev, clean=False, check=False):
> > +def updatetotally(ui, repo, checkout, brev, clean=False,
> updatecheck=None):
> >      """Update the working directory with extra care for non-file
> components
> >
> >      This takes care of non-file components below:
> > @@ -724,10 +725,19 @@
> >      :checkout: to which revision the working directory is updated
> >      :brev: a name, which might be a bookmark to be activated after
> updating
> >      :clean: whether changes in the working directory can be discarded
> > -    :check: whether changes in the working directory should be checked
> > +    :updatecheck: how to deal with a dirty working directory
> > +
> > +    Valid values for updatecheck are (None => linear):
> > +
> > +     * abort: abort if the working directory is dirty
> > +     * none: don't check (merge working directory changes into
> destination)
> > +     * linear: check that update is linear before merging working
> directory
> > +               changes into destination
> >
> >      This returns whether conflict is detected at updating or not.
> >      """
> > +    if updatecheck is None:
> > +        updatecheck = 'linear'
> >      with repo.wlock():
> >          movemarkfrom = None
> >          warndest = False
> > @@ -739,9 +749,10 @@
> >          if clean:
> >              ret = _clean(repo, checkout)
> >          else:
> > -            if check:
> > +            if updatecheck == 'abort':
> >                  cmdutil.bailifchanged(repo, merge=False)
> > -            ret = _update(repo, checkout)
> > +                updatecheck = 'none'
> > +            ret = _update(repo, checkout, updatecheck=updatecheck)
> >
> >          if not ret and movemarkfrom:
> >              if movemarkfrom == repo['.'].node():
> > diff -r 1ee685defe80 -r 19f471c81480 mercurial/merge.py
> > --- a/mercurial/merge.py    Wed Feb 15 16:29:58 2017 -0800
> > +++ b/mercurial/merge.py    Mon Feb 13 12:58:37 2017 -0800
> > @@ -1444,7 +1444,8 @@
> >              repo.dirstate.normal(f)
> >
> >  def update(repo, node, branchmerge, force, ancestor=None,
> > -           mergeancestor=False, labels=None, matcher=None,
> mergeforce=False):
> > +           mergeancestor=False, labels=None, matcher=None,
> mergeforce=False,
> > +           updatecheck=None):
> >      """
> >      Perform a merge between the working directory and the given node
> >
> > @@ -1491,9 +1492,16 @@
> >      Return the same tuple as applyupdates().
> >      """
> >
> > -    # This functon used to find the default destination if node was
> None, but
> > +    # This function used to find the default destination if node was
> None, but
> >      # that's now in destutil.py.
> >      assert node is not None
> > +    if not branchmerge and not force:
> > +        # TODO: remove the default once all callers that pass
> branchmerge=False
> > +        # and force=False pass a value for updatecheck. We may want to
> allow
> > +        # updatecheck='abort' to better suppport some of these callers.
> > +        if updatecheck is None:
> > +            updatecheck = 'linear'
> > +        assert updatecheck in ('none', 'linear')
> >      # If we're doing a partial update, we need to skip updating
> >      # the dirstate, so make a note of any partial-ness to the
> >      # update here.
> > @@ -1550,7 +1558,8 @@
> >                  repo.hook('update', parent1=xp2, parent2='', error=0)
> >                  return 0, 0, 0, 0
> >
> > -            if pas not in ([p1], [p2]):  # nonlinear
> > +            if (updatecheck == 'linear' and
> > +                    pas not in ([p1], [p2])):  # nonlinear
> >                  dirty = wc.dirty(missing=True)
> >                  if dirty:
> >                      # Branching is a bit strange to ensure we do the
> minimal
> > diff -r 1ee685defe80 -r 19f471c81480 tests/test-completion.t
> > --- a/tests/test-completion.t    Wed Feb 15 16:29:58 2017 -0800
> > +++ b/tests/test-completion.t    Mon Feb 13 12:58:37 2017 -0800
> > @@ -223,7 +223,7 @@
> >    serve: accesslog, daemon, daemon-postexec, errorlog, port, address,
> prefix, name, web-conf, webdir-conf, pid-file, stdio, cmdserver, templates,
> style, ipv6, certificate
> >    status: all, modified, added, removed, deleted, clean, unknown,
> ignored, no-status, copies, print0, rev, change, include, exclude,
> subrepos, template
> >    summary: remote
> > -  update: clean, check, date, rev, tool
> > +  update: clean, check, merge, date, rev, tool
> >    addremove: similarity, subrepos, include, exclude, dry-run
> >    archive: no-decode, prefix, rev, type, subrepos, include, exclude
> >    backout: merge, commit, no-commit, parent, rev, edit, tool, include,
> exclude, message, logfile, date, user
> > diff -r 1ee685defe80 -r 19f471c81480 tests/test-update-branches.t
> > --- a/tests/test-update-branches.t    Wed Feb 15 16:29:58 2017 -0800
> > +++ b/tests/test-update-branches.t    Mon Feb 13 12:58:37 2017 -0800
> > @@ -160,6 +160,16 @@
> >    parent=1
> >    M foo
> >
> > +  $ revtest '-m dirty linear'   dirty 1 2 -m
> > +  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
> > +  parent=2
> > +  M foo
> > +
> > +  $ revtest '-m dirty cross'  dirty 3 4 -m
> > +  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
> > +  parent=4
> > +  M foo
> > +
> >    $ revtest '-c dirtysub linear'   dirtysub 1 2 -c
> >    abort: uncommitted changes in subrepository 'sub'
> >    parent=1
> > @@ -171,7 +181,17 @@
> >    parent=2
> >
> >    $ revtest '-cC dirty linear'  dirty 1 2 -cC
> > -  abort: cannot specify both -c/--check and -C/--clean
> > +  abort: can only specify one of -C/--clean, -c/--check, or -m/merge
> > +  parent=1
> > +  M foo
> > +
> > +  $ revtest '-mc dirty linear'  dirty 1 2 -mc
> > +  abort: can only specify one of -C/--clean, -c/--check, or -m/merge
> > +  parent=1
> > +  M foo
> > +
> > +  $ revtest '-mC dirty linear'  dirty 1 2 -mC
> > +  abort: can only specify one of -C/--clean, -c/--check, or -m/merge
> >    parent=1
> >    M foo
> >
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.mercurial-scm.org/pipermail/mercurial-devel/attachments/20170221/219db0e0/attachment.html>


More information about the Mercurial-devel mailing list