fbamend: merge fbmetaedit

Summary:
Merge fbmetaedit which uses a fast path to change commit messages.

Make fbmetaedit a no-op.

Test Plan: arc unit

Reviewers: #mercurial, mitrandir

Reviewed By: mitrandir

Subscribers: mjpieters, medson

Differential Revision: https://phabricator.intern.facebook.com/D5254867

Signature: t1:5254867:1497524975:c7cc3ad9d1162332fbdd665eb5a2f6d7ce87a585
This commit is contained in:
Jun Wu 2017-06-16 14:12:32 -07:00
parent 87b248dd27
commit 2852dabbc8
5 changed files with 145 additions and 419 deletions

View File

@ -235,3 +235,49 @@ def rewrite(repo, old, updates, head, newbases, commitopts):
return newid, created
finally:
lockmod.release(tr, lock, wlock)
def metarewrite(repo, old, newbases, commitopts):
"""Return (nodeid, created) where nodeid is the identifier of the
changeset generated by the rewrite process, and created is True if
nodeid was actually created. If created is False, nodeid
references a changeset existing before the rewrite call.
"""
wlock = lock = tr = None
try:
wlock = repo.wlock()
lock = repo.lock()
tr = repo.transaction('rewrite')
updatebookmarks = bookmarksupdater(repo, old.node(), tr)
message = cmdutil.logmessage(repo.ui, commitopts)
if not message:
message = old.description()
user = commitopts.get('user') or old.user()
date = commitopts.get('date') or None # old.date()
extra = dict(commitopts.get('extra', old.extra()))
extra['branch'] = old.branch()
new = context.metadataonlyctx(repo,
old,
parents=newbases,
text=message,
user=user,
date=date,
extra=extra)
if commitopts.get('edit'):
new._text = cmdutil.commitforceeditor(repo, new, [])
revcount = len(repo)
newid = repo.commitctx(new)
new = repo[newid]
created = len(repo) != revcount
updatebookmarks(newid)
tr.close()
return newid, created
finally:
lockmod.release(tr, lock, wlock)
def newunstable(repo, revs):
return repo.revs("(%ld::) - %ld", revs, revs)

View File

@ -105,7 +105,6 @@ def metaedit(ui, repo, *revs, **opts):
try:
commitopts = opts.copy()
allctx = [repo[r] for r in revs]
targetphase = max(c.phase() for c in allctx)
if commitopts.get('message') or commitopts.get('logfile'):
commitopts['edit'] = False
@ -120,21 +119,68 @@ def metaedit(ui, repo, *revs, **opts):
commitopts['message'] = "\n".join(msgs)
commitopts['edit'] = True
# TODO: if the author and message are the same, don't create a new
# hash. Right now we create a new hash because the date can be
# different.
newid, created = common.rewrite(
repo, root, allctx, head, [root.p1().node(), root.p2().node()],
commitopts=commitopts)
if created:
if p1.rev() in revs:
newp1 = newid
phases.retractboundary(repo, tr, targetphase, [newid])
obsolete.createmarkers(repo, [(ctx, (repo[newid],))
for ctx in allctx])
if root == head:
# fast path: use metarewrite
replacemap = {}
# we need topological order
allctx = sorted(allctx, key=lambda c: c.rev())
# all descendats that can be safely rewritten
newunstable = common.newunstable(repo, revs)
newunstablectx = sorted([repo[r] for r in newunstable],
key=lambda c: c.rev())
def _rewritesingle(c, _commitopts):
if _commitopts.get('edit', False):
_commitopts['message'] = \
"HG: Commit message of changeset %s\n%s" %\
(str(c), c.description())
bases = [
replacemap.get(c.p1().node(), c.p1().node()),
replacemap.get(c.p2().node(), c.p2().node()),
]
newid, created = common.metarewrite(repo, c, bases,
commitopts=_commitopts)
if created:
replacemap[c.node()] = newid
for c in allctx:
_rewritesingle(c, commitopts)
for c in newunstablectx:
_rewritesingle(c,
{'date': commitopts.get('date') or None})
if p1.node() in replacemap:
repo.setparents(replacemap[p1.node()])
if len(replacemap) > 0:
obsolete.createmarkers(
repo,
[(repo[old], (repo[new],))
for old, new in replacemap.iteritems()],
)
# TODO: set poroper phase boundaries (affects secret
# phase only)
else:
ui.status(_("nothing changed\n"))
return 1
else:
ui.status(_("nothing changed\n"))
return 1
# slow path: create a new commit
targetphase = max(c.phase() for c in allctx)
# TODO: if the author and message are the same, don't create a
# new hash. Right now we create a new hash because the date can
# be different.
newid, created = common.rewrite(
repo, root, allctx, head,
[root.p1().node(), root.p2().node()],
commitopts=commitopts)
if created:
if p1.rev() in revs:
newp1 = newid
phases.retractboundary(repo, tr, targetphase, [newid])
obsolete.createmarkers(repo, [(ctx, (repo[newid],))
for ctx in allctx])
else:
ui.status(_("nothing changed\n"))
return 1
tr.close()
finally:
tr.release()

View File

@ -4,160 +4,5 @@
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
"""extends the existing metaedit functionality
Speeds up metaedit by reusing manifestes and allows to metaedit
multiple commit at once.
"""
from mercurial import (
cmdutil,
context,
error,
extensions,
lock as lockmod,
registrar,
scmutil,
obsolete,
)
from mercurial.i18n import _
wrapcommand = extensions.wrapcommand
wrapfunction = extensions.wrapfunction
cmdtable = {}
command = registrar.command(cmdtable)
testedwith = 'ships-with-fb-hgext'
def uisetup(ui):
order = extensions._order
order.remove('fbmetaedit')
order.append('fbmetaedit')
def extsetup(ui):
try:
evolve = extensions.find('evolve')
def metarewrite(repo, old, newbases, commitopts):
"""Return (nodeid, created) where nodeid is the identifier of the
changeset generated by the rewrite process, and created is True if
nodeid was actually created. If created is False, nodeid
references a changeset existing before the rewrite call.
"""
wlock = lock = tr = None
try:
wlock = repo.wlock()
lock = repo.lock()
tr = repo.transaction('rewrite')
updatebookmarks = evolve._bookmarksupdater(repo, old.node(), tr)
message = cmdutil.logmessage(repo.ui, commitopts)
if not message:
message = old.description()
user = commitopts.get('user') or old.user()
date = commitopts.get('date') or None # old.date()
extra = dict(commitopts.get('extra', old.extra()))
extra['branch'] = old.branch()
new = context.metadataonlyctx(repo,
old,
parents=newbases,
text=message,
user=user,
date=date,
extra=extra)
if commitopts.get('edit'):
new._text = cmdutil.commitforceeditor(repo, new, [])
revcount = len(repo)
newid = repo.commitctx(new)
new = repo[newid]
created = len(repo) != revcount
updatebookmarks(newid)
tr.close()
return newid, created
finally:
lockmod.release(tr, lock, wlock)
def _metaedit(orig, ui, repo, *revs, **opts):
if opts['fold']:
return orig(ui, repo, *revs, **opts)
revs = list(revs)
revs.extend(opts['rev'])
if not revs:
revs = ['.']
wlock = lock = None
try:
wlock = repo.wlock()
lock = repo.lock()
revs = scmutil.revrange(repo, revs)
if repo.revs("%ld and public()", revs):
raise error.Abort(_('cannot edit commit information for '
'public revisions'))
wctx = repo[None]
p1 = wctx.p1()
tr = repo.transaction('metaedit')
try:
commitopts = opts.copy()
allctx = [repo[r] for r in revs]
if commitopts.get('message') or commitopts.get('logfile'):
commitopts['edit'] = False
else:
commitopts['edit'] = True
replacemap = {}
# we need topological order
allctx = sorted(allctx, key=lambda c: c.rev())
# all descendats that can be safely rewritten
newunstable = evolve._disallowednewunstable(repo, revs)
newunstablectx = sorted([repo[r] for r in newunstable],
key=lambda c: c.rev())
def _rewritesingle(c, _commitopts):
if _commitopts.get('edit', False):
_commitopts['message'] = \
"HG: Commit message of changeset %s\n%s" %\
(str(c), c.description())
bases = [
replacemap.get(c.p1().node(), c.p1().node()),
replacemap.get(c.p2().node(), c.p2().node()),
]
newid, created = metarewrite(repo, c, bases,
commitopts=_commitopts)
if created:
replacemap[c.node()] = newid
for c in allctx:
_rewritesingle(c, commitopts)
for c in newunstablectx:
_rewritesingle(c,
{'date': commitopts.get('date') or None})
if p1.node() in replacemap:
repo.setparents(replacemap[p1.node()])
if len(replacemap) > 0:
obsolete.createmarkers(
repo,
[(repo[old], (repo[new],))
for old, new in replacemap.iteritems()],
)
# TODO: set poroper phase boundaries (affects secret
# phase only)
else:
ui.status(_("nothing changed\n"))
tr.close()
finally:
tr.release()
finally:
lockmod.release(lock, wlock)
if '^metaedit' in evolve.cmdtable:
wrapcommand(evolve.cmdtable, 'metaedit', _metaedit)
except KeyError:
pass # evolve not found
# moved to fbamend

View File

@ -115,7 +115,6 @@ Test
[255]
$ hg metaedit --user foobar
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg log --template '{rev}: {author}\n' -r 'desc(F):' --hidden
5: test
6: test
@ -159,6 +158,7 @@ TODO: support this
no new commit is created here because the date is the same
$ HGEDITOR=cat hg metaedit
HG: Commit message of changeset a08d35fd7d9d
E
@ -187,7 +187,6 @@ old commit (we add a default date with a value to show that metaedit is taking
the current date to generate the hash, this way we still have a stable hash
but highlight the bug)
$ hg metaedit --config defaults.metaedit= --config devel.default-date="42 0"
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg log -r '.^::.' --template '{rev}: {desc|firstline}\n'
3: C
11: E
@ -207,3 +206,39 @@ but highlight the bug)
1 changesets folded
$ hg log -r "tip" --template '{rev}: {author}\n'
13: foobar3
metaedit a commit in the middle of the stack:
$ cd $TESTTMP
$ hg init metaedit2
$ cd metaedit2
$ hg debugbuilddag '+5'
$ hg update tip
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ glog -r 'all()'
@ 4:bebd167eb94d@default(draft) r4
|
o 3:2dc09a01254d@default(draft) r3
|
o 2:01241442b3c2@default(draft) r2
|
o 1:66f7d451a68b@default(draft) r1
|
o 0:1ea73414a91b@default(draft) r0
$ hg metaedit -m "metaedit" -r 2
$ glog -r 'all()'
@ 7:8c1f124031e7@default(draft) r4
|
o 6:af1447d6a312@default(draft) r3
|
o 5:1aed0f31debd@default(draft) metaedit
|
o 1:66f7d451a68b@default(draft) r1
|
o 0:1ea73414a91b@default(draft) r0
$ hg metaedit -m "metaedit" -r 1aed0f31debd
nothing changed
[1]

View File

@ -1,246 +0,0 @@
based on test-evolve.t from mutable-history extension
$ . $TESTDIR/require-ext.sh evolve
$ REPOROOT=`dirname $TESTDIR`
$ cat >> $HGRCPATH <<EOF
> [defaults]
> amend=-d "0 0"
> fold=-d "0 0"
> metaedit=-d "0 0"
> [web]
> push_ssl = false
> allow_push = *
> [phases]
> publish = False
> [alias]
> qlog = log --template='{rev} - {node|short} {desc} ({phase})\n'
> [diff]
> git = 1
> unified = 0
> [extensions]
> hgext.graphlog=
> fbmetaedit=$REPOROOT/hgext3rd/fbmetaedit.py
> evolve=
> EOF
$ mkcommit() {
> echo "$1" > "$1"
> hg add "$1"
> hg ci -m "add $1"
> }
$ mkstack() {
> # Creates a stack of commit based on $1 with messages from $2, $3 ..
> hg update $1 -C
> shift
> mkcommits $*
> }
$ glog() {
> hg glog --template '{rev}:{node|short}@{branch}({phase}) {desc|firstline}\n' "$@"
> }
$ shaof() {
> hg log -T {node} -r "first(desc($1))"
> }
$ mkcommits() {
> for i in $@; do mkcommit $i ; done
> }
various init
$ hg init local
$ cd local
$ mkcommit a
$ mkcommit b
$ cat >> .hg/hgrc << EOF
> [phases]
> publish = True
> EOF
$ hg pull -q . # make 1 public
$ rm .hg/hgrc
$ mkcommit c
$ mkcommit d
$ hg up 1
0 files updated, 0 files merged, 2 files removed, 0 files unresolved
$ mkcommit e -q
created new head
$ mkcommit f
$ mkcommit g
$ hg qlog
6 - c802b7e6fec9 add g (draft)
5 - e44648563c73 add f (draft)
4 - fbb94e3a0ecf add e (draft)
3 - 47d2a3944de8 add d (draft)
2 - 4538525df7e2 add c (draft)
1 - 7c3bad9141dc add b (public)
0 - 1f0dee641bb7 add a (public)
hg metaedit
-----------
$ glog
@ 6:c802b7e6fec9@default(draft) add g
|
o 5:e44648563c73@default(draft) add f
|
o 4:fbb94e3a0ecf@default(draft) add e
|
| o 3:47d2a3944de8@default(draft) add d
| |
| o 2:4538525df7e2@default(draft) add c
|/
o 1:7c3bad9141dc@default(public) add b
|
o 0:1f0dee641bb7@default(public) add a
$ hg metaedit -r 0 -m "xx"
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 '2 + 5' --fold
abort: cannot fold non-linear revisions (multiple roots given)
[255]
check that metaedit respects allowunstable
$ hg metaedit '4::5' --fold --config 'experimental.evolution=createmarkers, allnewcommands'
abort: cannot fold chain not ending with a head or with branching
(new unstable changesets are not allowed)
[255]
$ hg metaedit --user foobar
$ hg log --template '{rev}: {author}\n' -r '2:' --hidden
2: test
3: test
4: test
5: test
6: test
7: foobar
$ hg log --template '{rev}: {author}\n' -r .
7: foobar
$ cat >> $TESTTMP/modifymsg.sh <<EOF
> #!/bin/bash
> sed -e 's/add f/add f nicely/g' \$1 > $TESTTMP/newmsg
> mv $TESTTMP/newmsg \$1
> EOF
$ chmod a+x $TESTTMP/modifymsg.sh
$ HGEDITOR="$TESTTMP/modifymsg.sh" hg metaedit -d '1 1' '.^::.'
$ HGEDITOR=cat hg metaedit '.^::.' --fold
HG: This is a fold of 2 changesets.
HG: Commit message of changeset 8.
add f nicely
HG: Commit message of changeset 9.
add g
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: added f
HG: added g
2 changesets folded
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ glog -r .
@ 10:09b4ac0f24fc@default(draft) add f nicely
|
~
no new commit is created here because the date is the same
$ HGEDITOR=cat hg metaedit
HG: Commit message of changeset 09b4ac0f24fc
add f nicely
add g
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: added f
HG: added g
nothing changed
$ glog -r '.^::.'
@ 10:09b4ac0f24fc@default(draft) add f nicely
|
o 4:fbb94e3a0ecf@default(draft) add e
|
~
$ hg up ".^"
0 files updated, 0 files merged, 2 files removed, 0 files unresolved
$ hg metaedit --user foobar2 .
$ hg log --template '{rev}: {author}\n' -r '3:' --hidden
3: test
4: test
5: test
6: test
7: foobar
8: test
9: foobar
10: test
11: foobar2
metaedit a commit in the middle of the stack:
$ glog -r '(.^)::'
@ 11:682abdd0f684@default(draft) add e
|
| o 10:09b4ac0f24fc@default(draft) add f nicely
| |
| x 4:fbb94e3a0ecf@default(draft) add e
|/
| o 3:47d2a3944de8@default(draft) add d
| |
| o 2:4538525df7e2@default(draft) add c
|/
o 1:7c3bad9141dc@default(public) add b
|
~
$ hg metaedit -m "add uu (with metaedit)" --config 'experimental.evolution=createmarkers, allnewcommands'
$ glog -r '(.^)::'
@ 12:f6c3c1613ce9@default(draft) add uu (with metaedit)
|
| o 10:09b4ac0f24fc@default(draft) add f nicely
| |
| x 4:fbb94e3a0ecf@default(draft) add e
|/
| o 3:47d2a3944de8@default(draft) add d
| |
| o 2:4538525df7e2@default(draft) add c
|/
o 1:7c3bad9141dc@default(public) add b
|
~
$ hg metaedit -m "add uu (with metaedit)"
nothing changed
$ glog -r '(.^)::'
@ 12:f6c3c1613ce9@default(draft) add uu (with metaedit)
|
| o 10:09b4ac0f24fc@default(draft) add f nicely
| |
| x 4:fbb94e3a0ecf@default(draft) add e
|/
| o 3:47d2a3944de8@default(draft) add d
| |
| o 2:4538525df7e2@default(draft) add c
|/
o 1:7c3bad9141dc@default(public) add b
|
~