[PATCH 4 of 4 V3 evolve-ext] metaedit: add support for folding commits while editing their metadata

Simon Farnsworth simonfar at fb.com
Mon Apr 25 18:03:56 EDT 2016


Apart from the naming issue, this looks good to me, code-wise.

Are there other operations that make sense combined with metaedit, not 
just fold? Reorder, perhaps? And do we want a --roll as well, which 
simply takes the commit message from a selected commit in the set being 
folded together?

On 18/04/2016 19:14, Siddharth Agarwal wrote:
> # HG changeset patch
> # User Siddharth Agarwal <sid0 at fb.com>
> # Date 1461003256 25200
> #      Mon Apr 18 11:14:16 2016 -0700
> # Node ID d39a22490ec843e9a08925996882ff1d1f6486a0
> # Parent  625420da4048a1cdf1599a6b8fb8782713bd560f
> metaedit: add support for folding commits while editing their metadata
>
> This also allows us to accept multiple commits without dealing with the thorny
> algorithmic and UI issues of editing multiple commits at once.
>
> Crucially, it is different from 'hg fold --exact' in that it also allows
> 'folding' a single commit and rewriting its metadata. This is really useful to
> have as a single logical operation, for example while preparing a series of
> multiple local changesets that will need to be pushed as a single changeset.
>
> diff --git a/hgext/evolve.py b/hgext/evolve.py
> --- a/hgext/evolve.py
> +++ b/hgext/evolve.py
> @@ -3151,14 +3151,18 @@ def fold(ui, repo, *revs, **opts):
>
>   @command('^metaedit',
>            [('r', 'rev', [], _("revision to edit")),
> +          ('', 'fold', None, _("also fold specified revisions into one")),
>            ] + commitopts + commitopts2,
>            _('hg metaedit [OPTION]... [-r] [REV]'))
>   def metaedit(ui, repo, *revs, **opts):
>       """edit commit information
>
> -    Edits the commit information for the specified revision. By default, edits
> +    Edits the commit information for the specified revisions. By default, edits
>       commit information for the working directory parent.
>
> +    With --fold, also folds multiple revisions into one if necessary. In this
> +    case, the given revisions must form a linear unbroken chain.
> +
>       .. container:: verbose
>
>        Some examples:
> @@ -3171,10 +3175,19 @@ def metaedit(ui, repo, *revs, **opts):
>
>            hg metaedit --user 'New User <new-email at example.com>'
>
> +     - Combine all draft revisions that are ancestors of foo but not of @ into
> +       one::
> +
> +         hg metaedit --fold 'draft() and only(foo,@)'
> +
> +       See :hg:`help phases` for more about draft revisions, and
> +       :hg:`help revsets` for more about the `draft()` and `only()` keywords.
>       """
>       revs = list(revs)
>       revs.extend(opts['rev'])
>       if not revs:
> +        if opts['fold']:
> +            raise error.Abort(_('revisions must be specified with --fold'))
>           revs = ['.']
>
>       wlock = lock = None
> @@ -3183,7 +3196,7 @@ def metaedit(ui, repo, *revs, **opts):
>           lock = repo.lock()
>
>           revs = scmutil.revrange(repo, revs)
> -        if len(revs) > 1:
> +        if not opts['fold'] and len(revs) > 1:
>               # TODO: handle multiple revisions. This is somewhat tricky because
>               # if we want to edit a series of commits:
>               #
> @@ -3192,18 +3205,21 @@ def metaedit(ui, repo, *revs, **opts):
>               # we need to rewrite a first, then directly rewrite b on top of the
>               # new a, then rewrite c on top of the new b. So we need to handle
>               # revisions in topological order.
> -            raise error.Abort(_('editing multiple revisions is not '
> -                                'currently supported'))
> -
> -        newunstable = _newdisallowedunstable(repo, revs)
> -        if newunstable:
> -            raise error.Abort(
> -                _('cannot edit commit information in the middle of a stack'),
> -                hint=_('%s will be affected') % repo[newunstable.first()])
> -        if repo.revs("%ld and public()", revs):
> -            raise error.Abort(_('cannot edit commit information for public '
> -                                'revisions'))
> -        root = head = repo[revs.first()]
> +            raise error.Abort(_('editing multiple revisions without --fold is '
> +                                'not currently supported'))
> +
> +        if opts['fold']:
> +            root, head = _foldcheck(repo, revs)
> +        else:
> +            newunstable = _newdisallowedunstable(repo, revs)
> +            if newunstable:
> +                raise error.Abort(
> +                    _('cannot edit commit information in the middle of a stack'),
> +                    hint=_('%s will be affected') % repo[newunstable.first()])
> +            if repo.revs("%ld and public()", revs):
> +                raise error.Abort(_('cannot edit commit information for public '
> +                                    'revisions'))
> +            root = head = repo[revs.first()]
>
>           wctx = repo[None]
>           p1 = wctx.p1()
> @@ -3217,7 +3233,12 @@ def metaedit(ui, repo, *revs, **opts):
>               if commitopts.get('message') or commitopts.get('logfile'):
>                   commitopts['edit'] = False
>               else:
> -                msgs = [head.description()]
> +                if opts['fold']:
> +                    msgs = ["HG: This is a fold of %d changesets." % len(allctx)]
> +                    msgs += ["HG: Commit message of changeset %s.\n\n%s\n" %
> +                             (c.rev(), c.description()) for c in allctx]
> +                else:
> +                    msgs = [head.description()]
>                   commitopts['message'] =  "\n".join(msgs)
>                   commitopts['edit'] = True
>
> @@ -3239,6 +3260,8 @@ def metaedit(ui, repo, *revs, **opts):
>           finally:
>               tr.release()
>
> +        if opts['fold']:
> +            ui.status('%i changesets folded\n' % len(revs))
>           if newp1 is not None:
>               hg.update(repo, newp1)
>       finally:
> diff --git a/tests/test-evolve.t b/tests/test-evolve.t
> --- a/tests/test-evolve.t
> +++ b/tests/test-evolve.t
> @@ -1468,11 +1468,26 @@ hg metaedit
>     $ hg metaedit -r 0
>     abort: cannot edit commit information for public revisions
>     [255]
> +  $ hg metaedit --fold
> +  abort: revisions must be specified with --fold
> +  [255]
> +  $ hg metaedit -r 0 --fold
> +  abort: cannot fold public revisions
> +  [255]
> +  $ hg metaedit '36 + 42' --fold
> +  abort: cannot fold non-linear revisions (multiple roots given)
> +  [255]
> +  $ hg metaedit '36::39 + 41' --fold
> +  abort: cannot fold non-linear revisions (multiple heads given)
> +  [255]
>   check that metaedit respects allowunstable
>     $ hg metaedit '.^' --config 'experimental.evolution=createmarkers, allnewcommands'
>     abort: cannot edit commit information in the middle of a stack
>     (c904da5245b0 will be affected)
>     [255]
> +  $ hg metaedit '18::20' --fold --config 'experimental.evolution=createmarkers, allnewcommands'
> +  abort: cannot fold chain not ending with a head or with branching
> +  [255]
>     $ hg metaedit --user foobar
>     0 files updated, 0 files merged, 0 files removed, 0 files unresolved
>     $ hg log --template '{rev}: {author}\n' -r '42:' --hidden
> @@ -1483,26 +1498,57 @@ check that metaedit respects allowunstab
>
>   TODO: support this
>     $ hg metaedit '.^::.'
> -  abort: editing multiple revisions is not currently supported
> +  abort: editing multiple revisions without --fold is not currently supported
>     [255]
>
> -no new commit is created here because the date is the same
> -  $ HGEDITOR=cat hg metaedit
> +  $ HGEDITOR=cat hg metaedit '.^::.' --fold
> +  HG: This is a fold of 2 changesets.
> +  HG: Commit message of changeset 41.
> +
> +  amended
> +
> +  HG: Commit message of changeset 43.
> +
>     will be evolved safely
>
>
> +
>     HG: Enter commit message.  Lines beginning with 'HG:' are removed.
>     HG: Leave message empty to abort commit.
>     HG: --
> -  HG: user: foobar
> +  HG: user: test
>     HG: branch 'default'
>     HG: changed a
> +  HG: changed newfile
> +  2 changesets folded
> +  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
> +
> +  $ glog -r .
> +  @  44:41bf1183869c at default(draft) amended
> +  |
> +  ~
> +
> +no new commit is created here because the date is the same
> +  $ HGEDITOR=cat hg metaedit
> +  amended
> +
> +
> +  will be evolved safely
> +
> +
> +  HG: Enter commit message.  Lines beginning with 'HG:' are removed.
> +  HG: Leave message empty to abort commit.
> +  HG: --
> +  HG: user: test
> +  HG: branch 'default'
> +  HG: changed a
> +  HG: changed newfile
>     nothing changed
>
>     $ glog -r '.^::.'
> -  @  43:62353add3dfb at default(draft) will be evolved safely
> +  @  44:41bf1183869c at default(draft) amended
>     |
> -  o  41:34ae045ec400 at default(draft) amended
> +  o  36:43c3f5ef149f at default(draft) add uu
>     |
>     ~
>
> @@ -1510,15 +1556,22 @@ TODO: don't create a new commit in this
>     $ hg metaedit --config defaults.metaedit=
>     0 files updated, 0 files merged, 0 files removed, 0 files unresolved
>     $ hg log -r '.^::.' --template '{rev}: {desc|firstline}\n'
> -  41: amended
> -  44: will be evolved safely
> +  36: add uu
> +  45: amended
>
>     $ hg up .^
> -  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
> -  $ hg metaedit --user foobar2 44
> +  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
> +  $ hg metaedit --user foobar2 45
>     $ hg log --template '{rev}: {author}\n' -r '42:' --hidden
>     42: test
>     43: foobar
> -  44: foobar
> -  45: foobar2
> -  $ hg diff -r 44 -r 45 --hidden
> +  44: test
> +  45: test
> +  46: foobar2
> +  $ hg diff -r 45 -r 46 --hidden
> +
> +'fold' one commit
> +  $ hg metaedit 39 --fold --user foobar3
> +  1 changesets folded
> +  $ hg log -r 47 --template '{rev}: {author}\n'
> +  47: foobar3
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at mercurial-scm.org
> https://urldefense.proofpoint.com/v2/url?u=https-3A__www.mercurial-2Dscm.org_mailman_listinfo_mercurial-2Ddevel&d=CwIGaQ&c=5VD0RTtNlTh3ycd41b3MUw&r=mEgSWILcY4c4W3zjApBQLA&m=XfbXzcGwwRMgZmat40fFUaZ0CcV6NyBzFYW0byLdjFI&s=dLxu70EPAoZCUILk9YUVhCGeABBWbJ2-IBVHUc5h_zQ&e=
>

-- 
Simon Farnsworth


More information about the Mercurial-devel mailing list