Submitter | Siddharth Agarwal |
---|---|
Date | April 18, 2016, 6:14 p.m. |
Message ID | <d39a22490ec843e9a089.1461003278@dev666.prn1.facebook.com> |
Download | mbox | patch |
Permalink | /patch/14728/ |
State | Superseded |
Delegated to: | Pierre-Yves David |
Headers | show |
Comments
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@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@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@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@default(draft) will be evolved safely > + @ 44:41bf1183869c@default(draft) amended > | > - o 41:34ae045ec400@default(draft) amended > + o 36:43c3f5ef149f@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@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= >
On 4/25/16 15:03, Simon Farnsworth wrote: > 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? Reorder can in principle involve working copy merges, so it's probably not the best fit. --roll sounds interesting but you can achieve it with something like --logfile <(hg log -r <commit> -T '{desc}'). I'd wait for it to be implemented for 'hg commit --amend' and similar, though.
Patch
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@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@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@default(draft) will be evolved safely + @ 44:41bf1183869c@default(draft) amended | - o 41:34ae045ec400@default(draft) amended + o 36:43c3f5ef149f@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