Patchwork [5,of,5,evolve-ext] prune: add --keep to not touch the working copy

login
register
mail settings
Submitter Durham Goode
Date March 20, 2015, 1:14 a.m.
Message ID <811a7345955e540045d5.1426814070@dev2000.prn2.facebook.com>
Download mbox | patch
Permalink /patch/8193/
State Accepted
Headers show

Comments

Durham Goode - March 20, 2015, 1:14 a.m.
# HG changeset patch
# User Durham Goode <durham@fb.com>
# Date 1426787762 25200
#      Thu Mar 19 10:56:02 2015 -0700
# Node ID 811a7345955e540045d57ed5698db0f12c27f36e
# Parent  e93100523ef10fae3fcee2bdeac0f676ed842ecd
prune: add --keep to not touch the working copy

In order to more closely emulate strip, lets add --keep to leave the working
copy untouched when we do our prune.
Jordi Gutiérrez Hermoso - March 20, 2015, 1:37 p.m.
On Thu, 2015-03-19 at 18:14 -0700, Durham Goode wrote:
> # HG changeset patch
> # User Durham Goode <durham@fb.com>
> # Date 1426787762 25200
> #      Thu Mar 19 10:56:02 2015 -0700
> # Node ID 811a7345955e540045d57ed5698db0f12c27f36e
> # Parent  e93100523ef10fae3fcee2bdeac0f676ed842ecd
> prune: add --keep to not touch the working copy
> 
> In order to more closely emulate strip, lets add --keep to leave the working
> copy untouched when we do our prune.

We already have uncommit. I think it makes more sense to keep this as
two separate commands than trying to emulate the strip UI. Perhaps
give hints on how to alias uncommit + prune into a single verb.

Smaller, modular verbs instead of stuffing all the funcionality into a
single verb.
Sean Farley - March 20, 2015, 4:27 p.m.
Jordi Gutiérrez Hermoso <jordigh@octave.org> writes:

> On Thu, 2015-03-19 at 18:14 -0700, Durham Goode wrote:
>> # HG changeset patch
>> # User Durham Goode <durham@fb.com>
>> # Date 1426787762 25200
>> #      Thu Mar 19 10:56:02 2015 -0700
>> # Node ID 811a7345955e540045d57ed5698db0f12c27f36e
>> # Parent  e93100523ef10fae3fcee2bdeac0f676ed842ecd
>> prune: add --keep to not touch the working copy
>> 
>> In order to more closely emulate strip, lets add --keep to leave the working
>> copy untouched when we do our prune.
>
> We already have uncommit. I think it makes more sense to keep this as
> two separate commands than trying to emulate the strip UI. Perhaps
> give hints on how to alias uncommit + prune into a single verb.

Actually, I've been wanting this flag for a while. Currently, if you
uncommit everything you're still left with a changeset.
Jordi Gutiérrez Hermoso - March 20, 2015, 4:51 p.m.
On Fri, 2015-03-20 at 09:27 -0700, Sean Farley wrote:
> Currently, if you uncommit everything you're still left with a
> changeset.

Yeah. I think it might make more sense to change *that* default. If
you really want to get the commit message of the empty cset, you can
always fetch that from the "garbage" (the obsolete commit).
Pierre-Yves David - March 20, 2015, 7:46 p.m.
On 03/20/2015 09:51 AM, Jordi Gutiérrez Hermoso wrote:
> On Fri, 2015-03-20 at 09:27 -0700, Sean Farley wrote:
>> Currently, if you uncommit everything you're still left with a
>> changeset.
>
> Yeah. I think it might make more sense to change *that* default. If
> you really want to get the commit message of the empty cset, you can
> always fetch that from the "garbage" (the obsolete commit).

That default is here to make it easier to preserve meta data and ensure 
the obsolescence chain stay true. This is especially needed now, as the 
lack of `hg uncommit --interactive` make `hg uncommit --all` much more 
frequent than necessary.
Pierre-Yves David - March 20, 2015, 7:49 p.m.
On 03/20/2015 06:37 AM, Jordi Gutiérrez Hermoso wrote:
> On Thu, 2015-03-19 at 18:14 -0700, Durham Goode wrote:
>> # HG changeset patch
>> # User Durham Goode <durham@fb.com>
>> # Date 1426787762 25200
>> #      Thu Mar 19 10:56:02 2015 -0700
>> # Node ID 811a7345955e540045d57ed5698db0f12c27f36e
>> # Parent  e93100523ef10fae3fcee2bdeac0f676ed842ecd
>> prune: add --keep to not touch the working copy
>>
>> In order to more closely emulate strip, lets add --keep to leave the working
>> copy untouched when we do our prune.
>
> We already have uncommit. I think it makes more sense to keep this as
> two separate commands than trying to emulate the strip UI. Perhaps
> give hints on how to alias uncommit + prune into a single verb.

uncommit focus on the working directory parent, hg prune lets your swip 
a whole stack of changeset in one go.

Experimenting with `hg prune --keep` sound like a good things to do.

Patch

diff --git a/hgext/evolve.py b/hgext/evolve.py
--- a/hgext/evolve.py
+++ b/hgext/evolve.py
@@ -1742,6 +1742,7 @@  def _getmetadata(**opts):
      ('s', 'succ', [], _("successor changeset")),
      ('r', 'rev', [], _("revisions to prune")),
      ('', 'descendants', None, _("prunes descendants of the revs as well")),
+     ('k', 'keep', None, _("does not modify working copy during prune")),
      ('', 'biject', False, _("do a 1-1 map between rev and successor ranges")),
      ('B', 'bookmark', '', _("remove revs only reachable from given"
                              " bookmark"))] + metadataopts,
@@ -1838,8 +1839,28 @@  def cmdprune(ui, repo, *revs, **opts):
                 newnode = newnode.parents()[0]
 
         if newnode.node() != wdp.node():
-            commands.update(ui, repo, newnode.rev())
-            ui.status(_('working directory now at %s\n') % newnode)
+            if opts.get('keep', False):
+                # This is largely the same as the implementation in
+                # strip.stripcmd(). We might want to refactor this somewhere
+                # common at some point.
+
+                # only reset the dirstate for files that would actually change
+                # between the working context and uctx
+                descendantrevs = repo.revs("%s::." % newnode.rev())
+                changedfiles = []
+                for rev in descendantrevs:
+                    # blindly reset the files, regardless of what actually changed
+                    changedfiles.extend(repo[rev].files())
+
+                # reset files that only changed in the dirstate too
+                dirstate = repo.dirstate
+                dirchanges = [f for f in dirstate if dirstate[f] != 'n']
+                changedfiles.extend(dirchanges)
+                repo.dirstate.rebuild(newnode.node(), newnode.manifest(), changedfiles)
+                repo.dirstate.write()
+            else:
+                commands.update(ui, repo, newnode.rev())
+                ui.status(_('working directory now at %s\n') % newnode)
         # update bookmarks
         if bookmark:
             _deletebookmark(ui, marks, bookmark)
diff --git a/tests/test-prune.t b/tests/test-prune.t
--- a/tests/test-prune.t
+++ b/tests/test-prune.t
@@ -252,6 +252,19 @@  test hg strip replacement
   0 files updated, 0 files merged, 1 files removed, 0 files unresolved
   saved backup bundle to $TESTTMP/repo/.hg/strip-backup/c7e58696a948-69ca36d3-backup.hg
 
+test hg prune --keep
+  $ mkcommit n1
+  $ hg diff -r .^
+  diff -r aa96dc3f04c2 n1
+  --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+  +++ b/n1	* +0000 (glob)
+  @@ -0,0 +1,1 @@
+  +n1
+  $ hg prune -r . --keep
+  1 changesets pruned
+  $ hg status
+  ? n1
+
 test hg prune -B bookmark
 yoinked from test-mq-strip.t