--- a/hgext3rd/evolve/cmdrewrite.py Thu Apr 12 13:30:28 2018 +0800
+++ b/hgext3rd/evolve/cmdrewrite.py Sun Mar 18 23:48:06 2018 +0530
@@ -33,6 +33,8 @@
from mercurial.i18n import _
+from mercurial.utils import dateutil
+
from . import (
compat,
state,
@@ -94,6 +96,7 @@
('a', 'all', False, _("match all files")),
('e', 'edit', False, _('invoke editor on commit messages')),
('', 'extract', False, _('extract changes from the commit to the working copy')),
+ ('', 'patch', False, _('make changes to wdir parent by editing patch')),
('', 'close-branch', None,
_('mark a branch as closed, hiding it from the branch list')),
('s', 'secret', None, _('use the secret phase for committing')),
@@ -118,6 +121,8 @@
"""
_checknotesize(ui, opts)
opts = opts.copy()
+ if opts.get('patch'):
+ return amendpatch(ui, repo, *pats, **opts)
if opts.get('extract'):
return uncommit(ui, repo, *pats, **opts)
else:
@@ -140,6 +145,127 @@
finally:
lockmod.release(lock, wlock)
+def amendpatch(ui, repo, *pats, **opts):
+ """logic for --patch flag of `hg amend` command."""
+ lock = wlock = tr = None
+ try:
+ wlock = repo.wlock()
+ lock = repo.lock()
+ tr = repo.transaction('amend')
+ cmdutil.bailifchanged(repo)
+ # first get the patch
+ old = repo['.']
+ p1 = old.p1()
+ rewriteutil.precheck(repo, [old.rev()], 'amend')
+ bookmarkupdater = rewriteutil.bookmarksupdater(repo, old.node(), tr)
+ diffopts = patch.difffeatureopts(repo.ui, whitespace=True)
+ diffopts.nodates = True
+ diffopts.git = True
+ fp = stringio()
+ _writectxmetadata(repo, old, fp)
+ matcher = scmutil.match(old, pats, opts)
+ for chunk, label in patch.diffui(repo, p1.node(), old.node(),
+ match=matcher,
+ opts=diffopts):
+ fp.write(chunk)
+
+ fp.seek(0)
+ newpatch = ui.edit(fp.getvalue(), old.user(), action="diff")
+
+ afp = stringio()
+ afp.write(newpatch)
+ if pats:
+ # write rest of the files in the patch
+ restmatcher = scmutil.match(old, [], opts={'exclude': pats})
+ for chunk, label in patch.diffui(repo, p1.node(), old.node(),
+ match=restmatcher,
+ opts=diffopts):
+ afp.write(chunk)
+
+ afp.seek(0)
+ # write the patch to repo and get the newnode
+ newnode = _writepatch(ui, repo, old, afp)
+
+ if newnode == old.node():
+ raise error.Abort(_("nothing changed"))
+ metadata = {}
+ if opts.get('note'):
+ metadata['note'] = opts['note']
+ compat.createmarkers(repo, [(old, (repo[newnode],))],
+ metadata=metadata, operation='amend')
+ phases.retractboundary(repo, tr, old.phase(), [newnode])
+ hg.updaterepo(repo, newnode, True)
+ bookmarkupdater(newnode)
+ tr.close()
+ finally:
+ tr.release()
+ lockmod.release(lock, wlock)
+
+def _writepatch(ui, repo, old, fp):
+ """utility function to use filestore and patchrepo to apply a patch to the
+ repository with metadata being extracted from the patch"""
+ metadata = patch.extract(ui, fp)
+ pold = old.p1()
+
+ # store the metadata from the patch to variables
+ parents = (metadata.get('p1'), metadata.get('p2'))
+ date = metadata.get('date') or old.date()
+ branch = metadata.get('branch') or old.branch()
+ user = metadata.get('user') or old.user()
+ # XXX: we must extract extras from the patchfile too
+ extra = old.extra()
+ message = metadata.get('message') or old.description()
+ store = patch.filestore()
+ fp.seek(0)
+ try:
+ files = set()
+ try:
+ patch.patchrepo(ui, repo, pold, store, fp, 1, '',
+ files=files, eolmode=None)
+ except patch.PatchError as err:
+ raise error.Abort(str(err))
+
+ finally:
+ del fp
+
+ memctx = context.memctx(repo, parents, message, files=files,
+ filectxfn=store,
+ user=user,
+ date=date,
+ branch=branch,
+ extra=extra)
+ newcm = memctx.commit()
+ finally:
+ store.close()
+ return newcm
+
+def _writectxmetadata(repo, ctx, fp):
+ nodeval = scmutil.binnode(ctx)
+ parents = [p.node() for p in ctx.parents() if p]
+ branch = ctx.branch()
+ if parents:
+ prev = parents[0]
+ else:
+ prev = node.nullid
+
+ fp.write("# HG changeset patch\n")
+ fp.write("# User %s\n" % ctx.user())
+ fp.write("# Date %d %d\n" % ctx.date())
+ fp.write("# %s\n" % dateutil.datestr(ctx.date()))
+ if branch and branch != 'default':
+ fp.write("# Branch %s\n" % branch)
+ fp.write("# Node ID %s\n" % node.hex(nodeval))
+ fp.write("# Parent %s\n" % node.hex(prev))
+ if len(parents) > 1:
+ fp.write("# Parent %s\n" % node.hex(parents[1]))
+
+ for headerid in cmdutil.extraexport:
+ header = cmdutil.extraexportmap[headerid](1, ctx)
+ if header is not None:
+ fp.write('# %s\n' % header)
+ fp.write(ctx.description().rstrip())
+ fp.write("\n\n")
+
def _touchedbetween(repo, source, dest, match=None):
touched = set()
for files in repo.status(source, dest, match=match)[:3]: