mirror of
https://github.com/facebook/sapling.git
synced 2024-10-07 23:38:50 +03:00
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:
parent
87b248dd27
commit
2852dabbc8
@ -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)
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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]
|
||||
|
@ -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
|
||||
|
|
||||
~
|
Loading…
Reference in New Issue
Block a user