D821: unamend: move fb extension unamend to core
pulkit (Pulkit Goyal)
phabricator at mercurial-scm.org
Wed Sep 27 13:33:00 EDT 2017
pulkit updated this revision to Diff 2128.
REPOSITORY
rHG Mercurial
CHANGES SINCE LAST UPDATE
https://phab.mercurial-scm.org/D821?vs=2092&id=2128
REVISION DETAIL
https://phab.mercurial-scm.org/D821
AFFECTED FILES
hgext/uncommit.py
tests/test-unamend.t
CHANGE DETAILS
diff --git a/tests/test-unamend.t b/tests/test-unamend.t
new file mode 100644
--- /dev/null
+++ b/tests/test-unamend.t
@@ -0,0 +1,289 @@
+Test for command `hg unamend` which lives in uncommit extension
+===============================================================
+
+ $ cat >> $HGRCPATH << EOF
+ > [alias]
+ > glog = log -G -T '{rev}:{node|short} {desc}'
+ > [experimental]
+ > evolution = createmarkers, allowunstable
+ > [extensions]
+ > rebase =
+ > amend =
+ > uncommit =
+ > EOF
+
+Repo Setup
+---------
+
+ $ hg init repo
+ $ cd repo
+ $ for ch in {a..h}; do touch $ch; echo "foo" >> $ch; hg ci -Aqm "Added "$ch; done
+
+ $ hg glog
+ @ 7:ec2426147f0e Added h
+ |
+ o 6:87d6d6676308 Added g
+ |
+ o 5:825660c69f0c Added f
+ |
+ o 4:aa98ab95a928 Added e
+ |
+ o 3:62615734edd5 Added d
+ |
+ o 2:28ad74487de9 Added c
+ |
+ o 1:29becc82797a Added b
+ |
+ o 0:18d04c59bb5d Added a
+
+
+Trying to unamend when there was no amend done
+----------------------------------------------
+
+ $ hg unamend
+ abort: changeset must have one predecessor, found 0 predecessors
+ [255]
+
+Unamend on clean wdir and tip
+------------------------------
+
+ $ echo "bar" >> h
+ $ hg amend
+
+ $ hg exp
+ # HG changeset patch
+ # User test
+ # Date 0 0
+ # Thu Jan 01 00:00:00 1970 +0000
+ # Node ID c9fa1a715c1b7661c0fafb362a9f30bd75878d7d
+ # Parent 87d6d66763085b629e6d7ed56778c79827273022
+ Added h
+
+ diff -r 87d6d6676308 -r c9fa1a715c1b h
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/h Thu Jan 01 00:00:00 1970 +0000
+ @@ -0,0 +1,2 @@
+ +foo
+ +bar
+
+ $ hg glog --hidden
+ @ 8:c9fa1a715c1b Added h
+ |
+ | x 7:ec2426147f0e Added h
+ |/
+ o 6:87d6d6676308 Added g
+ |
+ o 5:825660c69f0c Added f
+ |
+ o 4:aa98ab95a928 Added e
+ |
+ o 3:62615734edd5 Added d
+ |
+ o 2:28ad74487de9 Added c
+ |
+ o 1:29becc82797a Added b
+ |
+ o 0:18d04c59bb5d Added a
+
+ $ hg unamend
+ $ hg glog --hidden
+ @ 9:8da14a1fd653 Added h
+ |
+ | x 8:c9fa1a715c1b Added h
+ |/
+ | x 7:ec2426147f0e Added h
+ |/
+ o 6:87d6d6676308 Added g
+ |
+ o 5:825660c69f0c Added f
+ |
+ o 4:aa98ab95a928 Added e
+ |
+ o 3:62615734edd5 Added d
+ |
+ o 2:28ad74487de9 Added c
+ |
+ o 1:29becc82797a Added b
+ |
+ o 0:18d04c59bb5d Added a
+
+ $ hg diff
+ diff -r 8da14a1fd653 h
+ --- a/h Thu Jan 01 00:00:00 1970 +0000
+ +++ b/h Thu Jan 01 00:00:00 1970 +0000
+ @@ -1,1 +1,2 @@
+ foo
+ +bar
+
+ $ hg exp
+ # HG changeset patch
+ # User test
+ # Date 0 0
+ # Thu Jan 01 00:00:00 1970 +0000
+ # Node ID 8da14a1fd653c3f07fdad5760511c9e12652a306
+ # Parent 87d6d66763085b629e6d7ed56778c79827273022
+ Added h
+
+ diff -r 87d6d6676308 -r 8da14a1fd653 h
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/h Thu Jan 01 00:00:00 1970 +0000
+ @@ -0,0 +1,1 @@
+ +foo
+
+ $ hg status
+ M h
+
+ $ hg log -r . -T '{extras % "{extra}\n"}' --config alias.log=log
+ branch=default
+ unamend_source=\xc9\xfa\x1aq\\\x1bva\xc0\xfa\xfb6*\x9f0\xbdu\x87\x8d}
+
+Unamend on a dirty working directory
+------------------------------------
+
+ $ hg ci -m "Added bar to h"
+ $ echo "bar" >> a
+ $ hg amend
+ $ echo "foobar" >> a
+ $ echo "bar" >> b
+ $ hg status
+ M a
+ M b
+
+ $ hg unamend
+
+ $ hg status
+ M a
+ M b
+
+ $ hg diff
+ diff -r 49f03646f7a0 a
+ --- a/a Thu Jan 01 00:00:00 1970 +0000
+ +++ b/a Thu Jan 01 00:00:00 1970 +0000
+ @@ -1,1 +1,3 @@
+ foo
+ +bar
+ +foobar
+ diff -r 49f03646f7a0 b
+ --- a/b Thu Jan 01 00:00:00 1970 +0000
+ +++ b/b Thu Jan 01 00:00:00 1970 +0000
+ @@ -1,1 +1,2 @@
+ foo
+ +bar
+
+Unamending an added file
+------------------------
+
+ $ hg ci -m "Added things to a and b"
+ $ echo foo > bar
+ $ hg add bar
+ $ hg amend
+
+ $ hg unamend
+ $ hg status
+ A bar
+
+ $ hg revert --all
+ forgetting bar
+
+Unamending a removed file
+-------------------------
+
+ $ hg remove a
+ $ hg amend
+
+ $ hg unamend
+ $ hg status
+ R a
+ ? bar
+
+ $ hg revert --all
+ undeleting a
+
+Unamending an added file with dirty wdir status
+-----------------------------------------------
+
+ $ hg add bar
+ $ hg amend
+ $ echo bar >> bar
+ $ hg status
+ M bar
+
+ $ hg unamend
+ $ hg status
+ A bar
+ $ hg diff
+ diff -r 738d71740456 bar
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/bar Thu Jan 01 00:00:00 1970 +0000
+ @@ -0,0 +1,2 @@
+ +foo
+ +bar
+
+ $ hg revert --all
+ forgetting bar
+
+Unamending in middle of a stack
+-------------------------------
+
+ $ hg glog
+ @ 19:738d71740456 Added things to a and b
+ |
+ o 12:49f03646f7a0 Added bar to h
+ |
+ o 9:8da14a1fd653 Added h
+ |
+ o 6:87d6d6676308 Added g
+ |
+ o 5:825660c69f0c Added f
+ |
+ o 4:aa98ab95a928 Added e
+ |
+ o 3:62615734edd5 Added d
+ |
+ o 2:28ad74487de9 Added c
+ |
+ o 1:29becc82797a Added b
+ |
+ o 0:18d04c59bb5d Added a
+
+ $ hg up 5
+ 2 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ echo bar >> f
+ $ hg amend
+ $ hg rebase -s 6 -d . -q
+
+ $ hg glog
+ o 24:947f189a0dfc Added things to a and b
+ |
+ o 23:8c216e653148 Added bar to h
+ |
+ o 22:533b8ea407b4 Added h
+ |
+ o 21:49635b68477e Added g
+ |
+ @ 20:93f0e8ffab32 Added f
+ |
+ o 4:aa98ab95a928 Added e
+ |
+ o 3:62615734edd5 Added d
+ |
+ o 2:28ad74487de9 Added c
+ |
+ o 1:29becc82797a Added b
+ |
+ o 0:18d04c59bb5d Added a
+
+
+ $ hg unamend
+ abort: cannot unamend in the middle of a stack
+ [255]
+
+Trying to unamend a public changeset
+------------------------------------
+
+ $ hg up
+ 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg phase -r . -p
+ $ hg unamend
+ abort: cannot unamend public changesets
+ [255]
diff --git a/hgext/uncommit.py b/hgext/uncommit.py
--- a/hgext/uncommit.py
+++ b/hgext/uncommit.py
@@ -29,6 +29,7 @@
error,
node,
obsolete,
+ obsutil,
registrar,
scmutil,
)
@@ -185,3 +186,85 @@
with repo.dirstate.parentchange():
repo.dirstate.setparents(newid, node.nullid)
_uncommitdirstate(repo, old, match)
+
+def predecessormarkers(ctx):
+ """yields the obsolete markers marking the given changeset as a successor"""
+ for data in ctx.repo().obsstore.predecessors.get(ctx.node(), ()):
+ yield obsutil.marker(ctx.repo(), data)
+
+ at command('^unamend', [])
+def unamend(ui, repo, **opts):
+ """undo the amend operation on a current changeset
+
+ This command will roll back to the previous version of a changeset,
+ leaving working directory in state in which it was before running
+ `hg amend` (e.g. files modified as part of an amend will be
+ marked as modified `hg status`)"""
+
+ unfi = repo.unfiltered()
+
+ # identify the commit from which to unamend
+ curctx = repo['.']
+
+ if not curctx.mutable():
+ raise error.Abort(_('cannot unamend public changesets'))
+
+ # identify the commit to which to unamend
+ markers = list(predecessormarkers(curctx))
+ if len(markers) != 1:
+ e = _("changeset must have one predecessor, found %i predecessors")
+ raise error.Abort(e % len(markers))
+
+ prednode = markers[0].prednode()
+ predctx = unfi[prednode]
+
+ if curctx.children():
+ raise error.Abort(_("cannot unamend in the middle of a stack"))
+
+ with repo.wlock(), repo.lock(), repo.transaction('unamend'):
+ # add an extra so that we get a new hash
+ extras = predctx.extra()
+ extras['unamend_source'] = curctx.node()
+
+ def filectxfn(repo, ctx_, path):
+ try:
+ return predctx.filectx(path)
+ except KeyError:
+ return None
+
+ # Make a new commit same as predctx
+ newctx = context.memctx(repo,
+ parents=(predctx.p1(), predctx.p2()),
+ text=predctx.description(),
+ files=predctx.files(),
+ filectxfn=filectxfn,
+ user=predctx.user(),
+ date=predctx.date(),
+ extra=extras)
+ # phase handling
+ commitphase = curctx.phase()
+ overrides = {('phases', 'new-commit'): commitphase}
+ with repo.ui.configoverride(overrides, 'uncommit'):
+ newprednode = repo.commitctx(newctx)
+
+ newpredctx = repo[newprednode]
+
+ changedfiles = []
+ wctx = repo[None]
+ wm = wctx.manifest()
+ cm = newpredctx.manifest()
+ dirstate = repo.dirstate
+ diff = cm.diff(wm)
+ changedfiles.extend(diff.iterkeys())
+
+ with dirstate.parentchange():
+ dirstate.rebuild(newprednode, cm, changedfiles)
+ # we want added and removed files to be shown
+ # properly, not with ? and ! prefixes
+ for filename, data in diff.iteritems():
+ if data[0][0] is None:
+ dirstate.add(filename)
+ if data[1][0] is None:
+ dirstate.remove(filename)
+ mapping = {curctx.node(): (newprednode,)}
+ scmutil.cleanupnodes(repo, mapping, 'unamend')
To: pulkit, #hg-reviewers, durham
Cc: durham, mercurial-devel
More information about the Mercurial-devel
mailing list