changeset 269:6c6bb7a23bb5 0.1.0

stabilize: improve unstable selection heuristic Without argument, stabilize was picking the first in: "unstable() and ((suspended() or obsancestors(::.))::)" which usually returned the "oldest" unstable revision in parent predecessors descendants. This revision is interesting because it usually gives "soft" merges but rebasing it left the working directory on a remote branch, which was very confusing. The new heuristic picks an unstable changeset which can be rebased on top of the parent revision, or on top of one of its descendants (selected in revision order). This has the advantage of selecting a revision which can be rebased on the current subtree, and leave the working directory in a more convenient location.
author Patrick Mezard <patrick@mezard.eu>
date Wed, 13 Jun 2012 18:28:10 +0200
parents 2da5af3dadeb
children a68b763505c2 04823ea70d15
files hgext/evolve.py tests/test-evolve.t tests/test-stabilize-order.t
diffstat 3 files changed, 195 insertions(+), 28 deletions(-) [+]
line wrap: on
line diff
--- a/hgext/evolve.py	Tue Jun 12 15:33:23 2012 +0200
+++ b/hgext/evolve.py	Wed Jun 13 18:28:10 2012 +0200
@@ -195,6 +195,24 @@
         raise
 
 
+def stabilizableunstable(repo, pctx):
+    """Return a changectx for an unstable changeset which can be
+    stabilized on top of pctx or one of its descendants. None if none
+    can be found.
+    """
+    def selfanddescendants(repo, pctx):
+        yield pctx
+        for ctx in pctx.descendants():
+            yield ctx
+
+    # Look for an unstable which can be stabilized as a child of
+    # node. The unstable must be a child of one of node predecessors.
+    for ctx in selfanddescendants(repo, pctx):
+        unstables = list(repo.set('unstable() and children(obsancestors(%d))',
+                                  ctx.rev()))
+        if unstables:
+            return unstables[0]
+    return None
 
 ### new command
 #############################
@@ -208,30 +226,34 @@
     ],
     '')
 def stabilize(ui, repo, **opts):
-    """move changeset out of the unstable state
+    """rebase an unstable changeset to make it stable again
 
-    By default only works on changeset that will be rebase on ancestors of the
-    current working directory parent (included)"""
+    By default, take the first unstable changeset which could be
+    rebased as child of the working directory parent revision or one
+    of its descendants and rebase it.
+
+    With --any, stabilize any unstable changeset.
+
+    The working directory is updated to the rebased revision.
+    """
 
     obsolete = extensions.find('obsolete')
 
-    if opts['any']:
-        rvstargets = 'unstable()'
-    else:
-        rvstargets = 'unstable() and ((suspended() and obsancestors(::.))::)'
-
-    unstable = list(repo.set(rvstargets))
-    if not unstable:
-        unstable = opts['any'] and () or list(repo.set('unstable()'))
-        if unstable:
+    node = None
+    if not opts['any']:
+        node = stabilizableunstable(repo, repo['.'])
+    if node is None:
+        unstables = list(repo.set('unstable()'))
+        if unstables and not opts['any']:
             ui.write_err(_('nothing to stabilize here\n'))
             ui.status(_('(%i unstable changesets, do you want --any ?)\n')
-                      % len(unstable))
+                      % len(unstables))
             return 2
-        else:
+        elif not unstables:
             ui.write_err(_('no unstable changeset\n'))
             return 1
-    node = unstable[0]
+        node = unstables[0]
+
     obs = node.parents()[0]
     if not obs.obsolete():
         obs = node.parents()[1]
--- a/tests/test-evolve.t	Tue Jun 12 15:33:23 2012 +0200
+++ b/tests/test-evolve.t	Wed Jun 13 18:28:10 2012 +0200
@@ -211,19 +211,6 @@
   0	: base - test
   $ hg up -q 1
   Working directory parent is obsolete
-  $ hg stabilize -n
-  nothing to stabilize here
-  (1 unstable changesets, do you want --any ?)
-  [2]
-  $ hg stabilize -n --any
-  move:[4] another feature
-  atop:[6] a nifty feature
-  hg rebase -Dr f8111a076f09 -d 23409eba69a0
-  $ hg up -q 6
-  $ hg stabilize -n
-  move:[4] another feature
-  atop:[6] a nifty feature
-  hg rebase -Dr f8111a076f09 -d 23409eba69a0
   $ hg stabilize
   move:[4] another feature
   atop:[6] a nifty feature
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-stabilize-order.t	Wed Jun 13 18:28:10 2012 +0200
@@ -0,0 +1,158 @@
+  $ cat >> $HGRCPATH <<EOF
+  > [defaults]
+  > amend=-d "0 0"
+  > [extensions]
+  > hgext.rebase=
+  > hgext.graphlog=
+  > EOF
+  $ echo "obsolete=$(echo $(dirname $TESTDIR))/hgext/obsolete.py" >> $HGRCPATH
+  $ echo "evolve=$(echo $(dirname $TESTDIR))/hgext/evolve.py" >> $HGRCPATH
+
+  $ glog() {
+  >   hg glog --template '{rev}:{node|short}@{branch}({phase}) {desc|firstline}\n' "$@"
+  > }
+
+  $ hg init repo
+  $ cd repo
+  $ echo root > root
+  $ hg ci -Am addroot
+  adding root
+  $ echo a > a
+  $ hg ci -Am adda
+  adding a
+  $ echo b > b
+  $ hg ci -Am addb
+  adding b
+  $ echo c > c
+  $ hg ci -Am addc
+  adding c
+  $ glog
+  @  3:7a7552255fb5@default(draft) addc
+  |
+  o  2:ef23d6ef94d6@default(draft) addb
+  |
+  o  1:93418d2c0979@default(draft) adda
+  |
+  o  0:c471ef929e6a@default(draft) addroot
+  
+  $ hg gdown
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  [2] addb
+  $ echo b >> b
+  $ hg amend
+  1 new unstables changesets
+  $ hg gdown
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  [1] adda
+  $ echo a >> a
+  $ hg amend
+  1 new unstables changesets
+  $ glog
+  @  7:f5ff10856e5a@default(draft) adda
+  |
+  | o  5:ab8cbb6d87ff@default(draft) addb
+  | |
+  | | o  3:7a7552255fb5@default(draft) addc
+  | | |
+  | | o  2:ef23d6ef94d6@default(draft) addb
+  | |/
+  | o  1:93418d2c0979@default(draft) adda
+  |/
+  o  0:c471ef929e6a@default(draft) addroot
+  
+
+Test stabilizing a predecessor child
+
+  $ hg stabilize -v
+  move:[5] addb
+  atop:[7] adda
+  hg rebase -Dr ab8cbb6d87ff -d f5ff10856e5a
+  resolving manifests
+  getting b
+  b
+  $ glog
+  @  8:6bf44048e43f@default(draft) addb
+  |
+  o  7:f5ff10856e5a@default(draft) adda
+  |
+  | o  3:7a7552255fb5@default(draft) addc
+  | |
+  | o  2:ef23d6ef94d6@default(draft) addb
+  | |
+  | o  1:93418d2c0979@default(draft) adda
+  |/
+  o  0:c471ef929e6a@default(draft) addroot
+  
+
+Test stabilizing a descendant predecessors child
+
+  $ hg up 7
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ hg stabilize -v
+  move:[3] addc
+  atop:[8] addb
+  hg rebase -Dr 7a7552255fb5 -d 6bf44048e43f
+  resolving manifests
+  getting b
+  resolving manifests
+  getting c
+  c
+  $ glog
+  @  9:5e819fbb0d27@default(draft) addc
+  |
+  o  8:6bf44048e43f@default(draft) addb
+  |
+  o  7:f5ff10856e5a@default(draft) adda
+  |
+  o  0:c471ef929e6a@default(draft) addroot
+  
+  $ hg stabilize -v
+  no unstable changeset
+  [1]
+
+Test behaviour with --any
+
+  $ hg up 8
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ echo b >> b
+  $ hg amend
+  1 new unstables changesets
+  $ glog
+  @  11:4e7cec6b4afe@default(draft) addb
+  |
+  | o  9:5e819fbb0d27@default(draft) addc
+  | |
+  | o  8:6bf44048e43f@default(draft) addb
+  |/
+  o  7:f5ff10856e5a@default(draft) adda
+  |
+  o  0:c471ef929e6a@default(draft) addroot
+  
+  $ hg up 9
+  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg stabilize -v
+  nothing to stabilize here
+  (1 unstable changesets, do you want --any ?)
+  [2]
+  $ hg stabilize --any -v
+  move:[9] addc
+  atop:[11] addb
+  hg rebase -Dr 5e819fbb0d27 -d 4e7cec6b4afe
+  resolving manifests
+  removing c
+  getting b
+  resolving manifests
+  getting c
+  c
+  $ glog
+  @  12:24f95816bb21@default(draft) addc
+  |
+  o  11:4e7cec6b4afe@default(draft) addb
+  |
+  o  7:f5ff10856e5a@default(draft) adda
+  |
+  o  0:c471ef929e6a@default(draft) addroot
+  
+  $ hg stabilize --any -v
+  no unstable changeset
+  [1]