changeset 407:9fcbe7c47939

merge with stable
author Pierre-Yves David <pierre-yves.david@logilab.fr>
date Tue, 31 Jul 2012 12:47:56 +0200
parents b5b1bf5166a2 (diff) 24762f1911ba (current diff)
children 4c1997e41d18
files hgext/obsolete.py
diffstat 15 files changed, 309 insertions(+), 710 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore
+++ b/.hgignore
@@ -5,6 +5,7 @@
 ^html/
 \.pyc$
 ~$
+\.swp$
 \.orig$
 \.rej$
 \.err$
new file mode 100644
--- /dev/null
+++ b/contrib/nopushpublish.py
@@ -0,0 +1,30 @@
+# Extension which prevent changeset to be turn public by push operation
+
+from mercurial import extensions, util
+from mercurial import discovery
+
+def checkpublish(orig, repo, remote, outgoing, *args):
+
+    # is remote publishing?
+    publish = True
+    if 'phases' in remote.listkeys('namespaces'):
+        remotephases = remote.listkeys('phases')
+        publish = remotephases.get('publishing', False)
+
+    npublish = 0
+    if publish:
+        for rev in outgoing.missing:
+            if repo[rev].phase():
+                npublish += 1
+    if npublish:
+        repo.ui.warn("Push would publish %s changesets" % npublish)
+
+    ret = orig(repo, remote, outgoing, *args)
+    if npublish:
+        raise util.Abort("Publishing push forbiden",
+                         hint="Use `hg phase -p <rev>` to manually publish them")
+
+    return ret
+
+def uisetup(ui):
+    extensions.wrapfunction(discovery, 'checkheads', checkpublish)
--- a/docs/evolve-faq.rst
+++ b/docs/evolve-faq.rst
@@ -96,9 +96,9 @@
 Getting changes out of a commit
 ------------------------------------------------------------
 
-the ``hg uncommit`` commands allow you to rewrite the current commit to not
-include change for some file. The content of target files are not altered on
-disk and back as "modified"::
+The ``hg uncommit`` command lets you rewrite the parent commit without
+selected changed files. Target files content is not altered and
+appears again as "modified"::
 
   $ hg st
   M babar
@@ -112,8 +112,7 @@
 Split a changeset
 -----------------------
 
-I you just want to split whole file, you can just use the ``uncommit`` command.
-
+To split on file boundaries, just use ``uncommit`` command.
 
 If you need fine-grained split, there is no official command for that yet.
 However, it is easily achieved by manual operation::
@@ -223,8 +222,8 @@
 
 Extinct changesets are hidden using the *hidden* feature of mercurial.
 
-Only ``hg log`` and ``hgview`` support it. ``hg glog`` Only support that since
-2.2. Other visual viewer don't.
+Only ``hg log``, ``hg glog`` and ``hgview`` support it, other
+graphical viewer do not.
 
 
 
--- a/docs/from-mq.rst
+++ b/docs/from-mq.rst
@@ -84,7 +84,7 @@
 hg qref -X
 ````````````
 
-To remove change from you current commit use::
+To remove changes from you current commit use::
 
   $ hg uncommit not-ready.txt
 
--- a/docs/tutorials/tutorial.t
+++ b/docs/tutorials/tutorial.t
@@ -223,7 +223,7 @@
   adding manifests
   adding file changes
   added 1 changesets with 1 changes to 1 files (+1 heads)
-  (run 'hg update' to get a working copy)
+  (run 'hg heads .' to see heads, 'hg merge' to merge)
 
 I now have a new heads. Note that this remote head is immutable
 
@@ -585,7 +585,7 @@
   |
   | @  ffa278c50818 (draft): bathroom stuff
   | |
-  o |  8a79ae8b029e (draft): bathroom stuff
+  x |  8a79ae8b029e (draft): bathroom stuff
   |/
   o  a2fccc2e7b08 (public): SPAM SPAM
   |
@@ -610,7 +610,7 @@
   pushing to $TESTTMP/other
   searching for changes
   abort: push includes an unstable changeset: 9ac5d0e790a2!
-  (use 'hg stabilize' to get a stable history (or --force to proceed))
+  (use 'hg stabilize' to get a stable history or --force to ignore warnings)
   [255]
  
 
@@ -723,7 +723,7 @@
   $ hg log -G
   o  ae45c0c3092a (draft): SPAM SPAM SPAM
   |
-  o  437efbcaf700 (draft): animals
+  x  437efbcaf700 (draft): animals
   |
   @  ffa278c50818 (draft): bathroom stuff
   |
--- a/hgext/obsolete.py
+++ b/hgext/obsolete.py
@@ -31,13 +31,6 @@
 Usage and Feature
 =================
 
-Display and Exchange
---------------------
-
-obsolete changesets are hidden. (except if they have non obsolete changeset)
-
-obsolete changesets are not exchanged. This will probably change later but it
-was the simpler solution for now.
 
 New commands
 ------------
@@ -48,34 +41,9 @@
 extension will cause such a call to abort. Until better releasen please use
 graft command to rebase and copy changesets.
 
-Context object
---------------
-
-Context gains a ``obsolete`` method that will return True if a changeset is
-obsolete False otherwise.
-
-revset
-------
-
-Add an ``obsolete()`` entry.
-
-repo extension
---------------
-
-To Do
-~~~~~
-
-- refuse to obsolete published changesets
-
-- handle split
-
-- handle conflict
-
-- handle unstable // out of sync
-
 """
 
-import os
+import os, sys
 try:
     from cStringIO import StringIO
 except ImportError:
@@ -83,7 +51,6 @@
 
 from mercurial.i18n import _
 
-import base64
 import json
 
 import struct
@@ -108,6 +75,8 @@
 from mercurial import localrepo
 from mercurial import cmdutil
 from mercurial import templatekw
+from mercurial import obsolete
+setattr(obsolete, '_enabled', True)
 
 try:
     from mercurial.localrepo import storecache
@@ -120,14 +89,6 @@
 ### Patch changectx
 #############################
 
-def obsolete(ctx):
-    """is the changeset obsolete by other"""
-    if ctx.node()is None:
-        return False
-    return bool(ctx._repo.obsoletedby(ctx.node())) and ctx.phase()
-
-context.changectx.obsolete = obsolete
-
 def unstable(ctx):
     """is the changeset unstable (have obsolete ancestor)"""
     if ctx.node() is None:
@@ -165,44 +126,60 @@
 #############################
 
 def revsethidden(repo, subset, x):
-    """hidden changesets"""
+    """``hidden()``
+    Changeset is hidden.
+    """
     args = revset.getargs(x, 0, 0, 'hidden takes no argument')
-    return [r for r in subset if r in repo.changelog.hiddenrevs]
+    return [r for r in subset if r in repo.hiddenrevs]
 
 def revsetobsolete(repo, subset, x):
-    """obsolete changesets"""
+    """``obsolete()``
+    Changeset is obsolete.
+    """
     args = revset.getargs(x, 0, 0, 'obsolete takes no argument')
     return [r for r in subset if r in repo._obsoleteset and repo._phasecache.phase(repo, r) > 0]
 
 # XXX Backward compatibility, to be removed once stabilized
 if '_phasecache' not in vars(localrepo.localrepository): # new api
     def revsetobsolete(repo, subset, x):
-        """obsolete changesets"""
+        """``obsolete()``
+        Changeset is obsolete.
+        """
         args = revset.getargs(x, 0, 0, 'obsolete takes no argument')
         return [r for r in subset if r in repo._obsoleteset and repo._phaserev[r] > 0]
 
 def revsetunstable(repo, subset, x):
-    """non obsolete changesets descendant of obsolete one"""
+    """``unstable()``
+    Unstable changesets are non-obsolete with obsolete ancestors.
+    """
     args = revset.getargs(x, 0, 0, 'unstable takes no arguments')
     return [r for r in subset if r in repo._unstableset]
 
 def revsetsuspended(repo, subset, x):
-    """obsolete changesets with non obsolete descendants"""
+    """``suspended()``
+    Obsolete changesets with non-obsolete descendants.
+    """
     args = revset.getargs(x, 0, 0, 'suspended takes no arguments')
     return [r for r in subset if r in repo._suspendedset]
 
 def revsetextinct(repo, subset, x):
-    """obsolete changesets without obsolete descendants"""
+    """``extinct()``
+    Obsolete changesets with obsolete descendants only.
+    """
     args = revset.getargs(x, 0, 0, 'extinct takes no arguments')
     return [r for r in subset if r in repo._extinctset]
 
 def revsetlatecomer(repo, subset, x):
-    """latecomer, Try to succeed to public change"""
+    """``latecomer()``
+    Changesets marked as successors of public changesets.
+    """
     args = revset.getargs(x, 0, 0, 'latecomer takes no arguments')
     return [r for r in subset if r in repo._latecomerset]
 
 def revsetconflicting(repo, subset, x):
-    """conflicting, Try to succeed to public change"""
+    """``conflicting()``
+    Changesets marked as successors of a same changeset.
+    """
     args = revset.getargs(x, 0, 0, 'conflicting takes no arguments')
     return [r for r in subset if r in repo._conflictingset]
 
@@ -219,7 +196,9 @@
     return cs
 
 def revsetprecursors(repo, subset, x):
-    """precursors of a subset"""
+    """``precursors(set)``
+    Immediate precursors of changesets in set.
+    """
     s = revset.getset(repo, range(len(repo)), x)
     cs = _precursors(repo, s)
     return [r for r in subset if r in cs]
@@ -245,7 +224,9 @@
     return cs
 
 def revsetallprecursors(repo, subset, x):
-    """obsolete parents"""
+    """``allprecursors(set)``
+    Transitive precursors of changesets in set.
+    """
     s = revset.getset(repo, range(len(repo)), x)
     cs = _allprecursors(repo, s)
     return [r for r in subset if r in cs]
@@ -264,7 +245,9 @@
     return cs
 
 def revsetsuccessors(repo, subset, x):
-    """successors of a subset"""
+    """``successors(set)``
+    Immediate successors of changesets in set.
+    """
     s = revset.getset(repo, range(len(repo)), x)
     cs = _successors(repo, s)
     return [r for r in subset if r in cs]
@@ -290,7 +273,9 @@
     return cs
 
 def revsetallsuccessors(repo, subset, x):
-    """obsolete parents"""
+    """``allsuccessors(set)``
+    Transitive successors of changesets in set.
+    """
     s = revset.getset(repo, range(len(repo)), x)
     cs = _allsuccessors(repo, s)
     return [r for r in subset if r in cs]
@@ -428,59 +413,9 @@
     except KeyError:
         pass  # rebase not found
 
-# Pushkey mechanism for mutable
-#########################################
-
-def listmarkers(repo):
-    """List markers over pushkey"""
-    if not repo.obsstore:
-        return {}
-    data = repo.obsstore._writemarkers()
-    encdata = base85.b85encode(data)
-    return {'dump0': encdata,
-            'dump': encdata} # legacy compat
-
-def pushmarker(repo, key, old, new):
-    """Push markers over pushkey"""
-    if not key.startswith('dump'):
-        repo.ui.warn(_('unknown key: %r') % key)
-        return 0
-    if old:
-        repo.ui.warn(_('unexpected old value') % key)
-        return 0
-    data = base85.b85decode(new)
-    lock = repo.lock()
-    try:
-        repo.obsstore.mergemarkers(data)
-        return 1
-    finally:
-        lock.release()
-
-pushkey.register('obsolete', pushmarker, listmarkers)
-
 ### Discovery wrapping
 #############################
 
-class blist(list, object):
-    """silly class to have non False but empty list"""
-
-    def __nonzero__(self):
-        return bool(len(self.orig))
-
-def wrapfindcommonoutgoing(orig, repo, *args, **kwargs):
-    """wrap mercurial.discovery.findcommonoutgoing to remove extinct changeset
-
-    Such excluded changeset are removed from excluded  and will *not* appear
-    are excluded secret changeset.
-    """
-    outgoing = orig(repo, *args, **kwargs)
-    orig = outgoing.excluded
-    outgoing.excluded = blist(n for n in orig if not repo[n].extinct())
-    # when no revision is specified (push everything) a shortcut is taken when
-    # nothign was exclude. taking this code path when extinct changeset have
-    # been excluded leads to repository corruption.
-    outgoing.excluded.orig = orig
-    return outgoing
 
 def wrapcheckheads(orig, repo, remote, outgoing, *args, **kwargs):
     """wrap mercurial.discovery.checkheads
@@ -490,74 +425,16 @@
     """
     # do not push instability
     for h in outgoing.missingheads:
-        # checking heads only is enought because any thing base on obsolete
-        # changeset is either obsolete or unstable.
-        ctx =  repo[h]
-        if ctx.unstable():
-            raise util.Abort(_("push includes an unstable changeset: %s!")
-                             % ctx)
-        if ctx.obsolete():
-            raise util.Abort(_("push includes an  obsolete changeset: %s!")
-                             % ctx)
+        # Checking heads is enough, obsolete descendants are either
+        # obsolete or unstable.
+        ctx = repo[h]
         if ctx.latecomer():
-            raise util.Abort(_("push includes an latecomer changeset: %s!")
+            raise util.Abort(_("push includes a latecomer changeset: %s!")
                              % ctx)
         if ctx.conflicting():
-            raise util.Abort(_("push includes conflicting changeset: %s!")
+            raise util.Abort(_("push includes a conflicting changeset: %s!")
                              % ctx)
-    ### patch remote branch map
-    # do not read it this burn eyes
-    try:
-        if 'oldbranchmap' not in vars(remote):
-            remote.oldbranchmap = remote.branchmap
-            def branchmap():
-                newbm = {}
-                oldbm = None
-                if (util.safehasattr(phases, 'visiblebranchmap')
-                    and not util.safehasattr(remote, 'ignorevisiblebranchmap')
-                   ):
-                    remote.ignorevisiblebranchmap = False
-                    remote.branchmap = remote.oldbranchmap
-                    oldbm = phases.visiblebranchmap(remote)
-                    remote.branchmap = remote.newbranchmap
-                    remote.ignorevisiblebranchmap = True
-                if oldbm is None:
-                    oldbm = remote.oldbranchmap()
-                for branch, nodes in oldbm.iteritems():
-                    nodes = list(nodes)
-                    new = set()
-                    while nodes:
-                        n = nodes.pop()
-                        if n in repo.obsstore.precursors:
-                            markers = repo.obsstore.precursors[n]
-                            for mark in markers:
-                                for newernode in mark[1]:
-                                    if newernode is not None:
-                                        nodes.append(newernode)
-                        else:
-                            new.add(n)
-                    if new:
-                        newbm[branch] = list(new)
-                return newbm
-            remote.ignorevisiblebranchmap = True
-            remote.branchmap = branchmap
-            remote.newbranchmap = branchmap
-        return orig(repo, remote, outgoing, *args, **kwargs)
-    finally:
-        remote.__dict__.pop('branchmap', None) # restore class one
-        remote.__dict__.pop('oldbranchmap', None)
-        remote.__dict__.pop('newbranchmap', None)
-        remote.__dict__.pop('ignorevisiblebranchmap', None)
-
-# eye are still burning
-def wrapvisiblebranchmap(orig, repo):
-    ignore = getattr(repo, 'ignorevisiblebranchmap', None)
-    if ignore is None:
-        return orig(repo)
-    elif ignore:
-        return repo.branchmap()
-    else:
-        return None # break recursion
+    return orig(repo, remote, outgoing, *args, **kwargs)
 
 def wrapclearcache(orig, repo, *args, **kwargs):
     try:
@@ -572,20 +449,6 @@
 cmdtable = {}
 command = cmdutil.command(cmdtable)
 
-@command('debugobsolete', [], _('SUBJECT OBJECT'))
-def cmddebugobsolete(ui, repo, subject, object):
-    """add an obsolete relation between two nodes
-
-    The subject is expected to be a newer version of the object.
-    """
-    lock = repo.lock()
-    try:
-        sub = repo[subject]
-        obj = repo[object]
-        repo.addobsolete(sub.node(), obj.node())
-    finally:
-        lock.release()
-    return 0
 
 @command('debugconvertobsolete', [], '')
 def cmddebugconvertobsolete(ui, repo):
@@ -595,69 +458,77 @@
     l = repo.lock()
     some = False
     try:
-        repo._importoldobsolete = True
-        store = repo.obsstore
-        ### very first format
+        unlink = []
+        tr = repo.transaction('convert-obsolete')
         try:
-            f = repo.opener('obsolete-relations')
+            repo._importoldobsolete = True
+            store = repo.obsstore
+            ### very first format
             try:
+                f = repo.opener('obsolete-relations')
+                try:
+                    some = True
+                    for line in f:
+                        subhex, objhex = line.split()
+                        suc = bin(subhex)
+                        prec = bin(objhex)
+                        sucs = (suc==nullid) and [] or [suc]
+                        meta = {
+                            'date':  '%i %i' % util.makedate(),
+                            'user': ui.username(),
+                            }
+                        try:
+                            store.create(tr, prec, sucs, 0, meta)
+                            cnt += 1
+                        except ValueError:
+                            repo.ui.write_err("invalid old marker line: %s"
+                                              % (line))
+                            err += 1
+                finally:
+                    f.close()
+                unlink.append(repo.join('obsolete-relations'))
+            except IOError:
+                pass
+            ### second (json) format
+            data = repo.sopener.tryread('obsoletemarkers')
+            if data:
                 some = True
-                for line in f:
-                    subhex, objhex = line.split()
-                    suc = bin(subhex)
-                    prec = bin(objhex)
-                    sucs = (suc==nullid) and [] or [suc]
-                    meta = {
-                        'date':  '%i %i' % util.makedate(),
-                        'user': ui.username(),
-                        }
+                for oldmark in json.loads(data):
+                    del oldmark['id']  # dropped for now
+                    del oldmark['reason']  # unused until then
+                    oldobject = str(oldmark.pop('object'))
+                    oldsubjects = [str(s) for s in oldmark.pop('subjects', [])]
+                    LOOKUP_ERRORS = (error.RepoLookupError, error.LookupError)
+                    if len(oldobject) != 40:
+                        try:
+                            oldobject = repo[oldobject].node()
+                        except LOOKUP_ERRORS:
+                            pass
+                    if any(len(s) != 40 for s in oldsubjects):
+                        try:
+                            oldsubjects = [repo[s].node() for s in oldsubjects]
+                        except LOOKUP_ERRORS:
+                            pass
+
+                    oldmark['date'] = '%i %i' % tuple(oldmark['date'])
+                    meta = dict((k.encode('utf-8'), v.encode('utf-8'))
+                                 for k, v in oldmark.iteritems())
                     try:
-                        store.create(prec, sucs, 0, meta)
+                        succs = [bin(n) for n in oldsubjects]
+                        succs = [n for n in succs if n != nullid]
+                        store.create(tr, bin(oldobject), succs,
+                                     0, meta)
                         cnt += 1
                     except ValueError:
-                        repo.ui.write_err("invalid old marker line: %s"
-                                          % (line))
+                        repo.ui.write_err("invalid marker %s -> %s\n"
+                                     % (oldobject, oldsubjects))
                         err += 1
-            finally:
-                f.close()
-            util.unlink(repo.join('obsolete-relations'))
-        except IOError:
-            pass
-        ### second (json) format
-        data = repo.sopener.tryread('obsoletemarkers')
-        if data:
-            some = True
-            for oldmark in json.loads(data):
-                del oldmark['id']  # dropped for now
-                del oldmark['reason']  # unused until then
-                oldobject = str(oldmark.pop('object'))
-                oldsubjects = [str(s) for s in oldmark.pop('subjects', [])]
-                LOOKUP_ERRORS = (error.RepoLookupError, error.LookupError)
-                if len(oldobject) != 40:
-                    try:
-                        oldobject = repo[oldobject].node()
-                    except LOOKUP_ERRORS:
-                        pass
-                if any(len(s) != 40 for s in oldsubjects):
-                    try:
-                        oldsubjects = [repo[s].node() for s in oldsubjects]
-                    except LOOKUP_ERRORS:
-                        pass
-
-                oldmark['date'] = '%i %i' % tuple(oldmark['date'])
-                meta = dict((k.encode('utf-8'), v.encode('utf-8'))
-                             for k, v in oldmark.iteritems())
-                try:
-                    succs = [bin(n) for n in oldsubjects]
-                    succs = [n for n in succs if n != nullid]
-                    store.create(bin(oldobject), succs,
-                                 0, meta)
-                    cnt += 1
-                except ValueError:
-                    repo.ui.write_err("invalid marker %s -> %s\n"
-                                 % (oldobject, oldsubjects))
-                    err += 1
-            util.unlink(repo.sjoin('obsoletemarkers'))
+                unlink.append(repo.sjoin('obsoletemarkers'))
+            tr.close()
+            for path in unlink:
+                util.unlink(path)
+        finally:
+            tr.release()
     finally:
         del repo._importoldobsolete
         l.release()
@@ -718,26 +589,23 @@
         if newconflictings > 0:
             ui.warn(_('%i new conflictings changesets\n') % newconflictings)
 
-def noextinctsvisibleheads(orig, repo):
-    repo._turn_extinct_secret()
-    return orig(repo)
-
 def wrapcmdutilamend(orig, ui, repo, commitfunc, old, *args, **kwargs):
     oldnode = old.node()
     new = orig(ui, repo, commitfunc, old, *args, **kwargs)
     if new != oldnode:
         lock = repo.lock()
         try:
-            meta = {
-                'subjects':  [new],
-                'object': oldnode,
-                'date':  util.makedate(),
-                'user': ui.username(),
-                'reason': 'commit --amend',
-                }
-            repo.obsstore.create(oldnode, [new], 0, meta)
-            repo._clearobsoletecache()
-            repo._turn_extinct_secret()
+            tr = repo.transaction('post-amend-obst')
+            try:
+                meta = {
+                    'date':  '%i %i' % util.makedate(),
+                    'user': ui.username(),
+                    }
+                repo.obsstore.create(tr, oldnode, [new], 0, meta)
+                tr.close()
+                repo._clearobsoletecache()
+            finally:
+                tr.release()
         finally:
             lock.release()
     return new
@@ -747,12 +615,8 @@
     extensions.wrapcommand(commands.table, "pull", wrapmayobsoletewc)
     if util.safehasattr(cmdutil, 'amend'):
         extensions.wrapfunction(cmdutil, 'amend', wrapcmdutilamend)
-    extensions.wrapfunction(discovery, 'findcommonoutgoing', wrapfindcommonoutgoing)
     extensions.wrapfunction(discovery, 'checkheads', wrapcheckheads)
-    extensions.wrapfunction(phases, 'visibleheads', noextinctsvisibleheads)
     extensions.wrapfunction(phases, 'advanceboundary', wrapclearcache)
-    if util.safehasattr(phases, 'visiblebranchmap'):
-        extensions.wrapfunction(phases, 'visiblebranchmap', wrapvisiblebranchmap)
 
 ### serialisation
 #############################
@@ -813,183 +677,6 @@
             newer.add(())
     return sorted(newer)
 
-### obsolete relation storage
-#############################
-def add2set(d, key, mark):
-    """add <mark> to a `set` in <d>[<key>]"""
-    d.setdefault(key, []).append(mark)
-
-def markerid(marker):
-    KEYS = ['subjects', "object", "date", "user", "reason"]
-    for key in KEYS:
-        assert key in marker
-    keys = sorted(marker.keys())
-    a = util.sha1()
-    for key in keys:
-        if key == 'subjects':
-            for sub in sorted(marker[key]):
-                a.update(sub)
-        elif key == 'id':
-            pass
-        else:
-            a.update(str(marker[key]))
-    a.update('\0')
-    return a.digest()
-
-# mercurial backport
-
-def encodemeta(meta):
-    """Return encoded metadata string to string mapping.
-
-    Assume no ':' in key and no '\0' in both key and value."""
-    for key, value in meta.iteritems():
-        if ':' in key or '\0' in key:
-            raise ValueError("':' and '\0' are forbidden in metadata key'")
-        if '\0' in value:
-            raise ValueError("':' are forbidden in metadata value'")
-    return '\0'.join(['%s:%s' % (k, meta[k]) for k in sorted(meta)])
-
-def decodemeta(data):
-    """Return string to string dictionary from encoded version."""
-    d = {}
-    for l in data.split('\0'):
-        if l:
-            key, value = l.split(':')
-            d[key] = value
-    return d
-
-# data used for parsing and writing
-_fmversion = 0
-_fmfixed   = '>BIB20s'
-_fmnode = '20s'
-_fmfsize = struct.calcsize(_fmfixed)
-_fnodesize = struct.calcsize(_fmnode)
-
-def _readmarkers(data):
-    """Read and enumerate markers from raw data"""
-    off = 0
-    diskversion = _unpack('>B', data[off:off + 1])[0]
-    off += 1
-    if diskversion != _fmversion:
-        raise util.Abort(_('parsing obsolete marker: unknown version %r')
-                         % diskversion)
-
-    # Loop on markers
-    l = len(data)
-    while off + _fmfsize <= l:
-        # read fixed part
-        cur = data[off:off + _fmfsize]
-        off += _fmfsize
-        nbsuc, mdsize, flags, pre = _unpack(_fmfixed, cur)
-        # read replacement
-        sucs = ()
-        if nbsuc:
-            s = (_fnodesize * nbsuc)
-            cur = data[off:off + s]
-            sucs = _unpack(_fmnode * nbsuc, cur)
-            off += s
-        # read metadata
-        # (metadata will be decoded on demand)
-        metadata = data[off:off + mdsize]
-        if len(metadata) != mdsize:
-            raise util.Abort(_('parsing obsolete marker: metadata is too '
-                               'short, %d bytes expected, got %d')
-                             % (len(metadata), mdsize))
-        off += mdsize
-        yield (pre, sucs, flags, metadata)
-
-class obsstore(object):
-    """Store obsolete markers
-
-    Markers can be accessed with two mappings:
-    - precursors: old -> set(new)
-    - successors: new -> set(old)
-    """
-
-    def __init__(self):
-        self._all = []
-        # new markers to serialize
-        self._new = []
-        self.precursors = {}
-        self.successors = {}
-
-    def __iter__(self):
-        return iter(self._all)
-
-    def __nonzero__(self):
-        return bool(self._all)
-
-    def create(self, prec, succs=(), flag=0, metadata=None):
-        """obsolete: add a new obsolete marker
-
-        * ensuring it is hashable
-        * check mandatory metadata
-        * encode metadata
-        """
-        if metadata is None:
-            metadata = {}
-        if len(prec) != 20:
-            raise ValueError(repr(prec))
-        for succ in succs:
-            if len(succ) != 20:
-                raise ValueError((succs))
-        marker = (str(prec), tuple(succs), int(flag), encodemeta(metadata))
-        self.add(marker)
-
-    def add(self, marker):
-        """Add a new marker to the store
-
-        This marker still needs to be written to disk"""
-        self._new.append(marker)
-        self._load(marker)
-
-    def loadmarkers(self, data):
-        """Load all markers in data, mark them as known."""
-        for marker in _readmarkers(data):
-            self._load(marker)
-
-    def mergemarkers(self, data):
-        other = set(_readmarkers(data))
-        local = set(self._all)
-        new = other - local
-        for marker in new:
-            self.add(marker)
-
-    def flushmarkers(self, stream):
-        """Write all markers to a stream
-
-        After this operation, "new" markers are considered "known"."""
-        self._writemarkers(stream)
-        self._new[:] = []
-
-    def _load(self, marker):
-        self._all.append(marker)
-        pre, sucs = marker[:2]
-        self.precursors.setdefault(pre, set()).add(marker)
-        for suc in sucs:
-            self.successors.setdefault(suc, set()).add(marker)
-
-    def _writemarkers(self, stream=None):
-        # Kept separate from flushmarkers(), it will be reused for
-        # markers exchange.
-        if stream is None:
-            final = []
-            w = final.append
-        else:
-            w = stream.write
-        w(_pack('>B', _fmversion))
-        for marker in self._all:
-            pre, sucs, flags, metadata = marker
-            nbsuc = len(sucs)
-            format = _fmfixed + (_fmnode * nbsuc)
-            data = [nbsuc, len(metadata), flags, pre]
-            data.extend(sucs)
-            w(_pack(format, *data))
-            w(metadata)
-        if stream is None:
-            return ''.join(final)
-
-
 ### repo subclassing
 #############################
 
@@ -999,10 +686,7 @@
 
     if not util.safehasattr(repo.opener, 'tryread'):
         raise util.Abort('Obsolete extension require Mercurial 2.2 (or later)')
-    opull = repo.pull
     opush = repo.push
-    olock = repo.lock
-    o_rollback = repo._rollback
     o_updatebranchcache = repo.updatebranchcache
 
     # /!\ api change in  Hg 2.2 (97efd26eb9576f39590812ea9) /!\
@@ -1025,31 +709,13 @@
             """return the set of node that <node> make obsolete (sub)"""
             return set(marker[0] for marker in self.obsstore.successors.get(node, []))
 
-        @storecache('obsstore')
-        def obsstore(self):
-            if not getattr(self, '_importoldobsolete', False):
-                data = repo.opener.tryread('obsolete-relations')
-                if not data:
-                    data = repo.sopener.tryread('obsoletemarkers')
-                if data:
-                    raise util.Abort('old format of obsolete marker detected!\n'
-                                     'run `hg debugconvertobsolete` once.')
-            store = obsstore()
-            data = self.sopener.tryread('obsstore')
-            if data:
-                store.loadmarkers(data)
-            return store
-
         @util.propertycache
         def _obsoleteset(self):
             """the set of obsolete revision"""
             obs = set()
             nm = self.changelog.nodemap
-            for obj in self.obsstore.precursors:
-                try: # /!\api change in Hg 2.2 (e8d37b78acfb22ae2c1fb126c2)/!\
-                    rev = nm.get(obj)
-                except TypeError:  #XXX to remove while breaking Hg 2.1 support
-                    rev = nm.get(obj, None)
+            for prec in self.obsstore.precursors:
+                rev = nm.get(prec)
                 if rev is not None:
                     obs.add(rev)
             return obs
@@ -1130,16 +796,19 @@
                         % {'sub': short(sub), 'obj': short(obj)})
             lock = self.lock()
             try:
-                meta = {
-                    'date':  util.makedate(),
-                    'user': ui.username(),
-                    'reason': 'unknown',
-                    }
-                subs = (sub == nullid) and [] or [sub]
-                mid = self.obsstore.create(obj, subs, 0, meta)
-                self._clearobsoletecache()
-                self._turn_extinct_secret()
-                return mid
+                tr = self.transaction('add-obsolete')
+                try:
+                    meta = {
+                        'date':  '%i %i' % util.makedate(),
+                        'user': ui.username(),
+                        }
+                    subs = (sub == nullid) and [] or [sub]
+                    mid = self.obsstore.create(tr, obj, subs, 0, meta)
+                    tr.close()
+                    self._clearobsoletecache()
+                    return mid
+                finally:
+                    tr.release()
             finally:
                 lock.release()
 
@@ -1148,155 +817,35 @@
             # Assume oldnodes are all descendants of a single rev
             rootrevs = self.revs('roots(%ln)', oldnodes)
             assert len(rootrevs) == 1, rootrevs
-            rootnode = self[rootrevs[0]].node()
+            #rootnode = self[rootrevs[0]].node()
             for n in oldnodes:
                 self.addobsolete(newnode, n)
 
-        def _turn_extinct_secret(self):
-            """ensure all extinct changeset are secret"""
-            self._clearobsoletecache()
-            # this is mainly for safety purpose
-            # both pull and push
-            query = '(obsolete() - obsolete()::(unstable() - secret())) - secret()'
-            expobs = [c.node() for c in repo.set(query)]
-            phases.retractboundary(repo, 2, expobs)
-
-        ### Disk IO
-
-        def lock(self, *args, **kwargs):
-            l = olock(*args, **kwargs)
-            if not getattr(l.releasefn, 'obspatched', False):
-                oreleasefn = l.releasefn
-                def releasefn(*args, **kwargs):
-                    if 'obsstore' in vars(self) and self.obsstore._new:
-                        f = self.sopener('obsstore', 'wb', atomictemp=True)
-                        try:
-                            self.obsstore.flushmarkers(f)
-                            f.close()
-                        except: # re-raises
-                            f.discard()
-                            raise
-                    oreleasefn(*args, **kwargs)
-                releasefn.obspatched = True
-                l.releasefn = releasefn
-            return l
-
-
         ### pull // push support
 
-        def pull(self, remote, *args, **kwargs):
-            """wrapper around push that push obsolete relation"""
-            l = repo.lock()
-            try:
-                result = opull(remote, *args, **kwargs)
-                remoteobs = remote.listkeys('obsolete')
-                if 'dump' in remoteobs:
-                    remoteobs['dump0'] = remoteobs.pop('dump')
-                if 'dump0' in remoteobs:
-                    for key, values in remoteobs.iteritems():
-                        if key.startswith('dump'):
-                            data = base85.b85decode(remoteobs['dump0'])
-                            self.obsstore.mergemarkers(data)
-                    self._clearobsoletecache()
-                    self._turn_extinct_secret()
-                    return result
-            finally:
-                l.release()
-
         def push(self, remote, *args, **opts):
             """wrapper around pull that pull obsolete relation"""
-            self._turn_extinct_secret()
             try:
                 result = opush(remote, *args, **opts)
             except util.Abort, ex:
-                hint = _("use 'hg stabilize' to get a stable history (or --force to proceed)")
+                hint = _("use 'hg stabilize' to get a stable history "
+                         "or --force to ignore warnings")
                 if (len(ex.args) >= 1
                     and ex.args[0].startswith('push includes ')
                     and ex.hint is None):
                     ex.hint = hint
                 raise
-            if 'obsolete' in remote.listkeys('namespaces') and self.obsstore:
-                data = self.obsstore._writemarkers()
-                r = remote.pushkey('obsolete', 'dump0', '',
-                                   base85.b85encode(data))
-                if not r:
-                    self.ui.warn(_('failed to push obsolete markers!\n'))
-            self._turn_extinct_secret()
-
             return result
 
 
-        ### rollback support
-
-        # /!\ api change in  Hg 2.2 (97efd26eb9576f39590812ea9) /!\
-        if util.safehasattr(repo, '_journalfiles'): # Hg 2.2
-            def _journalfiles(self):
-                return o_journalfiles() + (self.sjoin('journal.obsstore'),) 
-
-            def _writejournal(self, desc):
-                """wrapped version of _writejournal that save obsolete data"""
-                o_writejournal(desc)
-                filename = 'obsstore'
-                filepath = self.sjoin(filename)
-                if os.path.exists(filepath):
-                    journalname = 'journal.' + filename
-                    journalpath = self.sjoin(journalname)
-                    util.copyfile(filepath, journalpath)
-
-        else: # XXX removing this bloc will break Hg 2.1 support
-            def _writejournal(self, desc):
-                """wrapped version of _writejournal that save obsolete data"""
-                entries = list(o_writejournal(desc))
-                filename = 'obsstore'
-                filepath = self.sjoin(filename)
-                if  os.path.exists(filepath):
-                    journalname = 'journal.' + filename
-                    journalpath = self.sjoin(journalname)
-                    util.copyfile(filepath, journalpath)
-                    entries.append(journalpath)
-                return tuple(entries)
-
-        def _rollback(self, dryrun, force):
-            """wrapped version of _rollback that restore obsolete data"""
-            ret = o_rollback(dryrun, force)
-            if not (ret or dryrun): #rollback did not failed
-                src = self.sjoin('undo.obsstore')
-                dst = self.sjoin('obsstore')
-                if os.path.exists(src):
-                    util.rename(src, dst)
-                elif os.path.exists(dst):
-                    # If no state was saved because the file did not existed before.
-                    os.unlink(dst)
-                # invalidate cache
-                self.__dict__.pop('obsstore', None)
-            return ret
-
-        @storecache('00changelog.i')
-        def changelog(self):
-            # << copy pasted from mercurial source
-            c = changelog.changelog(self.sopener)
-            if 'HG_PENDING' in os.environ:
-                p = os.environ['HG_PENDING']
-                if p.startswith(self.root):
-                    c.readpending('00changelog.i.a')
-            # >> end of the copy paste
-            old = c.__dict__.pop('hiddenrevs', ())
-            if old:
-                ui.warn("old wasn't empty ? %r" % old)
-            def _sethidden(c, value):
-                assert not value
-
-
-            class hchangelog(c.__class__):
-                @util.propertycache
-                def hiddenrevs(c):
-                    shown = ['not obsolete()', '.', 'bookmark()', 'tagged()',
-                             'public()']
-                    basicquery = 'obsolete() - (::(%s))' % (' or '.join(shown))
-                    # !!! self is repo not changelog
-                    result = set(scmutil.revrange(self, [basicquery]))
-                    return result
-            c.__class__ = hchangelog
-            return c
-
     repo.__class__ = obsoletingrepo
+    for arg in sys.argv:
+        if 'debugc' in arg:
+            break
+    else:
+        data = repo.opener.tryread('obsolete-relations')
+        if not data:
+            data = repo.sopener.tryread('obsoletemarkers')
+        if data:
+            raise util.Abort('old format of obsolete marker detected!\n'
+                             'run `hg debugconvertobsolete` once.')
--- a/tests/test-amend.t
+++ b/tests/test-amend.t
@@ -93,7 +93,7 @@
   7384bbcba36f 000000000000
   bd19cbe78fbf a34b93d251e4
   $ glog
-  @  6@foo(secret) amends a34b93d251e49c93d5685ebacad785c73a7e8605
+  @  6@foo(draft) amends a34b93d251e49c93d5685ebacad785c73a7e8605
   |
   o  5@default(draft) resetbranch
   |
--- a/tests/test-evolve.t
+++ b/tests/test-evolve.t
@@ -231,15 +231,15 @@
   $ glog --hidden
   o  6:23409eba69a0@default(draft) a nifty feature
   |
-  | o  5:e416e48b2742@default(secret) french looks better
+  | x  5:e416e48b2742@default(draft) french looks better
   | |
   | | o  4:f8111a076f09@default(draft) another feature
   | |/
-  | | o  3:524e478d4811@default(secret) fix spelling of Zwei
+  | | x  3:524e478d4811@default(draft) fix spelling of Zwei
   | | |
-  | | o  2:7b36850622b2@default(secret) another feature
+  | | x  2:7b36850622b2@default(draft) another feature
   | |/
-  | o  1:568a468b60fc@default(draft) a nifty feature
+  | x  1:568a468b60fc@default(draft) a nifty feature
   |/
   @  0:e55e0562ee93@default(draft) base
   
--- a/tests/test-obsolete-push.t
+++ b/tests/test-obsolete-push.t
@@ -32,9 +32,9 @@
   $ glog --hidden
   @  2:244232c2222a@default(unstable/secret) C
   |
-  | o  1:6c81ed0049f8@default(extinct/secret) B
+  | x  1:6c81ed0049f8@default(extinct/draft) B
   |/
-  o  0:1994f17a630e@default(suspended/secret) A
+  x  0:1994f17a630e@default(suspended/draft) A
   
   $ hg init ../clone
   $ cat >  ../clone/.hg/hgrc <<EOF
@@ -44,5 +44,4 @@
   $ hg outgoing ../clone --template "$template"
   comparing with ../clone
   searching for changes
-  no changes found (ignored 2 secret changesets)
-  [1]
+  0:1994f17a630e@default(suspended/draft) A
--- a/tests/test-obsolete-rebase.t
+++ b/tests/test-obsolete-rebase.t
@@ -70,7 +70,7 @@
   $ glog --hidden
   @  4:9c5494949763@default(draft) adde
   |
-  | o  3:98e4a024635e@default(secret) adde
+  | x  3:98e4a024635e@default(draft) adde
   | |
   | o  2:102a90ea7b4a@default(draft) addb
   | |
@@ -92,11 +92,11 @@
   $ hg ci -m changea
   $ hg rebase -d 1
   $ glog --hidden
-  o  5:4e322f7ce8e3@foo(secret) changea
+  x  5:4e322f7ce8e3@foo(draft) changea
   |
   | o  4:9c5494949763@default(draft) adde
   | |
-  | | o  3:98e4a024635e@default(secret) adde
+  | | x  3:98e4a024635e@default(draft) adde
   | | |
   +---o  2:102a90ea7b4a@default(draft) addb
   | |
@@ -123,15 +123,15 @@
   $ glog --hidden
   @  8:a7773ffa7edc@default(draft) Collapsed revision
   |
-  | o  7:03f31481307a@default(secret) changec
+  | x  7:03f31481307a@default(draft) changec
   | |
-  | o  6:076e9b2ffbe1@default(secret) addc
+  | x  6:076e9b2ffbe1@default(draft) addc
   | |
-  | | o  5:4e322f7ce8e3@foo(secret) changea
+  | | x  5:4e322f7ce8e3@foo(draft) changea
   | |/
   +---o  4:9c5494949763@default(draft) adde
   | |
-  | | o  3:98e4a024635e@default(secret) adde
+  | | x  3:98e4a024635e@default(draft) adde
   | | |
   | | o  2:102a90ea7b4a@default(draft) addb
   | |/
@@ -182,21 +182,21 @@
   |
   o  11:03f165c84ea8@default(draft) addd
   |
-  | o  10:4b9d80f48523@default(secret) appendab
+  | x  10:4b9d80f48523@default(draft) appendab
   | |
-  | o  9:a31943eabc43@default(secret) addd
+  | x  9:a31943eabc43@default(draft) addd
   | |
   +---o  8:a7773ffa7edc@default(draft) Collapsed revision
   | |
-  | | o  7:03f31481307a@default(secret) changec
+  | | x  7:03f31481307a@default(draft) changec
   | | |
-  | | o  6:076e9b2ffbe1@default(secret) addc
+  | | x  6:076e9b2ffbe1@default(draft) addc
   | |/
-  | | o  5:4e322f7ce8e3@foo(secret) changea
+  | | x  5:4e322f7ce8e3@foo(draft) changea
   | |/
   +---o  4:9c5494949763@default(draft) adde
   | |
-  | | o  3:98e4a024635e@default(secret) adde
+  | | x  3:98e4a024635e@default(draft) adde
   | | |
   | | o  2:102a90ea7b4a@default(draft) addb
   | |/
--- a/tests/test-obsolete.t
+++ b/tests/test-obsolete.t
@@ -15,6 +15,9 @@
   >    hg add "$1"
   >    hg ci -m "add $1"
   > }
+  $ getid() {
+  >    hg id --debug -ir "$1"
+  > }
 
   $ alias qlog="hg log --template='{rev}\n- {node|short}\n'"
   $ hg init local
@@ -27,9 +30,21 @@
   0 files updated, 0 files merged, 1 files removed, 0 files unresolved
   $ mkcommit obsol_c # 3
   created new head
-  $ hg debugobsolete 3 2
+  $ getid 2
+  4538525df7e2b9f09423636c61ef63a4cb872a2d
+  $ getid 3
+  0d3f46688ccc6e756c7e96cf64c391c411309597
+  $ hg debugobsolete 4538525df7e2b9f09423636c61ef63a4cb872a2d 0d3f46688ccc6e756c7e96cf64c391c411309597
+  $ hg debugobsolete
+  4538525df7e2b9f09423636c61ef63a4cb872a2d 0d3f46688ccc6e756c7e96cf64c391c411309597 0 {'date': '', 'user': 'test'}
 
 
+Test hidden() revset
+
+  $ qlog -r 'hidden()' --hidden
+  2
+  - 4538525df7e2
+
 Test that obsolete changeset are hidden
 
   $ qlog
@@ -82,7 +97,7 @@
   $ hg up 1 -q
   $ mkcommit "obsol_c'" # 4 (on 1)
   created new head
-  $ hg debugobsolete 4 3
+  $ hg debugobsolete `getid 3` `getid 4`
   $ qlog
   4
   - 725c380fe99b
@@ -127,13 +142,13 @@
 
   $ hg glog --template '{rev}:{node|short}@{branch}({obsolete}/{phase}) {desc|firstline}\n' \
   >   --hidden
-  @  5:a7a6f2b5d8a5@default(unstable/secret) add d
+  @  5:a7a6f2b5d8a5@default(unstable/draft) add d
   |
   | o  4:725c380fe99b@default(stable/draft) add obsol_c'
   | |
-  o |  3:0d3f46688ccc@default(suspended/secret) add obsol_c
+  x |  3:0d3f46688ccc@default(suspended/draft) add obsol_c
   |/
-  | o  2:4538525df7e2@default(extinct/secret) add c
+  | x  2:4538525df7e2@default(extinct/draft) add c
   |/
   o  1:7c3bad9141dc@default(stable/draft) add b
   |
@@ -144,11 +159,13 @@
 
   $ hg init ../other-new
   $ hg phase --draft 'secret() - extinct()' # until we fix exclusion
+  abort: empty revision set
+  [255]
   $ hg push ../other-new
   pushing to ../other-new
   searching for changes
   abort: push includes an unstable changeset: a7a6f2b5d8a5!
-  (use 'hg stabilize' to get a stable history (or --force to proceed))
+  (use 'hg stabilize' to get a stable history or --force to ignore warnings)
   [255]
   $ hg push -f ../other-new
   pushing to ../other-new
@@ -182,7 +199,7 @@
   $ mkcommit obsol_d # 6
   created new head
   1 new unstables changesets
-  $ hg debugobsolete 6 5
+  $ hg debugobsolete `getid 5` `getid 6`
   $ qlog
   6
   - 95de7fc6918d
@@ -201,7 +218,7 @@
   pushing to ../other-new
   searching for changes
   abort: push includes an unstable changeset: 95de7fc6918d!
-  (use 'hg stabilize' to get a stable history (or --force to proceed))
+  (use 'hg stabilize' to get a stable history or --force to ignore warnings)
   [255]
   $ hg push ../other-new -f # use f because there is unstability
   pushing to ../other-new
@@ -230,7 +247,7 @@
   $ hg push ../other-new
   pushing to ../other-new
   searching for changes
-  no changes found (ignored 0 secret changesets)
+  no changes found
   [1]
 
   $ hg up -q .^ # 3
@@ -238,7 +255,7 @@
   $ mkcommit "obsol_d'" # 7
   created new head
   1 new unstables changesets
-  $ hg debugobsolete 7 6
+  $ hg debugobsolete `getid 6` `getid 7`
   $ hg pull -R ../other-new .
   pulling from .
   searching for changes
@@ -261,55 +278,58 @@
 
 pushing to stuff that doesn't support obsolete
 
-  $ hg init ../other-old
-  > # XXX I don't like this but changeset get published otherwise
-  > # remove it when we will get a --keep-state flag for push
-  $ echo '[extensions]'  > ../other-old/.hg/hgrc
-  $ echo "obsolete=!$(echo $(dirname $TESTDIR))/obsolete.py" >> ../other-old/.hg/hgrc
-  $ hg push ../other-old
-  pushing to ../other-old
-  searching for changes
-  abort: push includes an unstable changeset: 909a0fb57e5d!
-  (use 'hg stabilize' to get a stable history (or --force to proceed))
-  [255]
-  $ hg push -f ../other-old
-  pushing to ../other-old
-  searching for changes
-  adding changesets
-  adding manifests
-  adding file changes
-  added 5 changesets with 5 changes to 5 files (+1 heads)
-  $ qlog -R ../other-old
-  4
-  - 909a0fb57e5d
-  3
-  - 725c380fe99b
-  2
-  - 0d3f46688ccc
-  1
-  - 7c3bad9141dc
-  0
-  - 1f0dee641bb7
+DISABLED. the _enable switch it global :-/
+
+..  $ hg init ../other-old
+..  > # XXX I don't like this but changeset get published otherwise
+..  > # remove it when we will get a --keep-state flag for push
+..  $ echo '[extensions]'  > ../other-old/.hg/hgrc
+..  $ echo "obsolete=!$(echo $(dirname $TESTDIR))/obsolete.py" >> ../other-old/.hg/hgrc
+..  $ hg push ../other-old
+..  pushing to ../other-old
+..  searching for changes
+..  abort: push includes an unstable changeset: 909a0fb57e5d!
+..  (use 'hg stabilize' to get a stable history or --force to ignore warnings)
+..  [255]
+..  $ hg push -f ../other-old
+..  pushing to ../other-old
+..  searching for changes
+..  adding changesets
+..  adding manifests
+..  adding file changes
+..  added 5 changesets with 5 changes to 5 files (+1 heads)
+..  $ qlog -R ../other-ol
+..  4
+..  - 909a0fb57e5d
+..  3
+..  - 725c380fe99b
+..  2
+..  - 0d3f46688ccc
+..  1
+..  - 7c3bad9141dc
+..  0
+..  - 1f0dee641bb7
 
 clone support
 
   $ hg clone . ../cloned
   > # The warning should go away once we have default value to set ready before we pull
-  requesting all changes
-  adding changesets
-  adding manifests
-  adding file changes
-  added 5 changesets with 5 changes to 5 files (+1 heads)
   updating to branch default
   4 files updated, 0 files merged, 0 files removed, 0 files unresolved
 
-  $ qlog -R ../cloned
+  $ qlog -R ../cloned --hidden
+  7
+  - 909a0fb57e5d
+  6
+  - 95de7fc6918d
+  5
+  - a7a6f2b5d8a5
   4
-  - 909a0fb57e5d
+  - 725c380fe99b
   3
-  - 725c380fe99b
+  - 0d3f46688ccc
   2
-  - 0d3f46688ccc
+  - 4538525df7e2
   1
   - 7c3bad9141dc
   0
@@ -322,7 +342,7 @@
   $ mkcommit "obsol_d''"
   created new head
   1 new unstables changesets
-  $ hg debugobsolete 8 7
+  $ hg debugobsolete `getid 7` `getid 8`
   $ cd ../other-new
   $ hg up -q 3
   $ hg pull ../local/
@@ -379,8 +399,10 @@
   created new head
   $ hg id -n
   9
-  $ hg debugobsolete 9 0
-  83b5778897ad try to obsolete immutable changeset 1f0dee641bb7
+  $ hg debugobsolete `getid 0` `getid 9`
+83b5778897ad try to obsolete immutable changeset 1f0dee641bb7
+# at core level the warning is not issued
+# this is now a big issue now that we have latecomer warning
   $ qlog -r 'obsolete()'
   3
   - 0d3f46688ccc
@@ -400,7 +422,7 @@
   0
   - 1f0dee641bb7
 
-  $ hg debugobsolete null 9 #kill
+  $ hg debugobsolete `getid 9` #kill
   $ hg up null -q # to be not based on 9 anymore
   $ qlog
   8
@@ -421,7 +443,7 @@
   |
   | o  4 - 725c380fe99b
   | |
-  o |  3 - 0d3f46688ccc
+  x |  3 - 0d3f46688ccc
   |/
   o  1 - 7c3bad9141dc
   |
@@ -429,21 +451,21 @@
   
 
   $ hg glog  --template='{rev} - {node|short}\n' `(hg --version | grep -q 'version 2.1') ||  echo '--hidden'`
-  o  9 - 83b5778897ad
+  x  9 - 83b5778897ad
   
   o  8 - 159dfc9fa5d3
   |
-  | o  7 - 909a0fb57e5d
+  | x  7 - 909a0fb57e5d
   |/
-  | o  6 - 95de7fc6918d
+  | x  6 - 95de7fc6918d
   |/
-  | o  5 - a7a6f2b5d8a5
+  | x  5 - a7a6f2b5d8a5
   |/
   | o  4 - 725c380fe99b
   | |
-  o |  3 - 0d3f46688ccc
+  x |  3 - 0d3f46688ccc
   |/
-  | o  2 - 4538525df7e2
+  | x  2 - 4538525df7e2
   |/
   o  1 - 7c3bad9141dc
   |
@@ -477,7 +499,7 @@
   $ hg up -q 10
   $ mkcommit "obsol_d'''"
   created new head
-  $ hg debugobsolete 12 11
+  $ hg debugobsolete `getid 11` `getid 12`
   $ hg push ../other-new --traceback
   pushing to ../other-new
   searching for changes
@@ -517,8 +539,8 @@
   $ hg push ../other-new/
   pushing to ../other-new/
   searching for changes
-  abort: push includes an latecomer changeset: 6db5e282cb91!
-  (use 'hg stabilize' to get a stable history (or --force to proceed))
+  abort: push includes a latecomer changeset: 6db5e282cb91!
+  (use 'hg stabilize' to get a stable history or --force to ignore warnings)
   [255]
 
 Check hg commit --amend compat
@@ -578,7 +600,7 @@
   159dfc9fa5d3 9468a5f5d8b2
   1f0dee641bb7 83b5778897ad
   4538525df7e2 0d3f46688ccc
-  83b5778897ad 000000000000
+  83b5778897ad
   909a0fb57e5d 159dfc9fa5d3
   9468a5f5d8b2 6db5e282cb91
   95de7fc6918d 909a0fb57e5d
@@ -595,7 +617,7 @@
   branch: default
   commit: (clean)
   update: 9 new changesets, 9 branch heads (merge)
-  $ hg debugobsolete 50f11e5e3a63 a7a6f2b5d8a5
+  $ hg debugobsolete `getid a7a6f2b5d8a5` `getid 50f11e5e3a63`
   $ hg log -r 'conflicting()'
   changeset:   14:50f11e5e3a63
   tag:         tip
--- a/tests/test-qsync.t
+++ b/tests/test-qsync.t
@@ -182,7 +182,6 @@
   pulling from ../local2
   searching for changes
   no changes found
-  (run 'hg update' to get a working copy)
   $ hg pull --mq ../local2/.hg/patches
   pulling from ../local2/.hg/patches
   searching for changes
--- a/tests/test-stabilize-order.t
+++ b/tests/test-stabilize-order.t
@@ -54,9 +54,9 @@
   | |
   | | o  3:7a7552255fb5@default(draft) addc
   | | |
-  | | o  2:ef23d6ef94d6@default(draft) addb
+  | | x  2:ef23d6ef94d6@default(draft) addb
   | |/
-  | o  1:93418d2c0979@default(draft) adda
+  | x  1:93418d2c0979@default(draft) adda
   |/
   o  0:c471ef929e6a@default(draft) addroot
   
@@ -77,9 +77,9 @@
   |
   | o  3:7a7552255fb5@default(draft) addc
   | |
-  | o  2:ef23d6ef94d6@default(draft) addb
+  | x  2:ef23d6ef94d6@default(draft) addb
   | |
-  | o  1:93418d2c0979@default(draft) adda
+  | x  1:93418d2c0979@default(draft) adda
   |/
   o  0:c471ef929e6a@default(draft) addroot
   
@@ -135,7 +135,7 @@
   |
   | o  9:5e819fbb0d27@default(draft) addc
   | |
-  | o  8:6bf44048e43f@default(draft) addb
+  | x  8:6bf44048e43f@default(draft) addb
   |/
   o  7:f5ff10856e5a@default(draft) adda
   |
--- a/tests/test-stabilize-result.t
+++ b/tests/test-stabilize-result.t
@@ -37,11 +37,11 @@
   $ glog --hidden
   @  4:1447e1c4828d@default(draft) bk:[changea] changea
   |
-  | o  3:41ad4fe8c795@default(secret) bk:[] amends 102a90ea7b4a3361e4082ed620918c261189a36a
+  | x  3:41ad4fe8c795@default(draft) bk:[] amends 102a90ea7b4a3361e4082ed620918c261189a36a
   | |
-  | | o  2:cce2c55b8965@default(secret) bk:[] changea
+  | | x  2:cce2c55b8965@default(draft) bk:[] changea
   | |/
-  | o  1:102a90ea7b4a@default(secret) bk:[] addb
+  | x  1:102a90ea7b4a@default(draft) bk:[] addb
   |/
   o  0:07f494440405@default(draft) bk:[] adda
   
--- a/tests/test-uncommit.t
+++ b/tests/test-uncommit.t
@@ -220,7 +220,7 @@
   $ glog --hidden
   @  4:e8db4aa611f6@bar(stable/draft) touncommit
   |
-  | o  3:5eb72dbe0cb4@bar(extinct/secret) touncommit
+  | x  3:5eb72dbe0cb4@bar(extinct/draft) touncommit
   |/
   o    2:f63b90038565@default(stable/draft) merge
   |\
@@ -263,11 +263,11 @@
   R m
   R n
   $ glog --hidden
-  @  5:c706fe2c12f8@bar(stable/secret) touncommit
+  @  5:c706fe2c12f8@bar(stable/draft) touncommit
   |
   | o  4:e8db4aa611f6@bar(stable/draft) touncommit
   |/
-  | o  3:5eb72dbe0cb4@bar(extinct/secret) touncommit
+  | x  3:5eb72dbe0cb4@bar(extinct/draft) touncommit
   |/
   o    2:f63b90038565@default(stable/draft) merge
   |\