amend: add a new flag `--patch` to `hg amend`
authorPulkit Goyal <7895pulkit@gmail.com>
Sun, 18 Mar 2018 23:48:06 +0530
changeset 3660 f018656ca3bf
parent 3659 1e9b535cd9be
child 3661 61fdd25542a6
amend: add a new flag `--patch` to `hg amend` This patch adds a new flag `--patch` to `hg amend` which pops up an editor with the patch of working directory parent which you can change, and when you exit the editor the patch with changes is applied to current working directory with old changeset being obsoleted in favour of new one created by the applied patch. If supplied filenames, only those filenames are present in the popped editor and rest files stay the same way in the commit as they were. The extension of the file which opens up in editor is '.diff', we cannot have it as '.patch' as there will be develwarns related to that. We need to change to patch core and undo some change to achieve this. The implementation does not use any core API rather it has picked chunks from API which are required. One main reason to not use core import API is that we have to change wdir parent before using patch.patch() which I will like to avoid to make sure we handle merge cases too. While writing this patch I have spend lot of time try to use internal API's to work for this but none of them served the purpose well. If I have time in future and work on similar problem again, I am going to write better high-level API's which uses patchstore to achieve this. A new test file test-amend-patch.t which contains a lot of testing of the feature.
CHANGELOG
hgext3rd/evolve/cmdrewrite.py
tests/test-amend-patch.t
tests/test-amend.t
--- a/CHANGELOG	Thu Apr 12 13:30:28 2018 +0800
+++ b/CHANGELOG	Sun Mar 18 23:48:06 2018 +0530
@@ -9,6 +9,7 @@
   * evolve: a new `--abort` flag which aborts an interrupted evolve
             resolving orphans
   * `hg evolve` now return 0 if there is nothing to evolve
+  * amend: a new `--patch` flag to make changes to wdir parent by editing patch
 
   * fixed some memory leak issue
 
--- 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]:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-amend-patch.t	Sun Mar 18 23:48:06 2018 +0530
@@ -0,0 +1,1152 @@
+** Test for the `--patch` flag for `hg amend` command **
+
+Setup
+
+  $ cat >> $HGRCPATH << EOF
+  > [alias]
+  > glog = log -GT "{rev}:{node|short} {desc}\n ({bookmarks}) {phase}"
+  > [diff]
+  > git = 1
+  > [extensions]
+  > EOF
+  $ echo "evolve=$(echo $(dirname $TESTDIR))/hgext3rd/evolve/" >> $HGRCPATH
+
+Reposetup
+
+  $ hg init repo
+  $ cd repo
+  $ echo foo > a
+  $ hg ci -Aqm "added a"
+  $ hg exp
+  # HG changeset patch
+  # User test
+  # Date 0 0
+  #      Thu Jan 01 00:00:00 1970 +0000
+  # Node ID f7ad4196431346de3c33c52e75374fba45e04313
+  # Parent  0000000000000000000000000000000000000000
+  added a
+  
+  diff --git a/a b/a
+  new file mode 100644
+  --- /dev/null
+  +++ b/a
+  @@ -0,0 +1,1 @@
+  +foo
+
+Testing of just changing the diff, not the patch metadata
+==========================================================
+
+Testing the normal case
+-----------------------
+
+  $ cat > editor.sh <<EOF
+  > #!/bin/sh
+  > cat > \$1 <<ENDOF
+  > # HG changeset patch
+  > # User test
+  > # Date 0 0
+  > #      Thu Jan 01 00:00:00 1970 +0000
+  > # Node ID f7ad4196431346de3c33c52e75374fba45e04313
+  > # Parent  0000000000000000000000000000000000000000
+  > added a
+  > diff --git a/a b/a
+  > new file mode 100644
+  > --- /dev/null
+  > +++ b/a
+  > @@ -0,0 +1,1 @@
+  > +Gello
+  > ENDOF
+  > EOF
+
+  $ HGEDITOR="sh ./editor.sh" hg amend --patch
+
+Making sure the amended commit is correct
+
+  $ hg exp
+  # HG changeset patch
+  # User test
+  # Date 0 0
+  #      Thu Jan 01 00:00:00 1970 +0000
+  # Node ID af624b221c0c0bec5d74e2650180dd3eddcb7c42
+  # Parent  0000000000000000000000000000000000000000
+  added a
+  
+  diff --git a/a b/a
+  new file mode 100644
+  --- /dev/null
+  +++ b/a
+  @@ -0,0 +1,1 @@
+  +Gello
+
+  $ hg glog
+  @  1:af624b221c0c added a
+      () draft
+
+Obsolsence history is fine
+
+  $ hg obslog -p -r .
+  @  af624b221c0c (1) added a
+  |
+  x  f7ad41964313 (0) added a
+       rewritten(content) as af624b221c0c using amend by test (Thu Jan 01 00:00:00 1970 +0000)
+         diff --git a/a b/a
+         --- a/a
+         +++ b/a
+         @@ -1,1 +1,1 @@
+         -foo
+         +Gello
+  
+  
+Diff and status are good too
+  $ hg diff
+  $ hg status
+  ? editor.sh
+  $ cat a
+  Gello
+
+Dirstate parents should be correctly set
+  $ hg parents
+  changeset:   1:af624b221c0c
+  tag:         tip
+  parent:      -1:000000000000
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     added a
+  
+Trying to amend with a wrong patch
+----------------------------------
+
+Having context which was is not present
+
+  $ cat > editor.sh <<EOF
+  > #!/bin/sh
+  > cat > \$1 <<ENDOF
+  > # HG changeset patch
+  > # User test
+  > # Date 0 0
+  > #      Thu Jan 01 00:00:00 1970 +0000
+  > # Node ID c6ba250efbf73e671f2ca24b79db2c178ccbfff9
+  > # Parent  0000000000000000000000000000000000000000
+  > added a
+  > diff --git a/a b/a
+  > new file mode 100644
+  > --- /dev/null
+  > +++ b/a
+  > @@ -0,0 +1,1 @@
+  > I was not there before!
+  > +Gello
+  > ENDOF
+  > EOF
+
+  $ HGEDITOR="sh ./editor.sh" hg amend --patch
+  abort: bad hunk #1 @@ -0,0 +1,1 @@
+   (1 0 1 1)
+  [255]
+
+Having deletions which dont exists
+
+  $ cat > editor.sh <<EOF
+  > #!/bin/sh
+  > cat > \$1 <<ENDOF
+  > # HG changeset patch
+  > # User test
+  > # Date 0 0
+  > #      Thu Jan 01 00:00:00 1970 +0000
+  > # Node ID af624b221c0c0bec5d74e2650180dd3eddcb7c42
+  > # Parent  0000000000000000000000000000000000000000
+  > added a
+  > diff --git a/a b/a
+  > new file mode 100644
+  > --- /dev/null
+  > +++ b/a
+  > @@ -0,0 +1,1 @@
+  > -I was not deleted before!
+  > +Gello
+  > ENDOF
+  > EOF
+
+  $ HGEDITOR="sh ./editor.sh" hg amend --patch
+  abort: bad hunk #1 @@ -0,0 +1,1 @@
+   (1 0 1 1)
+  [255]
+
+Changing the file mode using amend --patch
+------------------------------------------
+
+  $ cat > editor.sh <<EOF
+  > #!/bin/sh
+  > cat > \$1 <<ENDOF
+  > # HG changeset patch
+  > # User test
+  > # Date 0 0
+  > #      Thu Jan 01 00:00:00 1970 +0000
+  > # Node ID af624b221c0c0bec5d74e2650180dd3eddcb7c42
+  > # Parent  0000000000000000000000000000000000000000
+  > added a
+  > diff --git a/a b/a
+  > new file mode 100755
+  > --- /dev/null
+  > +++ b/a
+  > @@ -0,0 +1,1 @@
+  > +Gello
+  > ENDOF
+  > EOF
+
+  $ HGEDITOR="sh ./editor.sh" hg amend --patch
+
+  $ hg exp --git
+  # HG changeset patch
+  # User test
+  # Date 0 0
+  #      Thu Jan 01 00:00:00 1970 +0000
+  # Node ID 3a99e4b7ac73da799e20ae56914e3dd5b1a22d4d
+  # Parent  0000000000000000000000000000000000000000
+  added a
+  
+  diff --git a/a b/a
+  new file mode 100755
+  --- /dev/null
+  +++ b/a
+  @@ -0,0 +1,1 @@
+  +Gello
+
+Changing the file using amend --patch
+-------------------------------------
+
+  $ cat > editor.sh <<EOF
+  > #!/bin/sh
+  > cat > \$1 <<ENDOF
+  > # HG changeset patch
+  > # User test
+  > # Date 0 0
+  > #      Thu Jan 01 00:00:00 1970 +0000
+  > # Node ID 3a99e4b7ac73da799e20ae56914e3dd5b1a22d4d
+  > # Parent  0000000000000000000000000000000000000000
+  > added a
+  > diff --git a/changedfile b/changedfile
+  > new file mode 100755
+  > --- /dev/null
+  > +++ b/changedfile
+  > @@ -0,0 +1,1 @@
+  > +Gello
+  > ENDOF
+  > EOF
+
+  $ HGEDITOR="sh ./editor.sh" hg amend --patch
+
+  $ hg exp
+  # HG changeset patch
+  # User test
+  # Date 0 0
+  #      Thu Jan 01 00:00:00 1970 +0000
+  # Node ID fc57c20be380f2878f4db139dad66d6cfb42ec62
+  # Parent  0000000000000000000000000000000000000000
+  added a
+  
+  diff --git a/changedfile b/changedfile
+  new file mode 100755
+  --- /dev/null
+  +++ b/changedfile
+  @@ -0,0 +1,1 @@
+  +Gello
+
+  $ hg status
+  ? editor.sh
+
+  $ ls
+  changedfile
+  editor.sh
+
+Handling both deletions and additions
+-------------------------------------
+
+  $ echo foobar > changedfile
+  $ hg ci -m "foobar to changedfile"
+  $ hg exp
+  # HG changeset patch
+  # User test
+  # Date 0 0
+  #      Thu Jan 01 00:00:00 1970 +0000
+  # Node ID 7969f70ffb81c3a6eee2d4f2f7032b694ce05349
+  # Parent  fc57c20be380f2878f4db139dad66d6cfb42ec62
+  foobar to changedfile
+  
+  diff --git a/changedfile b/changedfile
+  --- a/changedfile
+  +++ b/changedfile
+  @@ -1,1 +1,1 @@
+  -Gello
+  +foobar
+
+  $ cat > editor.sh <<EOF
+  > #!/bin/sh
+  > cat > \$1 <<ENDOF
+  > # HG changeset patch
+  > # User test
+  > # Date 0 0
+  > #      Thu Jan 01 00:00:00 1970 +0000
+  > # Node ID 7969f70ffb81c3a6eee2d4f2f7032b694ce05349
+  > # Parent  fc57c20be380f2878f4db139dad66d6cfb42ec62
+  > foobar to changedfile
+  > diff --git a/changedfile b/changedfile
+  > --- a/changedfile
+  > +++ b/changedfile
+  > @@ -1,1 +1,1 @@
+  > -Gello
+  > +foobar
+  > ENDOF
+  > EOF
+
+  $ HGEDITOR="sh ./editor.sh" hg amend --patch
+  abort: nothing changed
+  [255]
+
+Cannot change lines which are deleted
+
+  $ cat > editor.sh <<EOF
+  > #!/bin/sh
+  > cat > \$1 <<ENDOF
+  > # HG changeset patch
+  > # User test
+  > # Date 0 0
+  > #      Thu Jan 01 00:00:00 1970 +0000
+  > # Node ID 7969f70ffb81c3a6eee2d4f2f7032b694ce05349
+  > # Parent  fc57c20be380f2878f4db139dad66d6cfb42ec62
+  > foobar to changedfile
+  > diff --git a/changedfile b/changedfile
+  > --- a/changedfile
+  > +++ b/changedfile
+  > @@ -1,1 +1,1 @@
+  > -Hello
+  > +foobar
+  > ENDOF
+  > EOF
+
+  $ HGEDITOR="sh ./editor.sh" hg amend --patch
+  patching file changedfile
+  Hunk #1 FAILED at 0
+  abort: patch failed to apply
+  [255]
+
+Add more addition to the patch
+
+  $ cat > editor.sh <<EOF
+  > #!/bin/sh
+  > cat > \$1 <<ENDOF
+  > # HG changeset patch
+  > # User test
+  > # Date 0 0
+  > #      Thu Jan 01 00:00:00 1970 +0000
+  > # Node ID 7969f70ffb81c3a6eee2d4f2f7032b694ce05349
+  > # Parent  fc57c20be380f2878f4db139dad66d6cfb42ec62
+  > foobar to changedfile
+  > diff --git a/changedfile b/changedfile
+  > --- a/changedfile
+  > +++ b/changedfile
+  > @@ -1,1 +1,2 @@
+  > -Gello
+  > +foobar
+  > +babar
+  > ENDOF
+  > EOF
+
+  $ HGEDITOR="sh ./editor.sh" hg amend --patch
+
+  $ hg exp
+  # HG changeset patch
+  # User test
+  # Date 0 0
+  #      Thu Jan 01 00:00:00 1970 +0000
+  # Node ID 5d54400acb70b88f07128a1df497ed794b0b177b
+  # Parent  fc57c20be380f2878f4db139dad66d6cfb42ec62
+  foobar to changedfile
+  
+  diff --git a/changedfile b/changedfile
+  --- a/changedfile
+  +++ b/changedfile
+  @@ -1,1 +1,2 @@
+  -Gello
+  +foobar
+  +babar
+
+  $ cat changedfile
+  foobar
+  babar
+
+Introduce files which were not there
+------------------------------------
+
+  $ cat > editor.sh <<EOF
+  > #!/bin/sh
+  > cat > \$1 <<ENDOF
+  > # HG changeset patch
+  > # User test
+  > # Date 0 0
+  > #      Thu Jan 01 00:00:00 1970 +0000
+  > # Node ID 5d54400acb70b88f07128a1df497ed794b0b177b
+  > # Parent  fc57c20be380f2878f4db139dad66d6cfb42ec62
+  > foobar to changedfile
+  > diff --git a/changedfile b/changedfile
+  > --- a/changedfile
+  > +++ b/changedfile
+  > @@ -1,1 +1,2 @@
+  > -Gello
+  > +foobar
+  > +babar
+  > diff --git a/a b/a
+  > new file mode 100755
+  > --- /dev/null
+  > +++ b/a
+  > @@ -0,0 +1,1 @@
+  > +Gello
+  > ENDOF
+  > EOF
+
+  $ HGEDITOR="sh ./editor.sh" hg amend --patch
+
+  $ hg exp
+  # HG changeset patch
+  # User test
+  # Date 0 0
+  #      Thu Jan 01 00:00:00 1970 +0000
+  # Node ID c3e29c061982c94418ce141d521434d6da76cd46
+  # Parent  fc57c20be380f2878f4db139dad66d6cfb42ec62
+  foobar to changedfile
+  
+  diff --git a/a b/a
+  new file mode 100755
+  --- /dev/null
+  +++ b/a
+  @@ -0,0 +1,1 @@
+  +Gello
+  diff --git a/changedfile b/changedfile
+  --- a/changedfile
+  +++ b/changedfile
+  @@ -1,1 +1,2 @@
+  -Gello
+  +foobar
+  +babar
+
+Delete files which were not deleted in the first place
+------------------------------------------------------
+
+  $ echo Hello >> a
+  $ hg ci -m "hello to a"
+  $ hg glog
+  @  7:3d62c45a1699 hello to a
+  |   () draft
+  o  6:c3e29c061982 foobar to changedfile
+  |   () draft
+  o  3:fc57c20be380 added a
+      () draft
+
+  $ cat > editor.sh <<EOF
+  > #!/bin/sh
+  > cat > \$1 <<ENDOF
+  > # HG changeset patch
+  > # User test
+  > # Date 0 0
+  > #      Thu Jan 01 00:00:00 1970 +0000
+  > # Node ID 3d62c45a1699b11c7ecae573f013601712f2cc5f
+  > # Parent  c3e29c061982c94418ce141d521434d6da76cd46
+  > hello to a
+  > diff --git a/a b/a
+  > --- a/a
+  > +++ b/a
+  > @@ -1,1 +1,2 @@
+  >  Gello
+  > +Hello
+  > diff --git a/changedfile b/changedfile
+  > deleted file mode 100755
+  > --- a/changedfile
+  > +++ /dev/null
+  > @@ -1,2 +0,0 @@
+  > -foobar
+  > -babar
+  > ENDOF
+  > EOF
+
+  $ HGEDITOR="sh ./editor.sh" hg amend --patch
+
+  $ hg exp
+  # HG changeset patch
+  # User test
+  # Date 0 0
+  #      Thu Jan 01 00:00:00 1970 +0000
+  # Node ID c9875799c53fb862c0dbaf01500459c9397373a4
+  # Parent  c3e29c061982c94418ce141d521434d6da76cd46
+  hello to a
+  
+  diff --git a/a b/a
+  --- a/a
+  +++ b/a
+  @@ -1,1 +1,2 @@
+   Gello
+  +Hello
+  diff --git a/changedfile b/changedfile
+  deleted file mode 100755
+  --- a/changedfile
+  +++ /dev/null
+  @@ -1,2 +0,0 @@
+  -foobar
+  -babar
+
+  $ hg status
+  ? editor.sh
+
+  $ cat changedfile
+  cat: changedfile: No such file or directory
+  [1]
+
+Testing sercret phase preservation during `hg amend --patch`
+------------------------------------------------------------
+
+  $ hg phase -r . --secret --force
+
+  $ hg phase -r .
+  8: secret
+
+  $ cat > editor.sh <<EOF
+  > #!/bin/sh
+  > cat > \$1 <<ENDOF
+  > # HG changeset patch
+  > # User test
+  > # Date 0 0
+  > #      Thu Jan 01 00:00:00 1970 +0000
+  > # Node ID c9875799c53fb862c0dbaf01500459c9397373a4
+  > # Parent  c3e29c061982c94418ce141d521434d6da76cd46
+  > hello to a
+  > diff --git a/a b/a
+  > --- a/a
+  > +++ b/a
+  > @@ -1,1 +1,3 @@
+  >  Gello
+  > +Hello
+  > +mello
+  > diff --git a/changedfile b/changedfile
+  > deleted file mode 100755
+  > --- a/changedfile
+  > +++ /dev/null
+  > @@ -1,2 +0,0 @@
+  > -foobar
+  > -babar
+  > ENDOF
+  > EOF
+
+  $ HGEDITOR="sh ./editor.sh" hg amend --patch
+
+  $ hg exp
+  # HG changeset patch
+  # User test
+  # Date 0 0
+  #      Thu Jan 01 00:00:00 1970 +0000
+  # Node ID 4414485658e719a1f3d5e58bc8b2412385aa1592
+  # Parent  c3e29c061982c94418ce141d521434d6da76cd46
+  hello to a
+  
+  diff --git a/a b/a
+  --- a/a
+  +++ b/a
+  @@ -1,1 +1,3 @@
+   Gello
+  +Hello
+  +mello
+  diff --git a/changedfile b/changedfile
+  deleted file mode 100755
+  --- a/changedfile
+  +++ /dev/null
+  @@ -1,2 +0,0 @@
+  -foobar
+  -babar
+
+  $ hg phase -r .
+  9: secret
+
+Testing bookmark movement on amend --patch
+------------------------------------------
+
+  $ hg bookmark foo
+  $ hg glog
+  @  9:4414485658e7 hello to a
+  |   (foo) secret
+  o  6:c3e29c061982 foobar to changedfile
+  |   () draft
+  o  3:fc57c20be380 added a
+      () draft
+
+  $ cat > editor.sh <<EOF
+  > #!/bin/sh
+  > cat > \$1 <<ENDOF
+  > # HG changeset patch
+  > # User test
+  > # Date 0 0
+  > #      Thu Jan 01 00:00:00 1970 +0000
+  > # Node ID 4414485658e719a1f3d5e58bc8b2412385aa1592
+  > # Parent  c3e29c061982c94418ce141d521434d6da76cd46
+  > hello to a
+  > diff --git a/a b/a
+  > --- a/a
+  > +++ b/a
+  > @@ -1,1 +1,3 @@
+  >  Gello
+  > +Hello
+  > +bello
+  > diff --git a/changedfile b/changedfile
+  > deleted file mode 100755
+  > --- a/changedfile
+  > +++ /dev/null
+  > @@ -1,2 +0,0 @@
+  > -foobar
+  > -babar
+  > ENDOF
+  > EOF
+
+  $ HGEDITOR="sh ./editor.sh" hg amend --patch
+
+  $ hg exp
+  # HG changeset patch
+  # User test
+  # Date 0 0
+  #      Thu Jan 01 00:00:00 1970 +0000
+  # Node ID 36454bda1fdb8e2e4fe07bb084eef378e29cba74
+  # Parent  c3e29c061982c94418ce141d521434d6da76cd46
+  hello to a
+  
+  diff --git a/a b/a
+  --- a/a
+  +++ b/a
+  @@ -1,1 +1,3 @@
+   Gello
+  +Hello
+  +bello
+  diff --git a/changedfile b/changedfile
+  deleted file mode 100755
+  --- a/changedfile
+  +++ /dev/null
+  @@ -1,2 +0,0 @@
+  -foobar
+  -babar
+
+  $ hg glog
+  @  10:36454bda1fdb hello to a
+  |   (foo) secret
+  o  6:c3e29c061982 foobar to changedfile
+  |   () draft
+  o  3:fc57c20be380 added a
+      () draft
+
+Trying to amend --patch a public changeset
+------------------------------------------
+
+  $ hg phase -r . --public
+  $ hg glog
+  @  10:36454bda1fdb hello to a
+  |   (foo) public
+  o  6:c3e29c061982 foobar to changedfile
+  |   () public
+  o  3:fc57c20be380 added a
+      () public
+
+  $ HGEDITOR=cat hg amend --patch
+  abort: cannot amend public changesets: 36454bda1fdb
+  (see 'hg help phases' for details)
+  [255]
+
+  $ hg phase -r . --draft --force
+
+Trying on a dirty working directory
+-------------------------------------
+
+  $ echo bar > bar
+  $ hg add bar
+  $ HGEDITOR=cat hg amend --patch
+  abort: uncommitted changes
+  [255]
+
+  $ hg revert --all
+  forgetting bar
+
+Trying to pass filenames, only mentioned file names should be popped up in
+editor and rest should stay in the commit as they were
+--------------------------------------------------------------------------
+
+Checking the we pop-up with the files which were mentioned
+
+  $ HGEDITOR=cat hg amend --patch changedfile
+  # HG changeset patch
+  # User test
+  # Date 0 0
+  #      Thu Jan 01 00:00:00 1970 +0000
+  # Node ID 36454bda1fdb8e2e4fe07bb084eef378e29cba74
+  # Parent  c3e29c061982c94418ce141d521434d6da76cd46
+  hello to a
+  
+  diff --git a/changedfile b/changedfile
+  deleted file mode 100755
+  --- a/changedfile
+  +++ /dev/null
+  @@ -1,2 +0,0 @@
+  -foobar
+  -babar
+  abort: nothing changed
+  [255]
+
+  $ HGEDITOR=cat hg amend --patch a
+  # HG changeset patch
+  # User test
+  # Date 0 0
+  #      Thu Jan 01 00:00:00 1970 +0000
+  # Node ID 36454bda1fdb8e2e4fe07bb084eef378e29cba74
+  # Parent  c3e29c061982c94418ce141d521434d6da76cd46
+  hello to a
+  
+  diff --git a/a b/a
+  --- a/a
+  +++ b/a
+  @@ -1,1 +1,3 @@
+   Gello
+  +Hello
+  +bello
+  abort: nothing changed
+  [255]
+
+  $ HGEDITOR=cat hg amend --patch changedfile a
+  # HG changeset patch
+  # User test
+  # Date 0 0
+  #      Thu Jan 01 00:00:00 1970 +0000
+  # Node ID 36454bda1fdb8e2e4fe07bb084eef378e29cba74
+  # Parent  c3e29c061982c94418ce141d521434d6da76cd46
+  hello to a
+  
+  diff --git a/a b/a
+  --- a/a
+  +++ b/a
+  @@ -1,1 +1,3 @@
+   Gello
+  +Hello
+  +bello
+  diff --git a/changedfile b/changedfile
+  deleted file mode 100755
+  --- a/changedfile
+  +++ /dev/null
+  @@ -1,2 +0,0 @@
+  -foobar
+  -babar
+  abort: nothing changed
+  [255]
+
+  $ HGEDITOR=cat hg amend --patch doesnotexists
+  # HG changeset patch
+  # User test
+  # Date 0 0
+  #      Thu Jan 01 00:00:00 1970 +0000
+  # Node ID 36454bda1fdb8e2e4fe07bb084eef378e29cba74
+  # Parent  c3e29c061982c94418ce141d521434d6da76cd46
+  hello to a
+  
+  abort: nothing changed
+  [255]
+
+Changing only one file
+  $ cat > editor.sh <<EOF
+  > #!/bin/sh
+  > cat > \$1 <<ENDOF
+  > # HG changeset patch
+  > # User test
+  > # Date 0 0
+  > #      Thu Jan 01 00:00:00 1970 +0000
+  > # Node ID 36454bda1fdb8e2e4fe07bb084eef378e29cba74
+  > # Parent  c3e29c061982c94418ce141d521434d6da76cd46
+  > hello to a
+  > diff --git a/a b/a
+  > --- a/a
+  > +++ b/a
+  > @@ -1,1 +1,3 @@
+  >  Gello
+  > +Hello
+  > +betto
+  > ENDOF
+  > EOF
+
+  $ HGEDITOR="sh ./editor.sh" hg amend --patch a
+
+file 'a' should be amended, rest of them should remain unchanged
+
+  $ hg exp
+  # HG changeset patch
+  # User test
+  # Date 0 0
+  #      Thu Jan 01 00:00:00 1970 +0000
+  # Node ID ea175dcc4ee38c106db157975e006b4092444c65
+  # Parent  c3e29c061982c94418ce141d521434d6da76cd46
+  hello to a
+  
+  diff --git a/a b/a
+  --- a/a
+  +++ b/a
+  @@ -1,1 +1,3 @@
+   Gello
+  +Hello
+  +betto
+  diff --git a/changedfile b/changedfile
+  deleted file mode 100755
+  --- a/changedfile
+  +++ /dev/null
+  @@ -1,2 +0,0 @@
+  -foobar
+  -babar
+
+  $ hg status
+  ? bar
+  ? editor.sh
+
+  $ hg diff
+
+Testing again with file 'changedfile'
+
+  $ cat > editor.sh <<EOF
+  > #!/bin/sh
+  > cat > \$1 <<ENDOF
+  > # HG changeset patch
+  > # User test
+  > # Date 0 0
+  > #      Thu Jan 01 00:00:00 1970 +0000
+  > # Node ID ea175dcc4ee38c106db157975e006b4092444c65
+  > # Parent  c3e29c061982c94418ce141d521434d6da76cd46
+  > hello to a
+  > diff --git a/changedfile b/changedfile
+  > --- a/changedfile
+  > +++ b/changedfile
+  > @@ -1,2 +1,1 @@
+  >  foobar
+  > -babar
+  > ENDOF
+  > EOF
+
+  $ HGEDITOR="sh ./editor.sh" hg amend --patch changedfile
+
+  $ hg exp
+  # HG changeset patch
+  # User test
+  # Date 0 0
+  #      Thu Jan 01 00:00:00 1970 +0000
+  # Node ID 0e64d76c3519308c398a28192cb095d48b29aede
+  # Parent  c3e29c061982c94418ce141d521434d6da76cd46
+  hello to a
+  
+  diff --git a/a b/a
+  --- a/a
+  +++ b/a
+  @@ -1,1 +1,3 @@
+   Gello
+  +Hello
+  +betto
+  diff --git a/changedfile b/changedfile
+  --- a/changedfile
+  +++ b/changedfile
+  @@ -1,2 +1,1 @@
+   foobar
+  -babar
+
+  $ hg diff
+  $ hg status
+  ? bar
+  ? editor.sh
+
+Dropping a file from commit by removing related hunks
+------------------------------------------------------
+
+  $ cat > editor.sh <<EOF
+  > #!/bin/sh
+  > cat > \$1 <<ENDOF
+  > # HG changeset patch
+  > # User test
+  > # Date 0 0
+  > #      Thu Jan 01 00:00:00 1970 +0000
+  > # Node ID 0e64d76c3519308c398a28192cb095d48b29aede
+  > # Parent  c3e29c061982c94418ce141d521434d6da76cd46
+  > hello to a
+  > diff --git a/a b/a
+  > --- a/a
+  > +++ b/a
+  > @@ -1,1 +1,3 @@
+  >  Gello
+  > +Kello
+  > +betto
+  > ENDOF
+  > EOF
+
+  $ HGEDITOR="sh ./editor.sh" hg amend --patch
+
+  $ hg exp
+  # HG changeset patch
+  # User test
+  # Date 0 0
+  #      Thu Jan 01 00:00:00 1970 +0000
+  # Node ID 944e9f65fa55fdb2de98577c9d8ab30de0927d8e
+  # Parent  c3e29c061982c94418ce141d521434d6da76cd46
+  hello to a
+  
+  diff --git a/a b/a
+  --- a/a
+  +++ b/a
+  @@ -1,1 +1,3 @@
+   Gello
+  +Kello
+  +betto
+
+The part which was dropped from the patch will not be there in working directory
+too
+  $ hg diff
+
+  $ hg status
+  ? bar
+  ? editor.sh
+
+Changing metadata of a patch by editing patch content
+======================================================
+
+Changing user
+-------------
+
+  $ cat > editor.sh <<EOF
+  > #!/bin/sh
+  > cat > \$1 <<ENDOF
+  > # HG changeset patch
+  > # User RandomUser
+  > # Date 0 0
+  > #      Thu Jan 01 00:00:00 1970 +0000
+  > # Node ID 944e9f65fa55fdb2de98577c9d8ab30de0927d8e
+  > # Parent  c3e29c061982c94418ce141d521434d6da76cd46
+  > hello to a
+  > diff --git a/a b/a
+  > --- a/a
+  > +++ b/a
+  > @@ -1,1 +1,3 @@
+  >  Gello
+  > +Kello
+  > +betto
+  > ENDOF
+  > EOF
+
+  $ HGEDITOR="sh ./editor.sh" hg amend --patch
+
+  $ hg exp
+  # HG changeset patch
+  # User RandomUser
+  # Date 0 0
+  #      Thu Jan 01 00:00:00 1970 +0000
+  # Node ID 5ded18a8c333a55da4b0e051162457cfe5d85558
+  # Parent  c3e29c061982c94418ce141d521434d6da76cd46
+  hello to a
+  
+  diff --git a/a b/a
+  --- a/a
+  +++ b/a
+  @@ -1,1 +1,3 @@
+   Gello
+  +Kello
+  +betto
+
+Changing Date
+-------------
+
+  $ cat > editor.sh <<EOF
+  > #!/bin/sh
+  > cat > \$1 <<ENDOF
+  > # HG changeset patch
+  > # User RandomUser
+  > # Date 123456 1200
+  > #      Thu Jan 01 00:00:00 1970 +0000
+  > # Node ID 944e9f65fa55fdb2de98577c9d8ab30de0927d8e
+  > # Parent  c3e29c061982c94418ce141d521434d6da76cd46
+  > hello to a
+  > diff --git a/a b/a
+  > --- a/a
+  > +++ b/a
+  > @@ -1,1 +1,3 @@
+  >  Gello
+  > +Kello
+  > +betto
+  > ENDOF
+  > EOF
+
+  $ HGEDITOR="sh ./editor.sh" hg amend --patch
+
+  $ hg exp
+  # HG changeset patch
+  # User RandomUser
+  # Date 123456 1200
+  #      Fri Jan 02 09:57:36 1970 -0020
+  # Node ID e2312ddcd8756665075a60bd05431ddca3c45050
+  # Parent  c3e29c061982c94418ce141d521434d6da76cd46
+  hello to a
+  
+  diff --git a/a b/a
+  --- a/a
+  +++ b/a
+  @@ -1,1 +1,3 @@
+   Gello
+  +Kello
+  +betto
+
+Changing branch
+---------------
+
+  $ cat > editor.sh <<EOF
+  > #!/bin/sh
+  > cat > \$1 <<ENDOF
+  > # HG changeset patch
+  > # User RandomUser
+  > # Date 123456 1200
+  > #      Thu Jan 01 00:00:00 1970 +0000
+  > # Branch stable
+  > # Node ID 944e9f65fa55fdb2de98577c9d8ab30de0927d8e
+  > # Parent  c3e29c061982c94418ce141d521434d6da76cd46
+  > hello to a
+  > diff --git a/a b/a
+  > --- a/a
+  > +++ b/a
+  > @@ -1,1 +1,3 @@
+  >  Gello
+  > +Kello
+  > +betto
+  > ENDOF
+  > EOF
+
+  $ HGEDITOR="sh ./editor.sh" hg amend --patch
+
+  $ hg exp
+  # HG changeset patch
+  # User RandomUser
+  # Date 123456 1200
+  #      Fri Jan 02 09:57:36 1970 -0020
+  # Branch stable
+  # Node ID ddc61a4058687b2dd4a316f4b5fe7d52a35b702a
+  # Parent  c3e29c061982c94418ce141d521434d6da76cd46
+  hello to a
+  
+  diff --git a/a b/a
+  --- a/a
+  +++ b/a
+  @@ -1,1 +1,3 @@
+   Gello
+  +Kello
+  +betto
+
+Changing parent (this should be fun)
+------------------------------------
+
+  $ hg glog
+  @  16:ddc61a405868 hello to a
+  |   (foo) draft
+  o  6:c3e29c061982 foobar to changedfile
+  |   () public
+  o  3:fc57c20be380 added a
+      () public
+
+  $ hg log -r .^^ -T '{node}'
+  fc57c20be380f2878f4db139dad66d6cfb42ec62 (no-eol)
+
+  $ cat > editor.sh <<EOF
+  > #!/bin/sh
+  > cat > \$1 <<ENDOF
+  > # HG changeset patch
+  > # User RandomUser
+  > # Date 123456 1200
+  > #      Thu Jan 01 00:00:00 1970 +0000
+  > # Branch stable
+  > # Node ID 944e9f65fa55fdb2de98577c9d8ab30de0927d8e
+  > # Parent  fc57c20be380f2878f4db139dad66d6cfb42ec62
+  > hello to a
+  > diff --git a/a b/a
+  > --- a/a
+  > +++ b/a
+  > @@ -1,1 +1,3 @@
+  >  Gello
+  > +Kello
+  > +betto
+  > ENDOF
+  > EOF
+
+  $ HGEDITOR="sh ./editor.sh" hg amend --patch
+
+  $ hg exp
+  # HG changeset patch
+  # User RandomUser
+  # Date 123456 1200
+  #      Fri Jan 02 09:57:36 1970 -0020
+  # Branch stable
+  # Node ID b763f7cb2302f2efa1275e2a9202655872c9567f
+  # Parent  fc57c20be380f2878f4db139dad66d6cfb42ec62
+  hello to a
+  
+  diff --git a/a b/a
+  new file mode 100755
+  --- /dev/null
+  +++ b/a
+  @@ -0,0 +1,3 @@
+  +Gello
+  +Kello
+  +betto
+
+  $ hg glog
+  @  17:b763f7cb2302 hello to a
+  |   (foo) draft
+  | o  6:c3e29c061982 foobar to changedfile
+  |/    () public
+  o  3:fc57c20be380 added a
+      () public
+
+Changing the commit desciption
+-------------------------------
+
+  $ cat > editor.sh <<EOF
+  > #!/bin/sh
+  > cat > \$1 <<ENDOF
+  > # HG changeset patch
+  > # User RandomUser
+  > # Date 123456 1200
+  > #      Thu Jan 01 00:00:00 1970 +0000
+  > # Branch stable
+  > # Node ID 944e9f65fa55fdb2de98577c9d8ab30de0927d8e
+  > # Parent  fc57c20be380f2878f4db139dad66d6cfb42ec62
+  > I am a message which is testing change of message
+  > diff --git a/a b/a
+  > new file mode 100755
+  > --- /dev/null
+  > +++ b/a
+  > @@ -0,0 +1,3 @@
+  > +Gello
+  > +Kello
+  > +betto
+  > ENDOF
+  > EOF
+
+  $ HGEDITOR="sh ./editor.sh" hg amend --patch
+
+  $ hg exp
+  # HG changeset patch
+  # User RandomUser
+  # Date 123456 1200
+  #      Fri Jan 02 09:57:36 1970 -0020
+  # Branch stable
+  # Node ID f14ecd7121e63915ac93edbad7f60f605e62dd52
+  # Parent  fc57c20be380f2878f4db139dad66d6cfb42ec62
+  I am a message which is testing change of message
+  
+  diff --git a/a b/a
+  new file mode 100755
+  --- /dev/null
+  +++ b/a
+  @@ -0,0 +1,3 @@
+  +Gello
+  +Kello
+  +betto
+
+Changing the Node ID of the patch
+---------------------------------
+
+Nothing happens in that case we dont care about the node ID. Look the above 3-4
+tests to realize I was testing that too.
--- a/tests/test-amend.t	Thu Apr 12 13:30:28 2018 +0800
+++ b/tests/test-amend.t	Sun Mar 18 23:48:06 2018 +0530
@@ -149,6 +149,7 @@
    -a --all                 match all files
    -e --edit                invoke editor on commit messages
       --extract             extract changes from the commit to the working copy
+      --patch               make changes to wdir parent by editing patch
       --close-branch        mark a branch as closed, hiding it from the branch
                             list
    -s --secret              use the secret phase for committing