changeset 861:b6337585ae25

merged 3.3 release into default Some of the default content was released in 3.3.0 the other ones are moved to 3.4
author Pierre-Yves David <pierre-yves.david@fb.com>
date Tue, 04 Mar 2014 11:31:11 -0800
parents 86b826399dfd (diff) f3263e022ba8 (current diff)
children f954e331d511
files README hgext/evolve.py
diffstat 35 files changed, 4744 insertions(+), 39 deletions(-) [+]
line wrap: on
line diff
--- a/README	Tue Mar 04 11:14:24 2014 -0800
+++ b/README	Tue Mar 04 11:31:11 2014 -0800
@@ -42,10 +42,12 @@
 Changelog
 =========
 
+3.4.0 --
+
+- added Augie Facklers `fastop` extension (usage not recommended yet)
+
 3.3.0 -- 2014-03-04
 
-- drop `latercomer` and `conflicting` compatibility. Those old alias are
-  deprecated for a long time now.
 - add verbose hint about how to handle corner case by hand.
   This should help people until evolve is able to to it itself.
 - removed the qsync extension. The only user I knew about (logilab) is not
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hgext/drophack.py	Tue Mar 04 11:31:11 2014 -0800
@@ -0,0 +1,162 @@
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+'''This extension add a hacky command to drop changeset during review
+
+This extension is intended as a temporary hack to allow Matt Mackall to use
+evolve in the Mercurial review it self. You should probably not use it if your
+name is not Matt Mackall.
+'''
+
+import os
+import time
+import contextlib
+
+from mercurial.i18n import _
+from mercurial import cmdutil
+from mercurial import repair
+from mercurial import scmutil
+from mercurial import lock as lockmod
+from mercurial import util
+from mercurial import commands
+
+cmdtable = {}
+command = cmdutil.command(cmdtable)
+
+
+@contextlib.contextmanager
+def timed(ui, caption):
+    ostart = os.times()
+    cstart = time.time()
+    yield
+    cstop = time.time()
+    ostop = os.times()
+    wall = cstop - cstart
+    user = ostop[0] - ostart[0]
+    sys  = ostop[1] - ostart[1]
+    comb = user + sys
+    ui.write("%s: wall %f comb %f user %f sys %f\n"
+             % (caption, wall, comb, user, sys))
+
+def obsmarkerchainfrom(obsstore, nodes):
+    """return all marker chain starting from node
+
+    Starting from mean "use as successors"."""
+    # XXX need something smarter for descendant of bumped changeset
+    seennodes = set(nodes)
+    seenmarkers = set()
+    pendingnodes = set(nodes)
+    precursorsmarkers = obsstore.precursors
+    while pendingnodes:
+        current = pendingnodes.pop()
+        new = set()
+        for precmark in precursorsmarkers.get(current, ()):
+            if precmark in seenmarkers:
+                continue
+            seenmarkers.add(precmark)
+            new.add(precmark[0])
+            yield precmark
+        new -= seennodes
+        pendingnodes |= new
+
+def stripmarker(ui, repo, markers):
+    """remove <markers> from the repo obsstore
+
+    The old obsstore content is saved in a `obsstore.prestrip` file
+    """
+    repo = repo.unfiltered()
+    repo.destroying()
+    oldmarkers = list(repo.obsstore._all)
+    util.rename(repo.sjoin('obsstore'),
+                repo.join('obsstore.prestrip'))
+    del repo.obsstore # drop the cache
+    newstore = repo.obsstore
+    assert not newstore # should be empty after rename
+    newmarkers = [m for m in oldmarkers if m not in markers]
+    tr = repo.transaction('drophack')
+    try:
+        newstore.add(tr, newmarkers)
+        tr.close()
+    finally:
+        tr.release()
+    repo.destroyed()
+
+
+@command('drop', [('r', 'rev', [], 'revision to update')], _('[-r] revs'))
+def cmddrop(ui, repo, *revs, **opts):
+    """I'm hacky do not use me!
+
+    This command strip a changeset, its precursors and all obsolescence marker
+    associated to its chain.
+
+    There is no way to limit the extend of the purge yet. You may have to
+    repull from other source to get some changeset and obsolescence marker
+    back.
+
+    This intended for Matt Mackall usage only. do not use me.
+    """
+    revs = list(revs)
+    revs.extend(opts['rev'])
+    if not revs:
+        revs = ['.']
+    # get the changeset
+    revs = scmutil.revrange(repo, revs)
+    if not revs:
+        ui.write_err('no revision to drop\n')
+        return 1
+    # lock from the beginning to prevent race
+    wlock = lock = None
+    try:
+        lock = repo.wlock()
+        lock = repo.lock()
+        # check they have no children
+        if repo.revs('%ld and public()', revs):
+            ui.write_err('cannot drop public revision')
+            return 1
+        if repo.revs('children(%ld) - %ld', revs, revs):
+            ui.write_err('cannot drop revision with children')
+            return 1
+        if repo.revs('. and %ld', revs):
+            newrevs = repo.revs('max(::. - %ld)', revs)
+            if newrevs:
+                assert len(newrevs) == 1
+                newrev = newrevs[0]
+            else:
+                newrev = -1
+            commands.update(ui, repo, newrev)
+            ui.status(_('working directory now at %s\n') % repo[newrev])
+        # get all markers and successors up to root
+        nodes = [repo[r].node() for r in revs]
+        with timed(ui, 'search obsmarker'):
+            markers = set(obsmarkerchainfrom(repo.obsstore, nodes))
+        ui.write('%i obsmarkers found\n' % len(markers))
+        cl = repo.unfiltered().changelog
+        with timed(ui, 'search nodes'):
+            allnodes = set(nodes)
+            allnodes.update(m[0] for m in markers if cl.hasnode(m[0]))
+        ui.write('%i nodes found\n' % len(allnodes))
+        cl = repo.changelog
+        visiblenodes = set(n for n in allnodes if cl.hasnode(n))
+        # check constraint again
+        if repo.revs('%ln and public()', visiblenodes):
+            ui.write_err('cannot drop public revision')
+            return 1
+        if repo.revs('children(%ln) - %ln', visiblenodes, visiblenodes):
+            ui.write_err('cannot drop revision with children')
+            return 1
+
+        if markers:
+            # strip them
+            with timed(ui, 'strip obsmarker'):
+                stripmarker(ui, repo, markers)
+        # strip the changeset
+        with timed(ui, 'strip nodes'):
+            repair.strip(ui, repo, allnodes, backup="all", topic='drophack')
+
+    finally:
+        lockmod.release(lock, wlock)
+
+    # rewrite the whole file.
+    # print data.
+    # - time to compute the chain
+    # - time to strip the changeset
+    # - time to strip the obs marker.
--- a/hgext/evolve.py	Tue Mar 04 11:14:24 2014 -0800
+++ b/hgext/evolve.py	Tue Mar 04 11:31:11 2014 -0800
@@ -24,6 +24,8 @@
 
 import sys
 import random
+from StringIO import StringIO
+import struct
 
 import mercurial
 from mercurial import util
@@ -40,12 +42,14 @@
 
 
 
+from mercurial import base85
 from mercurial import bookmarks
 from mercurial import cmdutil
 from mercurial import commands
 from mercurial import context
 from mercurial import copies
 from mercurial import error
+from mercurial import exchange
 from mercurial import extensions
 from mercurial import hg
 from mercurial import lock as lockmod
@@ -58,7 +62,10 @@
 from mercurial.i18n import _
 from mercurial.commands import walkopts, commitopts, commitopts2
 from mercurial.node import nullid
+from mercurial import wireproto
+from mercurial import localrepo
 
+_pack = struct.pack
 
 
 # This extension contains the following code
@@ -301,6 +308,56 @@
 reposetup = eh.final_reposetup
 
 #####################################################################
+### experimental behavior                                         ###
+#####################################################################
+
+@eh.wrapfunction(mercurial.obsolete, 'createmarkers')
+def _createmarkers(orig, repo, relations, *args, **kwargs):
+    """register parent information at prune time"""
+    # every time this test is run, a kitten is slain.
+    # Change it as soon as possible
+    if '[,{metadata}]' in orig.__doc__:
+        for idx, rel in enumerate(relations):
+            prec = rel[0]
+            sucs = rel[1]
+            if not sucs:
+                meta = {}
+                if 2 < len(rel):
+                    meta.update(rel[2])
+                for i, p in enumerate(prec.parents(), 1):
+                    meta['p%i' % i] = p.hex()
+                relations[idx] = (prec, sucs, meta)
+    return orig(repo, relations, *args, **kwargs)
+
+def createmarkers(*args, **kwargs):
+    return obsolete.createmarkers(*args, **kwargs)
+
+class pruneobsstore(obsolete.obsstore):
+
+    def __init__(self, *args, **kwargs):
+        self.prunedchildren = {}
+        return super(pruneobsstore, self).__init__(*args, **kwargs)
+
+    def _load(self, markers):
+        markers = self._prunedetectingmarkers(markers)
+        return super(pruneobsstore, self)._load(markers)
+
+
+    def _prunedetectingmarkers(self, markers):
+        for m in markers:
+            if not m[1]: # no successors
+                meta = obsolete.decodemeta(m[3])
+                if 'p1' in meta:
+                    p1 = node.bin(meta['p1'])
+                    self.prunedchildren.setdefault(p1, set()).add(m)
+                if 'p2' in meta:
+                    p2 = node.bin(meta['p2'])
+                    self.prunedchildren.setdefault(p2, set()).add(m)
+            yield m
+
+obsolete.obsstore = pruneobsstore
+
+#####################################################################
 ### Critical fix                                                  ###
 #####################################################################
 
@@ -337,8 +394,6 @@
 # - function to travel throught the obsolescence graph
 # - function to find useful changeset to stabilize
 
-createmarkers = obsolete.createmarkers
-
 
 ### Useful alias
 
@@ -634,7 +689,6 @@
     except KeyError:
         pass  # rebase not found
 
-
 #####################################################################
 ### Old Evolve extension content                                  ###
 #####################################################################
@@ -812,6 +866,167 @@
      _('record the specified user in metadata'), _('USER')),
 ]
 
+@command('debugrecordpruneparents', [], '')
+def cmddebugrecordpruneparents(ui, repo):
+    """add parents data to prune markers when possible
+
+    This commands search the repo for prune markers without parent information.
+    If the pruned node is locally known, a new markers with parent data is
+    created."""
+    pgop = 'reading markers'
+
+    # lock from the beginning to prevent race
+    wlock = lock = tr = None
+    try:
+        wlock = repo.wlock()
+        lock = repo.lock()
+        tr = repo.transaction('recordpruneparents')
+        unfi = repo.unfiltered()
+        nm = unfi.changelog.nodemap
+        store = repo.obsstore
+        pgtotal = len(store._all)
+        for idx, mark in enumerate(list(store._all)):
+            if not mark[1]:
+                rev = nm.get(mark[0])
+                if rev is not None:
+                    ctx = unfi[rev]
+                    meta = obsolete.decodemeta(mark[3])
+                    for i, p in enumerate(ctx.parents(), 1):
+                        meta['p%i' % i] = p.hex()
+                    before = len(store._all)
+                    store.create(tr, mark[0], mark[1], mark[2], meta)
+                    if len(store._all) - before:
+                        ui.write('created new markers for %i\n' % rev)
+            ui.progress(pgop, idx, total=pgtotal)
+        tr.close()
+        ui.progress(pgop, None)
+    finally:
+        if tr is not None:
+            tr.release()
+        lockmod.release(lock, wlock)
+
+@command('debugobsstorestat', [], '')
+def cmddebugobsstorestat(ui, repo):
+    """print statistic about obsolescence markers in the repo"""
+    store = repo.obsstore
+    unfi = repo.unfiltered()
+    nm = unfi.changelog.nodemap
+    ui.write('markers total:              %9i\n' % len(store._all))
+    sucscount = [0, 0 , 0, 0]
+    known = 0
+    parentsdata = 0
+    metatotallenght = 0
+    metakeys = {}
+    # node -> cluster mapping
+    #   a cluster is a (set(nodes), set(markers)) tuple
+    clustersmap = {}
+    # same data using parent information
+    pclustersmap= {}
+    for mark in store:
+        if mark[0] in nm:
+            known += 1
+        nbsucs = len(mark[1])
+        sucscount[min(nbsucs, 3)] += 1
+        metatotallenght += len(mark[3])
+        meta = obsolete.decodemeta(mark[3])
+        for key in meta:
+            metakeys.setdefault(key, 0)
+            metakeys[key] += 1
+        parents = [meta.get('p1'), meta.get('p2')]
+        parents = [node.bin(p) for p in parents if p is not None]
+        if parents:
+            parentsdata += 1
+        # cluster handling
+        nodes = set()
+        nodes.add(mark[0])
+        nodes.update(mark[1])
+        c = (set(nodes), set([mark]))
+
+        toproceed = set(nodes)
+        while toproceed:
+            n = toproceed.pop()
+            other = clustersmap.get(n)
+            if (other is not None
+                and other is not c):
+                other[0].update(c[0])
+                other[1].update(c[1])
+                for on in c[0]:
+                    if on in toproceed:
+                        continue
+                    clustersmap[on] = other
+                c = other
+            clustersmap[n] = c
+        # same with parent data
+        nodes.update(parents)
+        c = (set(nodes), set([mark]))
+        toproceed = set(nodes)
+        while toproceed:
+            n = toproceed.pop()
+            other = pclustersmap.get(n)
+            if (other is not None
+                and other is not c):
+                other[0].update(c[0])
+                other[1].update(c[1])
+                for on in c[0]:
+                    if on in toproceed:
+                        continue
+                    pclustersmap[on] = other
+                c = other
+            pclustersmap[n] = c
+
+    # freezing the result
+    for c in clustersmap.values():
+        fc = (frozenset(c[0]), frozenset(c[1]))
+        for n in fc[0]:
+            clustersmap[n] = fc
+    # same with parent data
+    for c in pclustersmap.values():
+        fc = (frozenset(c[0]), frozenset(c[1]))
+        for n in fc[0]:
+            pclustersmap[n] = fc
+    ui.write('    for known precursors:   %9i\n' % known)
+    ui.write('    with parents data:      %9i\n' % parentsdata)
+    # successors data
+    ui.write('markers with no successors: %9i\n' % sucscount[0])
+    ui.write('              1 successors: %9i\n' % sucscount[1])
+    ui.write('              2 successors: %9i\n' % sucscount[2])
+    ui.write('    more than 2 successors: %9i\n' % sucscount[3])
+    # meta data info
+    ui.write('average meta length:        %9i\n'
+             % (metatotallenght/len(store._all)))
+    ui.write('    available  keys:\n')
+    for key in sorted(metakeys):
+        ui.write('    %15s:        %9i\n' % (key, metakeys[key]))
+
+    allclusters = list(set(clustersmap.values()))
+    allclusters.sort(key=lambda x: len(x[1]))
+    ui.write('disconnected clusters:      %9i\n' % len(allclusters))
+
+    ui.write('        any known node:     %9i\n'
+             % len([c for c in allclusters
+                    if [n for n in c[0] if nm.get(n) is not None]]))
+    if allclusters:
+        nbcluster = len(allclusters)
+        ui.write('        smallest length:    %9i\n' % len(allclusters[0][1]))
+        ui.write('        longer length:      %9i\n' % len(allclusters[-1][1]))
+        median = len(allclusters[nbcluster//2][1])
+        ui.write('        median length:      %9i\n' % median)
+        mean = sum(len(x[1]) for x in allclusters) // nbcluster
+        ui.write('        mean length:        %9i\n' % mean)
+    allpclusters = list(set(pclustersmap.values()))
+    allpclusters.sort(key=lambda x: len(x[1]))
+    ui.write('    using parents data:     %9i\n' % len(allpclusters))
+    ui.write('        any known node:     %9i\n'
+             % len([c for c in allclusters
+                    if [n for n in c[0] if nm.get(n) is not None]]))
+    if allpclusters:
+        nbcluster = len(allpclusters)
+        ui.write('        smallest length:    %9i\n' % len(allpclusters[0][1]))
+        ui.write('        longer length:      %9i\n' % len(allpclusters[-1][1]))
+        median = len(allpclusters[nbcluster//2][1])
+        ui.write('        median length:      %9i\n' % median)
+        mean = sum(len(x[1]) for x in allpclusters) // nbcluster
+        ui.write('        mean length:        %9i\n' % mean)
 
 @command('^evolve|stabilize|solve',
     [('n', 'dry-run', False, 'do not perform actions, print what to be done'),
@@ -1822,3 +2037,275 @@
     entry[1].append(('O', 'old-obsolete', False,
                      _("make graft obsoletes its source")))
 
+#####################################################################
+### Obsolescence marker exchange experimenation                   ###
+#####################################################################
+
+@command('debugobsoleterelevant',
+         [],
+         'REVSET')
+def debugobsoleterelevant(ui, repo, *revsets):
+    """print allobsolescence marker relevant to a set of revision"""
+    nodes = [ctx.node() for ctx in repo.set('%lr', revsets)]
+    markers = repo.obsstore.relevantmarkers(nodes)
+    for rawmarker in sorted(markers):
+        marker = obsolete.marker(repo, rawmarker)
+        cmdutil.showmarker(ui, marker)
+
+@eh.addattr(obsolete.obsstore, 'relevantmarkers')
+def relevantmarkers(self, nodes):
+    """return a set of all obsolescence marker relevant to a set of node.
+
+    "relevant" to a set of node mean:
+
+    - marker that use this changeset as successors
+    - prune marker of direct children on this changeset.
+    - recursive application of the two rules on precursors of these markers
+
+    It  a set so you cannot rely on order"""
+    seennodes = set(nodes)
+    seenmarkers = set()
+    pendingnodes = set(nodes)
+    precursorsmarkers = self.precursors
+    prunedchildren = self.prunedchildren
+    while pendingnodes:
+        direct = set()
+        for current in pendingnodes:
+            direct.update(precursorsmarkers.get(current, ()))
+            direct.update(prunedchildren.get(current, ()))
+        direct -= seenmarkers
+        pendingnodes = set([m[0] for m in direct])
+        seenmarkers |= direct
+        pendingnodes -= seennodes
+        seennodes |= pendingnodes
+    return seenmarkers
+
+
+_pushkeyescape = getattr(obsolete, '_pushkeyescape', None)
+if _pushkeyescape is None:
+    _maxpayload = 5300
+    def _pushkeyescape(markers):
+        """encode markers into a dict suitable for pushkey exchange
+
+        - binary data are base86 encoded
+        - splited in chunk less than 5300 bytes"""
+        parts = []
+        currentlen = _maxpayload * 2  # ensure we create a new part
+        for marker in markers:
+            nextdata = obsolete._encodeonemarker(marker)
+            if (len(nextdata) + currentlen > _maxpayload):
+                currentpart = []
+                currentlen = 0
+                parts.append(currentpart)
+            currentpart.append(nextdata)
+            currentlen += len(nextdata)
+        keys = {}
+        for idx, part in enumerate(reversed(parts)):
+            data = ''.join([_pack('>B', 0)] + part)
+            keys['dump%i' % idx] = base85.b85encode(data)
+        return keys
+
+def _encodemarkersstream(fp, markers):
+    fp.write(_pack('>B', 0))
+    for mark in markers:
+        fp.write(obsolete._encodeonemarker(mark))
+
+class pushobsmarkerStringIO(StringIO):
+    """hacky string io for progress"""
+
+    @util.propertycache
+    def _length(self):
+        return len(self.getvalue())
+
+    def read(self, size):
+        self.ui.progress('OBSEXC', self.tell(), unit="bytes",
+                         total=self._length)
+        return StringIO.read(self, size)
+
+
+
+@eh.wrapfunction(exchange, '_pushobsolete')
+def _pushobsolete(orig, pushop):
+    """utility function to push obsolete markers to a remote"""
+    pushop.ui.debug('try to push obsolete markers to remote\n')
+    repo = pushop.repo
+    remote = pushop.remote
+    unfi = repo.unfiltered()
+    if (obsolete._enabled and repo.obsstore and
+        'obsolete' in remote.listkeys('namespaces')):
+        repo.ui.status("OBSEXC: computing relevant nodes\n")
+        nodes = [ctx.node() for ctx in unfi.set('::%ln', pushop.commonheads)]
+        repo.ui.status("OBSEXC: computing markers relevant to %i nodes\n"
+                       % len(nodes))
+        markers = repo.obsstore.relevantmarkers(nodes)
+        if remote.capable('_evoext_pushobsmarkers_0'):
+            repo.ui.status("OBSEXC: writing %i markers\n" % len(markers))
+            obsdata = pushobsmarkerStringIO()
+            _encodemarkersstream(obsdata, markers)
+            obsdata.seek(0)
+            obsdata.ui = repo.ui
+            repo.ui.status("OBSEXC: pushing %i bytes\n"
+                           % len(obsdata.getvalue()))
+            remote.evoext_pushobsmarkers_0(obsdata)
+            repo.ui.progress('OBSEXC', None)
+        else:
+            rslts = []
+            repo.ui.status("OBSEXC: encoding %i markers\n" % len(markers))
+            remotedata = _pushkeyescape(markers).items()
+            totalbytes = sum(len(d) for k,d in remotedata)
+            sentbytes = 0
+            repo.ui.status("OBSEXC: sending %i pushkey payload (%i bytes)\n"
+                            % (len(remotedata), totalbytes))
+            for key, data in remotedata:
+                repo.ui.progress('OBSEXC', sentbytes, item=key, unit="bytes",
+                                 total=totalbytes)
+                rslts.append(remote.pushkey('obsolete', key, '', data))
+                sentbytes += len(data)
+                repo.ui.progress('OBSEXC', sentbytes, item=key, unit="bytes",
+                                 total=totalbytes)
+            repo.ui.progress('OBSEXC', None)
+            if [r for r in rslts if not r]:
+                msg = _('failed to push some obsolete markers!\n')
+                repo.ui.warn(msg)
+        repo.ui.status("OBSEXC: DONE\n")
+
+
+@eh.addattr(wireproto.wirepeer, 'evoext_pushobsmarkers_0')
+def client_pushobsmarkers(self, obsfile):
+    """wireprotocol peer method"""
+    self.requirecap('_evoext_pushobsmarkers_0',
+                    _('push obsolete markers faster'))
+    ret, output = self._callpush('evoext_pushobsmarkers_0', obsfile)
+    for l in output.splitlines(True):
+        self.ui.status(_('remote: '), l)
+    return ret
+
+
+def srv_pushobsmarkers(repo, proto):
+    """wireprotocol command"""
+    fp = StringIO()
+    proto.redirect()
+    proto.getfile(fp)
+    data = fp.getvalue()
+    fp.close()
+    lock = repo.lock()
+    try:
+        tr = repo.transaction('pushkey: obsolete markers')
+        try:
+            repo.obsstore.mergemarkers(tr, data)
+            tr.close()
+        finally:
+            tr.release()
+    finally:
+        lock.release()
+    return wireproto.pushres(0)
+
+def _buildpullobsmerkersboundaries(pullop):
+    """small funtion returning the argument for pull markers call
+    may to contains 'heads' and 'common'. skip the key for None.
+
+    Its a separed functio to play around with strategy for that."""
+    return {'heads': pullop.pulledsubset}
+
+
+@eh.wrapfunction(exchange, '_pullobsolete')
+def _pullobsolete(orig, pullop):
+    if not obsolete._enabled:
+        return None
+    if not pullop.remote.capable('_evoext_pullobsmarkers_0'):
+        return orig(pullop)
+    tr = None
+    ui = pullop.repo.ui
+    ui.status("OBSEXC: pull obsolescence markers\n")
+    boundaries = _buildpullobsmerkersboundaries(pullop)
+    obsdata = pullop.remote.evoext_pullobsmarkers_0(**boundaries)
+    obsdata = obsdata.read()
+    if len(obsdata) > 5:
+        ui.status("OBSEXC: merging obsolescence markers (%i bytes)\n"
+                       % len(obsdata))
+        tr = pullop.gettransaction()
+        old = len(pullop.repo.obsstore._all)
+        pullop.repo.obsstore.mergemarkers(tr, obsdata)
+        new = len(pullop.repo.obsstore._all) - old
+        ui.status("OBSEXC: %i markers added\n" % new)
+        if new:
+            pullop.repo.invalidatevolatilesets()
+    ui.status("OBSEXC: DONE\n")
+    return tr
+
+def _getobsmarkersstream(repo, heads=None, common=None):
+    revset = ''
+    args = []
+    repo = repo.unfiltered()
+    if heads is None:
+        revset = 'all()'
+    elif heads:
+        revset += "(::%ln)"
+        args.append(heads)
+    else:
+        assert False, 'pulling no heads?'
+    if common:
+        revset += ' - (::%ln)'
+        args.append(common)
+    nodes = [c.node() for c in repo.set(revset, *args)]
+    markers = repo.obsstore.relevantmarkers(nodes)
+    obsdata = StringIO()
+    _encodemarkersstream(obsdata, markers)
+    obsdata.seek(0)
+    return obsdata
+
+@eh.addattr(wireproto.wirepeer, 'evoext_pullobsmarkers_0')
+def client_pullobsmarkers(self, heads=None, common=None):
+    self.requirecap('_evoext_pullobsmarkers_0', _('look up remote obsmarkers'))
+    opts = {}
+    if heads is not None:
+        opts['heads'] = wireproto.encodelist(heads)
+    if common is not None:
+        opts['common'] = wireproto.encodelist(common)
+    f = self._callstream("evoext_pullobsmarkers_0", **opts)
+    f = self._decompress(f)
+    length= int(f.read(20))
+    chunk = 4096
+    current = 0
+    data = StringIO()
+    ui = self.ui
+    ui.progress('OBSEXC', current, unit="bytes", total=length)
+    while current < length:
+        readsize = min(length-current, chunk)
+        data.write(f.read(readsize))
+        current += readsize
+        ui.progress('OBSEXC', current, unit="bytes", total=length)
+    ui.progress('OBSEXC', None)
+    return data
+
+@eh.addattr(localrepo.localpeer, 'evoext_pullobsmarkers_0')
+def local_pullobsmarkers(self, heads=None, common=None):
+    return _getobsmarkersstream(self._repo, heads=heads, common=common)
+
+def srv_pullobsmarkers(repo, proto, others):
+    opts = wireproto.options('', ['heads', 'common'], others)
+    for k, v in opts.iteritems():
+        if k in ('heads', 'common'):
+            opts[k] = wireproto.decodelist(v)
+    obsdata = _getobsmarkersstream(repo, **opts)
+    length = '%20i' % len(obsdata.getvalue())
+    def data():
+        yield length
+        for c in proto.groupchunks(obsdata):
+            yield c
+    return wireproto.streamres(data())
+
+@eh.wrapfunction(wireproto, 'capabilities')
+def capabilities(orig, repo, proto):
+    """wrapper to advertise new capability"""
+    caps = orig(repo, proto)
+    if obsolete._enabled:
+        caps += ' _evoext_pushobsmarkers_0'
+        caps += ' _evoext_pullobsmarkers_0'
+    return caps
+
+@eh.extsetup
+def _installwireprotocol(ui):
+    localrepo.MODERNCAPS.add('_evoext_pullobsmarkers_0')
+    wireproto.commands['evoext_pushobsmarkers_0'] = (srv_pushobsmarkers, '')
+    wireproto.commands['evoext_pullobsmarkers_0'] = (srv_pullobsmarkers, '*')
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hgext/hgfastobs.py	Tue Mar 04 11:31:11 2014 -0800
@@ -0,0 +1,124 @@
+"""Extension to try and speed up transfer of obsolete markers.
+
+Mercurial 2.6 transfers obsolete markers in the dumbest way possible:
+it simply transfers all of them to the server on every
+operation. While this /works/, it's not ideal because it's a large
+amount of extra data for users to pull down (1.9M for the 17k obsolete
+markers in hg-crew as of this writing in late July 2013). It's also
+frustrating because this transfer takes a nontrivial amount of time.
+
+You can specify a strategy with the config knob
+obsolete.syncstrategy. Current strategies are "stock" and
+"boxfill". Default strategy is presently boxfill.
+
+:stock: use the default strategy of mercurial explaned above
+
+:boxfill: transmit obsolete markers which list any of transmitted changesets as
+          a successor (transitively), as well as any kill markers for dead
+          nodes descended from any of the precursors of outgoing.missing.
+
+TODO(durin42): consider better names for sync strategies.
+"""
+import sys
+
+from mercurial import base85
+from mercurial import commands
+from mercurial import extensions
+from mercurial import node
+from mercurial import obsolete
+from mercurial import exchange
+from mercurial import revset
+from mercurial.i18n import _
+
+_strategies = {
+    'stock': exchange._pushobsolete,
+    }
+
+def _strategy(name, default=False):
+    def inner(func):
+        _strategies[name] = func
+        if default:
+            _strategies[None] = func
+        return func
+    return inner
+
+def _pushobsoletewrapper(orig, pushop):
+    stratfn = _strategies[pushop.repo.ui.config('obsolete', 'syncstrategy')]
+    return stratfn(pushop)
+
+extensions.wrapfunction(exchange, '_pushobsolete', _pushobsoletewrapper)
+
+def _precursors(repo, s):
+    """Precursor of a changeset"""
+    cs = set()
+    nm = repo.changelog.nodemap
+    markerbysubj = repo.obsstore.precursors
+    for r in s:
+        for p in markerbysubj.get(repo[r].node(), ()):
+            pr = nm.get(p[0])
+            if pr is not None:
+                cs.add(pr)
+    return cs
+
+def _revsetprecursors(repo, subset, x):
+    s = revset.getset(repo, revset.baseset(range(len(repo))), x)
+    cs = _precursors(repo, s)
+    return revset.baseset([r for r in subset if r in cs])
+
+revset.symbols['_fastobs_precursors'] = _revsetprecursors
+
+
+@_strategy('boxfill', default=True)
+def boxfill(pushop):
+    """The "fill in the box" strategy from the 2.6 sprint.
+
+    See the notes[0] from the 2.6 sprint for what "fill in the box"
+    means here. It's a fairly subtle algorithm, which may have
+    surprising behavior at times, but was the least-bad option
+    proposed at the sprint.
+
+    [0]: https://bitbucket.org/durin42/2.6sprint-notes/src/tip/mercurial26-obsstore-rev.1398.txt
+    """
+    repo = pushop.repo
+    remote = pushop.remote
+    outgoing = pushop.outgoing
+    urepo = pushop.repo.unfiltered()
+    # need to collect obsolete markers which list any of
+    # outgoing.missing as a successor (transitively), as well as any
+    # kill markers for dead nodes descended from any of the precursors
+    # of outgoing.missing.
+    boxedges = urepo.revs(
+        '(descendants(_fastobs_precursors(%ln)) or '
+        ' descendants(%ln)) and hidden()',
+        outgoing.missing, outgoing.missing)
+    transmit = []
+    for node in outgoing.missing:
+        transmit.extend(obsolete.precursormarkers(urepo[node]))
+    for rev in boxedges:
+        transmit.extend(obsolete.successormarkers(urepo[rev]))
+    transmit = list(set(transmit))
+    xmit, total = len(transmit), len(repo.obsstore._all)
+    repo.ui.status(
+        'boxpush: about to transmit %d obsolete markers (%d markers total)\n'
+        % (xmit, total))
+    parts, size, chunk = [], 0, 0
+    def transmitmarks():
+            repo.ui.note(
+                'boxpush: sending a chunk of obsolete markers\n')
+            data = ''.join([obsolete._pack('>B', obsolete._fmversion)] + parts)
+            remote.pushkey('obsolete', 'dump-%d' % chunk, '',
+                           base85.b85encode(data))
+
+    for marker in transmit:
+        enc = obsolete._encodeonemarker(_markertuple(marker))
+        parts.append(enc)
+        size += len(enc)
+        if size > obsolete._maxpayload:
+            transmitmarks()
+            parts, size = [], 0
+            chunk += 1
+    if parts:
+        transmitmarks()
+
+def _markertuple(marker):
+    return marker._data
--- a/hgext/simple4server.py	Tue Mar 04 11:14:24 2014 -0800
+++ b/hgext/simple4server.py	Tue Mar 04 11:31:11 2014 -0800
@@ -10,3 +10,134 @@
 
 import mercurial.obsolete
 mercurial.obsolete._enabled = True
+
+import struct
+from mercurial import wireproto
+from mercurial import extensions
+from mercurial import obsolete
+from cStringIO import StringIO
+from mercurial import node
+_pack = struct.pack
+
+def srv_pushobsmarkers(repo, proto):
+    """wireprotocol command"""
+    fp = StringIO()
+    proto.redirect()
+    proto.getfile(fp)
+    data = fp.getvalue()
+    fp.close()
+    lock = repo.lock()
+    try:
+        tr = repo.transaction('pushkey: obsolete markers')
+        try:
+            repo.obsstore.mergemarkers(tr, data)
+            tr.close()
+        finally:
+            tr.release()
+    finally:
+        lock.release()
+    return wireproto.pushres(0)
+
+def _encodemarkersstream(fp, markers):
+    fp.write(_pack('>B', 0))
+    for mark in markers:
+        fp.write(obsolete._encodeonemarker(mark))
+
+def _getobsmarkersstream(repo, heads=None, common=None):
+    revset = ''
+    args = []
+    repo = repo.unfiltered()
+    if heads is None:
+        revset = 'all()'
+    elif heads:
+        revset += "(::%ln)"
+        args.append(heads)
+    else:
+        assert False, 'pulling no heads?'
+    if common:
+        revset += ' - (::%ln)'
+        args.append(common)
+    nodes = [c.node() for c in repo.set(revset, *args)]
+    markers = repo.obsstore.relevantmarkers(nodes)
+    obsdata = StringIO()
+    _encodemarkersstream(obsdata, markers)
+    obsdata.seek(0)
+    return obsdata
+
+class pruneobsstore(obsolete.obsstore):
+
+    def __init__(self, *args, **kwargs):
+        self.prunedchildren = {}
+        return super(pruneobsstore, self).__init__(*args, **kwargs)
+
+    def _load(self, markers):
+        markers = self._prunedetectingmarkers(markers)
+        return super(pruneobsstore, self)._load(markers)
+
+
+    def _prunedetectingmarkers(self, markers):
+        for m in markers:
+            if not m[1]: # no successors
+                meta = obsolete.decodemeta(m[3])
+                if 'p1' in meta:
+                    p1 = node.bin(meta['p1'])
+                    self.prunedchildren.setdefault(p1, set()).add(m)
+                if 'p2' in meta:
+                    p2 = node.bin(meta['p2'])
+                    self.prunedchildren.setdefault(p2, set()).add(m)
+            yield m
+
+def relevantmarkers(self, nodes):
+    """return a set of all obsolescence marker relevant to a set of node.
+
+    "relevant" to a set of node mean:
+
+    - marker that use this changeset as successors
+    - prune marker of direct children on this changeset.
+    - recursive application of the two rules on precursors of these markers
+
+    It  a set so you cannot rely on order"""
+    seennodes = set(nodes)
+    seenmarkers = set()
+    pendingnodes = set(nodes)
+    precursorsmarkers = self.precursors
+    prunedchildren = self.prunedchildren
+    while pendingnodes:
+        direct = set()
+        for current in pendingnodes:
+            direct.update(precursorsmarkers.get(current, ()))
+            direct.update(prunedchildren.get(current, ()))
+        direct -= seenmarkers
+        pendingnodes = set([m[0] for m in direct])
+        seenmarkers |= direct
+        pendingnodes -= seennodes
+        seennodes |= pendingnodes
+    return seenmarkers
+
+def srv_pullobsmarkers(repo, proto, others):
+    opts = wireproto.options('', ['heads', 'common'], others)
+    for k, v in opts.iteritems():
+        if k in ('heads', 'common'):
+            opts[k] = wireproto.decodelist(v)
+    obsdata = _getobsmarkersstream(repo, **opts)
+    length = '%20i' % len(obsdata.getvalue())
+    def data():
+        yield length
+        for c in proto.groupchunks(obsdata):
+            yield c
+    return wireproto.streamres(data())
+
+def capabilities(orig, repo, proto):
+    """wrapper to advertise new capability"""
+    caps = orig(repo, proto)
+    if obsolete._enabled:
+        caps += ' _evoext_pushobsmarkers_0'
+        caps += ' _evoext_pullobsmarkers_0'
+    return caps
+
+def extsetup(ui):
+    obsolete.obsstore = pruneobsstore
+    obsolete.obsstore.relevantmarkers = relevantmarkers
+    wireproto.commands['evoext_pushobsmarkers_0'] = (srv_pushobsmarkers, '')
+    wireproto.commands['evoext_pullobsmarkers_0'] = (srv_pullobsmarkers, '*')
+    extensions.wrapfunction(wireproto, 'capabilities', capabilities)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/_exc-util.sh	Tue Mar 04 11:31:11 2014 -0800
@@ -0,0 +1,100 @@
+#!/bin/sh
+
+cat >> $HGRCPATH <<EOF
+[web]
+push_ssl = false
+allow_push = *
+[ui]
+logtemplate ="{node|short} ({phase}): {desc}\n"
+[phases]
+publish=False
+[extensions]
+hgext.strip=
+hgext.rebase=
+EOF
+echo "evolve=$(echo $(dirname $TESTDIR))/hgext/evolve.py" >> $HGRCPATH
+
+mkcommit() {
+   echo "$1" > "$1"
+   hg add "$1"
+   hg ci -m "$1"
+}
+getid() {
+   hg id --hidden --debug -ir "$1"
+}
+
+setuprepos() {
+    echo creating test repo for test case $1
+    mkdir $1
+    cd $1
+    echo - pulldest
+    hg init pushdest
+    cd pushdest
+    mkcommit O
+    hg phase --public .
+    cd ..
+    echo - main
+    hg clone -q pushdest main
+    echo - pushdest
+    hg clone -q main pulldest
+    echo 'cd into `main` and proceed with env setup'
+}
+
+dotest() {
+# dotest TESTNAME [TARGETNODE]
+
+    testcase=$1
+    shift
+    target="$1"
+    if [ $# -gt 0 ]; then
+        shift
+    fi
+    targetnode=""
+    desccall=""
+    cd $testcase
+    echo "## Running testcase $testcase"
+    if [ -n "$target" ]; then
+        desccall="desc("\'"$target"\'")"
+        targetnode="`hg -R main id -qr \"$desccall\"`"
+        echo "# testing echange of \"$target\" ($targetnode)"
+    fi
+    echo "## initial state"
+    echo "# obstore: main"
+    hg -R main     debugobsolete
+    echo "# obstore: pushdest"
+    hg -R pushdest debugobsolete
+    echo "# obstore: pulldest"
+    hg -R pulldest debugobsolete
+
+    if [ -n "$target" ]; then
+        echo "## pushing \"$target\"" from main to pushdest
+        hg -R main push -r "$desccall" $@ pushdest
+    else
+        echo "## pushing from main to pushdest"
+        hg -R main push pushdest $@
+    fi
+    echo "## post push state"
+    echo "# obstore: main"
+    hg -R main     debugobsolete
+    echo "# obstore: pushdest"
+    hg -R pushdest debugobsolete
+    echo "# obstore: pulldest"
+    hg -R pulldest debugobsolete
+    if [ -n "$target" ]; then
+        echo "## pulling \"$targetnode\"" from main into pulldest
+        hg -R pulldest pull -r $targetnode $@ main
+    else
+        echo "## pulling from main into pulldest"
+        hg -R pulldest pull main $@
+    fi
+    echo "## post pull state"
+    echo "# obstore: main"
+    hg -R main     debugobsolete
+    echo "# obstore: pushdest"
+    hg -R pushdest debugobsolete
+    echo "# obstore: pulldest"
+    hg -R pulldest debugobsolete
+
+    cd ..
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-boxpush.t	Tue Mar 04 11:31:11 2014 -0800
@@ -0,0 +1,44 @@
+  $ fastobs="$TESTDIR"/../hgext/hgfastobs.py
+  $ echo 'from mercurial import obsolete ; obsolete._enabled = True' > enableobs.py
+  $ cat >> $HGRCPATH <<EOF
+  > [obsolete]
+  > syncstrategy = boxfill
+  > [extensions]
+  > EOF
+  $ echo "enable-obsolete = $PWD/enableobs.py" >> $HGRCPATH
+  $ echo "fastobs = $fastobs" >> $HGRCPATH
+
+  $ hg init alice
+  $ hg init bob
+  $ hg init trent
+  $ cd alice
+  $ echo a > a
+  $ hg addr && hg ci -m 'add a'
+  adding a
+  $ echo aa >> a
+  $ hg ci -m 'edit a'
+  $ echo aa > a
+  $ hg ci --amend -m 'edit a'
+  $ hg debugobsolete
+  e772e827cd64564621e7e5af15c9f848e3b92c8e efa8cd969bc37e6a1330c29f4234fe9e9be681b3 0 {'date': '* 0', 'user': 'test'} (glob)
+  5ccfcbc00f2a19cd7affedce5ff087e68e67c6cc 0 {'date': '* 0', 'user': 'test'} (glob)
+  $ hg push ../trent
+  pushing to ../trent
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 2 changesets with 2 changes to 1 files
+  boxpush: about to transmit 2 obsolete markers (2 markers total)
+  $ cd ../bob
+  $ hg pull ../trent
+  pulling from ../trent
+  requesting all changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 2 changesets with 2 changes to 1 files
+  (run 'hg update' to get a working copy)
+  $ hg debugobsolete | sort
+  5ccfcbc00f2a19cd7affedce5ff087e68e67c6cc 0 {'date': '* 0', 'user': 'test'} (glob)
+  e772e827cd64564621e7e5af15c9f848e3b92c8e efa8cd969bc37e6a1330c29f4234fe9e9be681b3 0 {'date': '* 0', 'user': 'test'} (glob)
--- a/tests/test-corrupt.t	Tue Mar 04 11:14:24 2014 -0800
+++ b/tests/test-corrupt.t	Tue Mar 04 11:31:11 2014 -0800
@@ -111,6 +111,11 @@
   adding manifests
   adding file changes
   added 1 changesets with 2 changes to 2 files
+  OBSEXC: computing relevant nodes
+  OBSEXC: computing markers relevant to 4 nodes
+  OBSEXC: encoding 2 markers
+  OBSEXC: sending 1 pushkey payload (184 bytes)
+  OBSEXC: DONE
   $ hg -R ../other verify
   checking changesets
   checking manifests
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-drop.t	Tue Mar 04 11:31:11 2014 -0800
@@ -0,0 +1,267 @@
+
+  $ cat >> $HGRCPATH <<EOF
+  > [extensions]
+  > hgext.rebase=
+  > hgext.graphlog=
+  > EOF
+  $ echo "drophack=$(echo $(dirname $TESTDIR))/hgext/drophack.py" >> $HGRCPATH
+  $ echo "evolve=$(echo $(dirname $TESTDIR))/hgext/evolve.py" >> $HGRCPATH
+  $ mkcommit() {
+  >    echo "$1" > "$1"
+  >    hg add "$1"
+  >    hg ci -m "add $1"
+  > }
+  $ summary() {
+  > echo ============ graph ==============
+  > hg log -G
+  > echo ============ hidden =============
+  > hg log --hidden -G
+  > echo ============ obsmark ============
+  > hg debugobsolete
+  > }
+
+
+  $ hg init repo
+  $ cd repo
+  $ mkcommit base
+
+drop a single changeset without any rewrite
+================================================
+
+
+  $ mkcommit simple-single
+  $ summary
+  ============ graph ==============
+  @  changeset:   1:d4e7845543ff
+  |  tag:         tip
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     add simple-single
+  |
+  o  changeset:   0:b4952fcf48cf
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     add base
+  
+  ============ hidden =============
+  @  changeset:   1:d4e7845543ff
+  |  tag:         tip
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     add simple-single
+  |
+  o  changeset:   0:b4952fcf48cf
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     add base
+  
+  ============ obsmark ============
+  $ hg drop .
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  working directory now at b4952fcf48cf
+  search obsmarker: wall * comb * user * sys * (glob)
+  0 obsmarkers found
+  search nodes: wall * comb * user * sys * (glob)
+  1 nodes found
+  saved backup bundle to $TESTTMP/repo/.hg/strip-backup/d4e7845543ff-drophack.hg
+  strip nodes: wall * comb * user * sys * (glob)
+  $ summary
+  ============ graph ==============
+  @  changeset:   0:b4952fcf48cf
+     tag:         tip
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     add base
+  
+  ============ hidden =============
+  @  changeset:   0:b4952fcf48cf
+     tag:         tip
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     add base
+  
+  ============ obsmark ============
+
+Try to drop a changeset with children
+================================================
+
+  $ mkcommit parent
+  $ mkcommit child
+  $ summary
+  ============ graph ==============
+  @  changeset:   2:34b6c051bf1f
+  |  tag:         tip
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     add child
+  |
+  o  changeset:   1:19509a42b0d0
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     add parent
+  |
+  o  changeset:   0:b4952fcf48cf
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     add base
+  
+  ============ hidden =============
+  @  changeset:   2:34b6c051bf1f
+  |  tag:         tip
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     add child
+  |
+  o  changeset:   1:19509a42b0d0
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     add parent
+  |
+  o  changeset:   0:b4952fcf48cf
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     add base
+  
+  ============ obsmark ============
+  $ hg drop 1
+  cannot drop revision with children (no-eol)
+  [1]
+  $ summary
+  ============ graph ==============
+  @  changeset:   2:34b6c051bf1f
+  |  tag:         tip
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     add child
+  |
+  o  changeset:   1:19509a42b0d0
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     add parent
+  |
+  o  changeset:   0:b4952fcf48cf
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     add base
+  
+  ============ hidden =============
+  @  changeset:   2:34b6c051bf1f
+  |  tag:         tip
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     add child
+  |
+  o  changeset:   1:19509a42b0d0
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     add parent
+  |
+  o  changeset:   0:b4952fcf48cf
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     add base
+  
+  ============ obsmark ============
+
+Try to drop a public changeset
+================================================
+
+  $ hg phase --public 2
+  $ hg drop 2
+  cannot drop public revision (no-eol)
+  [1]
+
+
+Try to drop a changeset with rewrite
+================================================
+
+  $ hg phase --force --draft 2
+  $ echo babar >> child
+  $ hg commit --amend
+  $ summary
+  ============ graph ==============
+  @  changeset:   4:a2c06c884bfe
+  |  tag:         tip
+  |  parent:      1:19509a42b0d0
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     add child
+  |
+  o  changeset:   1:19509a42b0d0
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     add parent
+  |
+  o  changeset:   0:b4952fcf48cf
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     add base
+  
+  ============ hidden =============
+  @  changeset:   4:a2c06c884bfe
+  |  tag:         tip
+  |  parent:      1:19509a42b0d0
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     add child
+  |
+  | x  changeset:   3:87ea30a976fd
+  | |  user:        test
+  | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  summary:     temporary amend commit for 34b6c051bf1f
+  | |
+  | x  changeset:   2:34b6c051bf1f
+  |/   user:        test
+  |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    summary:     add child
+  |
+  o  changeset:   1:19509a42b0d0
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     add parent
+  |
+  o  changeset:   0:b4952fcf48cf
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     add base
+  
+  ============ obsmark ============
+  34b6c051bf1f78db6aef400776de5cb964470207 a2c06c884bfe53d3840026248bd8a7eafa152df8 0 {'date': '* *', 'user': 'test'} (glob)
+  87ea30a976fdf235bf096f04899cb02a903873e2 0 {'date': '* *', 'user': 'test'} (glob)
+  $ hg drop .
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  working directory now at 19509a42b0d0
+  search obsmarker: wall * comb * user * sys * (glob)
+  1 obsmarkers found
+  search nodes: wall * comb * user * sys * (glob)
+  2 nodes found
+  strip obsmarker: wall * comb * user * sys * (glob)
+  saved backup bundle to $TESTTMP/repo/.hg/strip-backup/*-drophack.hg (glob)
+  strip nodes: wall * comb * user * sys * (glob)
+  $ summary
+  ============ graph ==============
+  @  changeset:   1:19509a42b0d0
+  |  tag:         tip
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     add parent
+  |
+  o  changeset:   0:b4952fcf48cf
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     add base
+  
+  ============ hidden =============
+  @  changeset:   1:19509a42b0d0
+  |  tag:         tip
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     add parent
+  |
+  o  changeset:   0:b4952fcf48cf
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     add base
+  
+  ============ obsmark ============
+  87ea30a976fdf235bf096f04899cb02a903873e2 0 {'date': '* *', 'user': 'test'} (glob)
--- a/tests/test-evolve.t	Tue Mar 04 11:14:24 2014 -0800
+++ b/tests/test-evolve.t	Tue Mar 04 11:31:11 2014 -0800
@@ -384,6 +384,8 @@
   adding manifests
   adding file changes
   added 1 changesets with 1 changes to 1 files
+  OBSEXC: pull obsolescence markers
+  OBSEXC: DONE
   $ cd alpha
 
   $ cat << EOF > A
@@ -440,6 +442,10 @@
   adding manifests
   adding file changes
   added 1 changesets with 1 changes to 1 files
+  OBSEXC: pull obsolescence markers
+  OBSEXC: merging obsolescence markers (171 bytes)
+  OBSEXC: 2 markers added
+  OBSEXC: DONE
   (run 'hg update' to get a working copy)
   $ hg up
   2 files updated, 0 files merged, 0 files removed, 0 files unresolved
@@ -645,3 +651,30 @@
   4	: add 4 - test
   5	: add 3 - test
   11	: add 1 - test
+
+Test obsstore stat
+
+  $ hg debugobsstorestat
+  markers total:                     10
+      for known precursors:          10
+      with parents data:              0
+  markers with no successors:         0
+                1 successors:        10
+                2 successors:         0
+      more than 2 successors:         0
+  average meta length:               27
+      available  keys:
+                 date:               10
+                 user:               10
+  disconnected clusters:              1
+          any known node:             1
+          smallest length:           10
+          longer length:             10
+          median length:             10
+          mean length:               10
+      using parents data:             1
+          any known node:             1
+          smallest length:           10
+          longer length:             10
+          median length:             10
+          mean length:               10
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-exchange-A1.t	Tue Mar 04 11:31:11 2014 -0800
@@ -0,0 +1,313 @@
+
+Initial setup
+
+  $ . $TESTDIR/_exc-util.sh
+
+==== A.1.1 pushing a single head ====
+..
+.. {{{
+..     ⇠◔ A
+..      |
+..      ● O
+.. }}}
+..
+.. Marker exist from:
+..
+..  * A
+..
+.. Command run:
+..
+..  * hg push -r A
+..  * hg push
+..
+.. Expected exchange:
+..
+..  * chain from A
+
+Setup
+---------------
+
+initial
+
+  $ setuprepos A.1.1
+  creating test repo for test case A.1.1
+  - pulldest
+  - main
+  - pushdest
+  cd into `main` and proceed with env setup
+  $ cd main
+  $ mkcommit A
+  $ hg debugobsolete aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa `getid 'desc(A)'`
+  $ hg log -G
+  @  f5bc6836db60 (draft): A
+  |
+  o  a9bdc8b26820 (public): O
+  
+  $ hg debugobsolete
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '', 'user': 'test'}
+  $ cd ..
+  $ cd ..
+
+setup both variants
+
+  $ cp -r A.1.1 A.1.1.a
+  $ cp -r A.1.1 A.1.1.b
+
+
+Variante a: push -r A
+---------------------
+
+  $ dotest A.1.1.a A
+  ## Running testcase A.1.1.a
+  # testing echange of "A" (f5bc6836db60)
+  ## initial state
+  # obstore: main
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  # obstore: pulldest
+  ## pushing "A" from main to pushdest
+  pushing to pushdest
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  OBSEXC: computing relevant nodes
+  OBSEXC: computing markers relevant to 2 nodes
+  OBSEXC: encoding 1 markers
+  OBSEXC: sending 1 pushkey payload (78 bytes)
+  OBSEXC: DONE
+  ## post push state
+  # obstore: main
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '', 'user': 'test'}
+  # obstore: pulldest
+  ## pulling "f5bc6836db60" from main into pulldest
+  pulling from main
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  OBSEXC: pull obsolescence markers
+  OBSEXC: merging obsolescence markers (62 bytes)
+  OBSEXC: 1 markers added
+  OBSEXC: DONE
+  (run 'hg update' to get a working copy)
+  ## post pull state
+  # obstore: main
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '', 'user': 'test'}
+  # obstore: pulldest
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '', 'user': 'test'}
+
+
+
+
+Variante b: push
+---------------------
+
+  $ dotest A.1.1.b
+  ## Running testcase A.1.1.b
+  ## initial state
+  # obstore: main
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  # obstore: pulldest
+  ## pushing from main to pushdest
+  pushing to pushdest
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  OBSEXC: computing relevant nodes
+  OBSEXC: computing markers relevant to 2 nodes
+  OBSEXC: encoding 1 markers
+  OBSEXC: sending 1 pushkey payload (78 bytes)
+  OBSEXC: DONE
+  ## post push state
+  # obstore: main
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '', 'user': 'test'}
+  # obstore: pulldest
+  ## pulling from main into pulldest
+  pulling from main
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  OBSEXC: pull obsolescence markers
+  OBSEXC: merging obsolescence markers (62 bytes)
+  OBSEXC: 1 markers added
+  OBSEXC: DONE
+  (run 'hg update' to get a working copy)
+  ## post pull state
+  # obstore: main
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '', 'user': 'test'}
+  # obstore: pulldest
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '', 'user': 'test'}
+
+
+
+
+
+
+==== A.1.2 pushing a multiple changeset into a single head  ====
+
+.. {{{
+..      ◔ B
+..      |
+..     ⇠◔ A
+..      |
+..      ● O
+.. }}}
+..
+.. Marker exist from:
+..
+..  * A
+..
+.. Command run:
+..
+..  * hg push -r B
+..  * hg push
+..
+.. Expected exchange:
+..
+..  * chain from A
+
+Setup
+---------------
+
+initial
+
+  $ setuprepos A.1.2
+  creating test repo for test case A.1.2
+  - pulldest
+  - main
+  - pushdest
+  cd into `main` and proceed with env setup
+  $ cd main
+  $ mkcommit A
+  $ mkcommit B
+  $ hg log -G
+  @  f6fbb35d8ac9 (draft): B
+  |
+  o  f5bc6836db60 (draft): A
+  |
+  o  a9bdc8b26820 (public): O
+  
+  $ hg debugobsolete aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa `getid 'desc(A)'`
+  $ hg debugobsolete
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '', 'user': 'test'}
+  $ cd ..
+  $ cd ..
+
+setup both variants
+
+  $ cp -r A.1.2 A.1.2.a
+  $ cp -r A.1.2 A.1.2.b
+
+
+Variante a: push -r A
+---------------------
+
+  $ dotest A.1.2.a B
+  ## Running testcase A.1.2.a
+  # testing echange of "B" (f6fbb35d8ac9)
+  ## initial state
+  # obstore: main
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  # obstore: pulldest
+  ## pushing "B" from main to pushdest
+  pushing to pushdest
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 2 changesets with 2 changes to 2 files
+  OBSEXC: computing relevant nodes
+  OBSEXC: computing markers relevant to 3 nodes
+  OBSEXC: encoding 1 markers
+  OBSEXC: sending 1 pushkey payload (78 bytes)
+  OBSEXC: DONE
+  ## post push state
+  # obstore: main
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '', 'user': 'test'}
+  # obstore: pulldest
+  ## pulling "f6fbb35d8ac9" from main into pulldest
+  pulling from main
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 2 changesets with 2 changes to 2 files
+  OBSEXC: pull obsolescence markers
+  OBSEXC: merging obsolescence markers (62 bytes)
+  OBSEXC: 1 markers added
+  OBSEXC: DONE
+  (run 'hg update' to get a working copy)
+  ## post pull state
+  # obstore: main
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '', 'user': 'test'}
+  # obstore: pulldest
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '', 'user': 'test'}
+
+Variante b: push
+---------------------
+
+  $ dotest A.1.2.b
+  ## Running testcase A.1.2.b
+  ## initial state
+  # obstore: main
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  # obstore: pulldest
+  ## pushing from main to pushdest
+  pushing to pushdest
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 2 changesets with 2 changes to 2 files
+  OBSEXC: computing relevant nodes
+  OBSEXC: computing markers relevant to 3 nodes
+  OBSEXC: encoding 1 markers
+  OBSEXC: sending 1 pushkey payload (78 bytes)
+  OBSEXC: DONE
+  ## post push state
+  # obstore: main
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '', 'user': 'test'}
+  # obstore: pulldest
+  ## pulling from main into pulldest
+  pulling from main
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 2 changesets with 2 changes to 2 files
+  OBSEXC: pull obsolescence markers
+  OBSEXC: merging obsolescence markers (62 bytes)
+  OBSEXC: 1 markers added
+  OBSEXC: DONE
+  (run 'hg update' to get a working copy)
+  ## post pull state
+  # obstore: main
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '', 'user': 'test'}
+  # obstore: pulldest
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '', 'user': 'test'}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-exchange-A2.t	Tue Mar 04 11:31:11 2014 -0800
@@ -0,0 +1,117 @@
+
+
+Initial setup
+
+  $ . $TESTDIR/_exc-util.sh
+
+=== A.2 Two heads ===
+
+.. {{{
+..     ⇠○ B
+..   ⇠◔ | A
+..    |/
+..    ● O
+.. }}}
+..
+.. Marker exist from:
+..
+..  * A
+..  * B
+..
+..
+.. Command run:
+..
+..  * hg push -r A
+..
+.. Expected exchange:
+..
+..  * chain from A
+..
+.. Expected Exclude:
+..
+..  * chain from B
+
+initial
+
+  $ setuprepos A.2
+  creating test repo for test case A.2
+  - pulldest
+  - main
+  - pushdest
+  cd into `main` and proceed with env setup
+  $ cd main
+  $ mkcommit A
+  $ hg debugobsolete aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa `getid 'desc(A)'`
+  $ hg up .^
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ mkcommit B
+  created new head
+  $ hg debugobsolete bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb `getid 'desc(B)'`
+  $ hg log -G
+  @  35b183996678 (draft): B
+  |
+  | o  f5bc6836db60 (draft): A
+  |/
+  o  a9bdc8b26820 (public): O
+  
+  $ hg debugobsolete
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '', 'user': 'test'}
+  bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 35b1839966785d5703a01607229eea932db42f87 0 {'date': '', 'user': 'test'}
+  $ cd ..
+  $ cd ..
+
+
+Actual Test
+---------------
+
+  $ dotest A.2 A
+  ## Running testcase A.2
+  # testing echange of "A" (f5bc6836db60)
+  ## initial state
+  # obstore: main
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '', 'user': 'test'}
+  bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 35b1839966785d5703a01607229eea932db42f87 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  # obstore: pulldest
+  ## pushing "A" from main to pushdest
+  pushing to pushdest
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  OBSEXC: computing relevant nodes
+  OBSEXC: computing markers relevant to 2 nodes
+  OBSEXC: encoding 1 markers
+  OBSEXC: sending 1 pushkey payload (78 bytes)
+  OBSEXC: DONE
+  ## post push state
+  # obstore: main
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '', 'user': 'test'}
+  bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 35b1839966785d5703a01607229eea932db42f87 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '', 'user': 'test'}
+  # obstore: pulldest
+  ## pulling "f5bc6836db60" from main into pulldest
+  pulling from main
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  OBSEXC: pull obsolescence markers
+  OBSEXC: merging obsolescence markers (62 bytes)
+  OBSEXC: 1 markers added
+  OBSEXC: DONE
+  (run 'hg update' to get a working copy)
+  ## post pull state
+  # obstore: main
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '', 'user': 'test'}
+  bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 35b1839966785d5703a01607229eea932db42f87 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '', 'user': 'test'}
+  # obstore: pulldest
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '', 'user': 'test'}
+
+
+  $ cd ..
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-exchange-A3.t	Tue Mar 04 11:31:11 2014 -0800
@@ -0,0 +1,232 @@
+
+Initial setup
+
+  $ . $TESTDIR/_exc-util.sh
+
+=== A.3 new branch created ===
+
+.. {{{
+..   B' ○⇢ø B
+..      | |
+..      \Aø⇠◔ A'
+..       \|/
+..        ● O
+.. }}}
+..
+.. Marker exist from:
+..
+..  * `Aø⇠○ A'`
+..  * `Bø⇠○ B'`
+..
+.. Command run:
+..
+..  * hg push -r A
+..
+.. Expected exchange:
+..
+..  * chain from A
+..
+.. Expected Exclude:
+..
+..  * chain from B
+..
+.. Extra note:
+..
+.. If A and B are remontly known, we should expect:
+..
+..  * `hg push` will complain about the new head
+..  * `hg push` should complain about unstable history creation
+
+initial
+
+  $ setuprepos A.3.a
+  creating test repo for test case A.3.a
+  - pulldest
+  - main
+  - pushdest
+  cd into `main` and proceed with env setup
+  $ cd main
+  $ mkcommit A0
+  $ mkcommit B0
+  $ hg update -q 0
+  $ mkcommit A1
+  created new head
+  $ hg update -q 0
+  $ mkcommit B1
+  created new head
+  $ hg debugobsolete `getid 'desc(A0)'` `getid 'desc(A1)'`
+  $ hg debugobsolete `getid 'desc(B0)'` `getid 'desc(B1)'`
+  $ hg log -G --hidden
+  @  f6298a8ac3a4 (draft): B1
+  |
+  | o  e5ea8f9c7314 (draft): A1
+  |/
+  | x  6e72f0a95b5e (draft): B0
+  | |
+  | x  28b51eb45704 (draft): A0
+  |/
+  o  a9bdc8b26820 (public): O
+  
+  $ hg debugobsolete
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 {'date': '', 'user': 'test'}
+  $ cd ..
+  $ cd ..
+
+Actual Test for first version (changeset unknown remotly)
+---------------------------------------------------------
+
+  $ dotest A.3.a A1
+  ## Running testcase A.3.a
+  # testing echange of "A1" (e5ea8f9c7314)
+  ## initial state
+  # obstore: main
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  # obstore: pulldest
+  ## pushing "A1" from main to pushdest
+  pushing to pushdest
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  OBSEXC: computing relevant nodes
+  OBSEXC: computing markers relevant to 2 nodes
+  OBSEXC: encoding 1 markers
+  OBSEXC: sending 1 pushkey payload (78 bytes)
+  OBSEXC: DONE
+  ## post push state
+  # obstore: main
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  # obstore: pulldest
+  ## pulling "e5ea8f9c7314" from main into pulldest
+  pulling from main
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  OBSEXC: pull obsolescence markers
+  OBSEXC: merging obsolescence markers (62 bytes)
+  OBSEXC: 1 markers added
+  OBSEXC: DONE
+  (run 'hg update' to get a working copy)
+  ## post pull state
+  # obstore: main
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  # obstore: pulldest
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+
+
+other variant: changeset know remotly
+-------------------------------------------
+
+  $ setuprepos A.3.b
+  creating test repo for test case A.3.b
+  - pulldest
+  - main
+  - pushdest
+  cd into `main` and proceed with env setup
+  $ cd main
+  $ mkcommit A0
+  $ mkcommit B0
+  $ hg push -q ../pushdest
+  $ hg push -q ../pulldest
+  $ hg update -q 0
+  $ mkcommit A1
+  created new head
+  $ hg update -q 0
+  $ mkcommit B1
+  created new head
+  $ hg debugobsolete `getid 'desc(A0)'` `getid 'desc(A1)'`
+  $ hg debugobsolete `getid 'desc(B0)'` `getid 'desc(B1)'`
+  $ hg log -G --hidden
+  @  f6298a8ac3a4 (draft): B1
+  |
+  | o  e5ea8f9c7314 (draft): A1
+  |/
+  | x  6e72f0a95b5e (draft): B0
+  | |
+  | x  28b51eb45704 (draft): A0
+  |/
+  o  a9bdc8b26820 (public): O
+  
+  $ hg debugobsolete
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 {'date': '', 'user': 'test'}
+  $ cd ..
+  $ cd ..
+
+Actual Test for first version (changeset unknown remotly)
+---------------------------------------------------------
+
+check it complains about multiple heads
+
+  $ cd A.3.b
+  $ hg push -R main -r e5ea8f9c7314 pushdest
+  pushing to pushdest
+  searching for changes
+  abort: push creates new remote head e5ea8f9c7314!
+  (merge or see "hg help push" for details about pushing new heads)
+  [255]
+  $ cd ..
+
+test obsmarkers exchange.
+
+  $ dotest A.3.b A1 -f
+  ## Running testcase A.3.b
+  # testing echange of "A1" (e5ea8f9c7314)
+  ## initial state
+  # obstore: main
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  # obstore: pulldest
+  ## pushing "A1" from main to pushdest
+  pushing to pushdest
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files (+1 heads)
+  OBSEXC: computing relevant nodes
+  OBSEXC: computing markers relevant to 2 nodes
+  OBSEXC: encoding 1 markers
+  OBSEXC: sending 1 pushkey payload (78 bytes)
+  OBSEXC: DONE
+  ## post push state
+  # obstore: main
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  # obstore: pulldest
+  ## pulling "e5ea8f9c7314" from main into pulldest
+  pulling from main
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 2 files (+1 heads)
+  OBSEXC: pull obsolescence markers
+  OBSEXC: merging obsolescence markers (62 bytes)
+  OBSEXC: 1 markers added
+  OBSEXC: DONE
+  (run 'hg heads' to see heads, 'hg merge' to merge)
+  1 new unstable changesets
+  ## post pull state
+  # obstore: main
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  # obstore: pulldest
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-exchange-A4.t	Tue Mar 04 11:31:11 2014 -0800
@@ -0,0 +1,119 @@
+
+Initial setup
+
+  $ . $TESTDIR/_exc-util.sh
+
+
+=== A.4 Push in the middle of the obsolescence chain ===
+
+.. (Where we show that we should not push the marker without the successors)
+..
+.. {{{
+..   B ◔
+..     |
+..   A⇠ø⇠○ A'
+..     |/
+..     ● O
+.. }}}
+..
+.. Marker exist from:
+..
+..  * `Aø⇠○ A'`
+..  * chain from A
+..
+.. Command run:
+..
+..  * hg push -r B
+..
+.. Expected exchange:
+..
+..  * Chain from A
+..
+.. Expected Exclude:
+..
+..  * `Aø⇠○ A'`
+
+
+initial
+
+  $ setuprepos A.4
+  creating test repo for test case A.4
+  - pulldest
+  - main
+  - pushdest
+  cd into `main` and proceed with env setup
+  $ cd main
+  $ mkcommit A0
+  $ mkcommit B
+  $ hg update 0
+  0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+  $ mkcommit A1
+  created new head
+  $ hg debugobsolete aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa `getid 'desc(A0)'`
+  $ hg debugobsolete `getid 'desc(A0)'` `getid 'desc(A1)'`
+  $ hg log -G --hidden
+  @  e5ea8f9c7314 (draft): A1
+  |
+  | o  06055a7959d4 (draft): B
+  | |
+  | x  28b51eb45704 (draft): A0
+  |/
+  o  a9bdc8b26820 (public): O
+  
+  $ hg debugobsolete
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 28b51eb45704506b5c603decd6bf7ac5e0f6a52f 0 {'date': '', 'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  $ cd ..
+  $ cd ..
+
+Actual Test for first version (changeset unknown remotly)
+---------------------------------------------------------
+
+  $ dotest A.4 B -f
+  ## Running testcase A.4
+  # testing echange of "B" (06055a7959d4)
+  ## initial state
+  # obstore: main
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 28b51eb45704506b5c603decd6bf7ac5e0f6a52f 0 {'date': '', 'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  # obstore: pulldest
+  ## pushing "B" from main to pushdest
+  pushing to pushdest
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 2 changesets with 2 changes to 2 files
+  OBSEXC: computing relevant nodes
+  OBSEXC: computing markers relevant to 3 nodes
+  OBSEXC: encoding 1 markers
+  OBSEXC: sending 1 pushkey payload (78 bytes)
+  OBSEXC: DONE
+  ## post push state
+  # obstore: main
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 28b51eb45704506b5c603decd6bf7ac5e0f6a52f 0 {'date': '', 'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 28b51eb45704506b5c603decd6bf7ac5e0f6a52f 0 {'date': '', 'user': 'test'}
+  # obstore: pulldest
+  ## pulling "06055a7959d4" from main into pulldest
+  pulling from main
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 2 changesets with 2 changes to 2 files
+  OBSEXC: pull obsolescence markers
+  OBSEXC: merging obsolescence markers (62 bytes)
+  OBSEXC: 1 markers added
+  OBSEXC: DONE
+  (run 'hg update' to get a working copy)
+  ## post pull state
+  # obstore: main
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 28b51eb45704506b5c603decd6bf7ac5e0f6a52f 0 {'date': '', 'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 28b51eb45704506b5c603decd6bf7ac5e0f6a52f 0 {'date': '', 'user': 'test'}
+  # obstore: pulldest
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 28b51eb45704506b5c603decd6bf7ac5e0f6a52f 0 {'date': '', 'user': 'test'}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-exchange-A5.t	Tue Mar 04 11:31:11 2014 -0800
@@ -0,0 +1,129 @@
+
+
+Initial setup
+
+  $ . $TESTDIR/_exc-util.sh
+
+
+=== A.5 partial reordering ===
+..
+.. {{{
+..   B ø⇠⇠
+..     | ⇡
+..   A ø⇠⇠⇠○ A'
+..     | ⇡/
+..     | ○ B'
+..     |/
+..     ● O
+.. }}}
+..
+.. Marker exist from:
+..
+..  * `Aø⇠○ A'`
+..  * `Bø⇠○ B'`
+..
+.. Command run:
+..
+..  * hg push -r B
+..
+.. Expected exchange:
+..
+..  * `Bø⇠○ B'`
+..
+.. Expected Exclude:
+..
+..  * `Aø⇠○ A'`
+
+
+initial
+
+  $ setuprepos A.5
+  creating test repo for test case A.5
+  - pulldest
+  - main
+  - pushdest
+  cd into `main` and proceed with env setup
+  $ cd main
+  $ mkcommit A0
+  $ mkcommit B0
+  $ hg update 0
+  0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+  $ mkcommit B1
+  created new head
+  $ mkcommit A1
+  $ hg debugobsolete aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa `getid 'desc(A0)'`
+  $ hg debugobsolete `getid 'desc(B0)'` `getid 'desc(B1)'`
+  $ hg debugobsolete `getid 'desc(A0)'` `getid 'desc(A1)'`
+  invalid branchheads cache (served): tip differs
+  $ hg log -G --hidden
+  @  8c0a98c83722 (draft): A1
+  |
+  o  f6298a8ac3a4 (draft): B1
+  |
+  | x  6e72f0a95b5e (draft): B0
+  | |
+  | x  28b51eb45704 (draft): A0
+  |/
+  o  a9bdc8b26820 (public): O
+  
+  $ hg debugobsolete
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 28b51eb45704506b5c603decd6bf7ac5e0f6a52f 0 {'date': '', 'user': 'test'}
+  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 {'date': '', 'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f 8c0a98c8372212c6efde4bfdcef006f27ff759d3 0 {'date': '', 'user': 'test'}
+  $ cd ..
+  $ cd ..
+
+Actual Test
+-----------
+
+  $ dotest A.5 B1
+  ## Running testcase A.5
+  # testing echange of "B1" (f6298a8ac3a4)
+  ## initial state
+  # obstore: main
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 28b51eb45704506b5c603decd6bf7ac5e0f6a52f 0 {'date': '', 'user': 'test'}
+  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 {'date': '', 'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f 8c0a98c8372212c6efde4bfdcef006f27ff759d3 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  # obstore: pulldest
+  ## pushing "B1" from main to pushdest
+  pushing to pushdest
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  OBSEXC: computing relevant nodes
+  OBSEXC: computing markers relevant to 2 nodes
+  OBSEXC: encoding 1 markers
+  OBSEXC: sending 1 pushkey payload (78 bytes)
+  OBSEXC: DONE
+  ## post push state
+  # obstore: main
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 28b51eb45704506b5c603decd6bf7ac5e0f6a52f 0 {'date': '', 'user': 'test'}
+  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 {'date': '', 'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f 8c0a98c8372212c6efde4bfdcef006f27ff759d3 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 {'date': '', 'user': 'test'}
+  # obstore: pulldest
+  ## pulling "f6298a8ac3a4" from main into pulldest
+  pulling from main
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  OBSEXC: pull obsolescence markers
+  OBSEXC: merging obsolescence markers (62 bytes)
+  OBSEXC: 1 markers added
+  OBSEXC: DONE
+  (run 'hg update' to get a working copy)
+  ## post pull state
+  # obstore: main
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 28b51eb45704506b5c603decd6bf7ac5e0f6a52f 0 {'date': '', 'user': 'test'}
+  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 {'date': '', 'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f 8c0a98c8372212c6efde4bfdcef006f27ff759d3 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 {'date': '', 'user': 'test'}
+  # obstore: pulldest
+  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 {'date': '', 'user': 'test'}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-exchange-A6.t	Tue Mar 04 11:31:11 2014 -0800
@@ -0,0 +1,148 @@
+
+
+
+Initial setup
+
+  $ . $TESTDIR/_exc-util.sh
+
+
+=== A.6 between existing changeset ===
+
+.. {{{
+..   A ◕⇠● B
+..     |/
+..     ● O
+.. }}}
+..
+.. Marker exist from:
+..
+..  * `A◕⇠● B`
+..
+.. Command run:
+..
+..  * hg push -r B
+..  * hg push
+..
+.. Expected exchange:
+..
+..  * `A◕⇠● B`
+
+
+initial
+
+  $ setuprepos A.6
+  creating test repo for test case A.6
+  - pulldest
+  - main
+  - pushdest
+  cd into `main` and proceed with env setup
+  $ cd main
+  $ mkcommit A0
+  $ hg update -q 0
+  $ mkcommit A1
+  created new head
+
+make both changeset known remotly
+
+  $ hg push -qf ../pushdest
+  $ hg push -qf ../pulldest
+
+create a marker after this
+
+  $ hg debugobsolete `getid 'desc(A0)'` `getid 'desc(A1)'`
+  $ hg log -G --hidden
+  @  e5ea8f9c7314 (draft): A1
+  |
+  | x  28b51eb45704 (draft): A0
+  |/
+  o  a9bdc8b26820 (public): O
+  
+  $ hg debugobsolete
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  $ cd ..
+  $ cd ..
+
+  $ cp -r A.6 A.6.a
+  $ cp -r A.6 A.6.b
+
+Actual Test (explicit push version)
+-----------------------------------
+
+  $ dotest A.6.a A1
+  ## Running testcase A.6.a
+  # testing echange of "A1" (e5ea8f9c7314)
+  ## initial state
+  # obstore: main
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  # obstore: pulldest
+  ## pushing "A1" from main to pushdest
+  pushing to pushdest
+  searching for changes
+  no changes found
+  OBSEXC: computing relevant nodes
+  OBSEXC: computing markers relevant to 2 nodes
+  OBSEXC: encoding 1 markers
+  OBSEXC: sending 1 pushkey payload (78 bytes)
+  OBSEXC: DONE
+  ## post push state
+  # obstore: main
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  # obstore: pulldest
+  ## pulling "e5ea8f9c7314" from main into pulldest
+  pulling from main
+  no changes found
+  OBSEXC: pull obsolescence markers
+  OBSEXC: merging obsolescence markers (62 bytes)
+  OBSEXC: 1 markers added
+  OBSEXC: DONE
+  ## post pull state
+  # obstore: main
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  # obstore: pulldest
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+
+Actual Test (bare push version)
+-----------------------------------
+
+  $ dotest A.6.b
+  ## Running testcase A.6.b
+  ## initial state
+  # obstore: main
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  # obstore: pulldest
+  ## pushing from main to pushdest
+  pushing to pushdest
+  searching for changes
+  no changes found
+  OBSEXC: computing relevant nodes
+  OBSEXC: computing markers relevant to 3 nodes
+  OBSEXC: encoding 1 markers
+  OBSEXC: sending 1 pushkey payload (78 bytes)
+  OBSEXC: DONE
+  ## post push state
+  # obstore: main
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  # obstore: pulldest
+  ## pulling from main into pulldest
+  pulling from main
+  searching for changes
+  no changes found
+  OBSEXC: pull obsolescence markers
+  OBSEXC: merging obsolescence markers (62 bytes)
+  OBSEXC: 1 markers added
+  OBSEXC: DONE
+  ## post pull state
+  # obstore: main
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  # obstore: pulldest
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-exchange-A7.t	Tue Mar 04 11:31:11 2014 -0800
@@ -0,0 +1,82 @@
+
+Initial setup
+
+  $ . $TESTDIR/_exc-util.sh
+
+=== A.7 Non targeted common changeset ===
+
+.. {{{
+..    ⇠◕ A
+..     |
+..     ● O
+.. }}}
+..
+.. Marker exist from:
+..
+..  * Chain from A
+..
+.. Command run:
+..
+..  * hg push -r O
+..
+.. Expected exchange:
+..
+..  * ø
+
+
+  $ setuprepos A.7
+  creating test repo for test case A.7
+  - pulldest
+  - main
+  - pushdest
+  cd into `main` and proceed with env setup
+  $ cd main
+  $ mkcommit A
+  $ hg push -q ../pushdest
+  $ hg push -q ../pulldest
+  $ hg debugobsolete aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa `getid 'desc(A)'`
+  $ hg log -G --hidden
+  @  f5bc6836db60 (draft): A
+  |
+  o  a9bdc8b26820 (public): O
+  
+  $ hg debugobsolete
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '', 'user': 'test'}
+  $ cd ..
+  $ cd ..
+
+Actual Test
+-----------------------------------
+
+  $ dotest A.7 O
+  ## Running testcase A.7
+  # testing echange of "O" (a9bdc8b26820)
+  ## initial state
+  # obstore: main
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  # obstore: pulldest
+  ## pushing "O" from main to pushdest
+  pushing to pushdest
+  searching for changes
+  no changes found
+  OBSEXC: computing relevant nodes
+  OBSEXC: computing markers relevant to 1 nodes
+  OBSEXC: encoding 0 markers
+  OBSEXC: sending 0 pushkey payload (0 bytes)
+  OBSEXC: DONE
+  ## post push state
+  # obstore: main
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  # obstore: pulldest
+  ## pulling "a9bdc8b26820" from main into pulldest
+  pulling from main
+  no changes found
+  OBSEXC: pull obsolescence markers
+  OBSEXC: DONE
+  ## post pull state
+  # obstore: main
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  # obstore: pulldest
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-exchange-B1.t	Tue Mar 04 11:31:11 2014 -0800
@@ -0,0 +1,151 @@
+
+Initial setup
+
+  $ . $TESTDIR/_exc-util.sh
+
+=== B.1 Prune on non targeted common changeset ===
+
+.. {{{
+..     ⊗ B
+..     |
+..     ◕ A
+..     |
+..     ● O
+.. }}}
+..
+.. Marker exist from:
+..
+..  * B (prune)
+..
+.. Command run:
+..
+..  * hg push -r O
+..  * hg push
+..
+.. Expected exchange:
+..
+..  * B (prune)
+
+
+  $ setuprepos B.1
+  creating test repo for test case B.1
+  - pulldest
+  - main
+  - pushdest
+  cd into `main` and proceed with env setup
+  $ cd main
+  $ mkcommit A
+  $ mkcommit B
+  $ hg prune -qd '0 0' .
+  $ hg log -G --hidden
+  x  f6fbb35d8ac9 (draft): B
+  |
+  @  f5bc6836db60 (draft): A
+  |
+  o  a9bdc8b26820 (public): O
+  
+  $ hg debugobsolete
+  f6fbb35d8ac958bbe70035e4c789c18471cdc0af 0 {'date': '0 0', 'p1': 'f5bc6836db60e308a17ba08bf050154ba9c4fad7', 'user': 'test'}
+  $ cd ..
+  $ cd ..
+
+
+  $ cp -r B.1 B.1.a
+  $ cp -r B.1 B.1.b
+
+Actual Test (explicite push version)
+-----------------------------------
+
+  $ dotest B.1.a A
+  ## Running testcase B.1.a
+  # testing echange of "A" (f5bc6836db60)
+  ## initial state
+  # obstore: main
+  f6fbb35d8ac958bbe70035e4c789c18471cdc0af 0 {'date': '0 0', 'p1': 'f5bc6836db60e308a17ba08bf050154ba9c4fad7', 'user': 'test'}
+  # obstore: pushdest
+  # obstore: pulldest
+  ## pushing "A" from main to pushdest
+  pushing to pushdest
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  OBSEXC: computing relevant nodes
+  OBSEXC: computing markers relevant to 2 nodes
+  OBSEXC: encoding 1 markers
+  OBSEXC: sending 1 pushkey payload (112 bytes)
+  OBSEXC: DONE
+  ## post push state
+  # obstore: main
+  f6fbb35d8ac958bbe70035e4c789c18471cdc0af 0 {'date': '0 0', 'p1': 'f5bc6836db60e308a17ba08bf050154ba9c4fad7', 'user': 'test'}
+  # obstore: pushdest
+  f6fbb35d8ac958bbe70035e4c789c18471cdc0af 0 {'date': '0 0', 'p1': 'f5bc6836db60e308a17ba08bf050154ba9c4fad7', 'user': 'test'}
+  # obstore: pulldest
+  ## pulling "f5bc6836db60" from main into pulldest
+  pulling from main
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  OBSEXC: pull obsolescence markers
+  OBSEXC: merging obsolescence markers (89 bytes)
+  OBSEXC: 1 markers added
+  OBSEXC: DONE
+  (run 'hg update' to get a working copy)
+  ## post pull state
+  # obstore: main
+  f6fbb35d8ac958bbe70035e4c789c18471cdc0af 0 {'date': '0 0', 'p1': 'f5bc6836db60e308a17ba08bf050154ba9c4fad7', 'user': 'test'}
+  # obstore: pushdest
+  f6fbb35d8ac958bbe70035e4c789c18471cdc0af 0 {'date': '0 0', 'p1': 'f5bc6836db60e308a17ba08bf050154ba9c4fad7', 'user': 'test'}
+  # obstore: pulldest
+  f6fbb35d8ac958bbe70035e4c789c18471cdc0af 0 {'date': '0 0', 'p1': 'f5bc6836db60e308a17ba08bf050154ba9c4fad7', 'user': 'test'}
+
+Actual Test (bare push version)
+-----------------------------------
+
+  $ dotest B.1.b
+  ## Running testcase B.1.b
+  ## initial state
+  # obstore: main
+  f6fbb35d8ac958bbe70035e4c789c18471cdc0af 0 {'date': '0 0', 'p1': 'f5bc6836db60e308a17ba08bf050154ba9c4fad7', 'user': 'test'}
+  # obstore: pushdest
+  # obstore: pulldest
+  ## pushing from main to pushdest
+  pushing to pushdest
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  OBSEXC: computing relevant nodes
+  OBSEXC: computing markers relevant to 2 nodes
+  OBSEXC: encoding 1 markers
+  OBSEXC: sending 1 pushkey payload (112 bytes)
+  OBSEXC: DONE
+  ## post push state
+  # obstore: main
+  f6fbb35d8ac958bbe70035e4c789c18471cdc0af 0 {'date': '0 0', 'p1': 'f5bc6836db60e308a17ba08bf050154ba9c4fad7', 'user': 'test'}
+  # obstore: pushdest
+  f6fbb35d8ac958bbe70035e4c789c18471cdc0af 0 {'date': '0 0', 'p1': 'f5bc6836db60e308a17ba08bf050154ba9c4fad7', 'user': 'test'}
+  # obstore: pulldest
+  ## pulling from main into pulldest
+  pulling from main
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  OBSEXC: pull obsolescence markers
+  OBSEXC: merging obsolescence markers (89 bytes)
+  OBSEXC: 1 markers added
+  OBSEXC: DONE
+  (run 'hg update' to get a working copy)
+  ## post pull state
+  # obstore: main
+  f6fbb35d8ac958bbe70035e4c789c18471cdc0af 0 {'date': '0 0', 'p1': 'f5bc6836db60e308a17ba08bf050154ba9c4fad7', 'user': 'test'}
+  # obstore: pushdest
+  f6fbb35d8ac958bbe70035e4c789c18471cdc0af 0 {'date': '0 0', 'p1': 'f5bc6836db60e308a17ba08bf050154ba9c4fad7', 'user': 'test'}
+  # obstore: pulldest
+  f6fbb35d8ac958bbe70035e4c789c18471cdc0af 0 {'date': '0 0', 'p1': 'f5bc6836db60e308a17ba08bf050154ba9c4fad7', 'user': 'test'}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-exchange-B2.t	Tue Mar 04 11:31:11 2014 -0800
@@ -0,0 +1,131 @@
+
+Initial setup
+
+  $ . $TESTDIR/_exc-util.sh
+
+=== B.2 Pruned changeset on head. nothing pushed ===
+
+.. {{{
+..     ⊗ A
+..     |
+..     ● O
+.. }}}
+..
+.. Marker exist from:
+..
+..  * A (prune)
+..
+.. Command run:
+..
+..  * hg push -r O
+..  * hg push
+..
+.. Expected exchange:
+..
+..  * prune marker for A
+
+
+  $ setuprepos B.2
+  creating test repo for test case B.2
+  - pulldest
+  - main
+  - pushdest
+  cd into `main` and proceed with env setup
+  $ cd main
+  $ mkcommit A
+  $ hg prune -qd '0 0' .
+  $ hg log -G --hidden
+  x  f5bc6836db60 (draft): A
+  |
+  @  a9bdc8b26820 (public): O
+  
+  $ hg debugobsolete
+  f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  $ cd ..
+  $ cd ..
+
+
+  $ cp -r B.2 B.2.a
+  $ cp -r B.2 B.2.b
+
+Actual Test (explicite push version)
+-----------------------------------
+
+  $ dotest B.2.a O
+  ## Running testcase B.2.a
+  # testing echange of "O" (a9bdc8b26820)
+  ## initial state
+  # obstore: main
+  f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pushdest
+  # obstore: pulldest
+  ## pushing "O" from main to pushdest
+  pushing to pushdest
+  searching for changes
+  no changes found
+  OBSEXC: computing relevant nodes
+  OBSEXC: computing markers relevant to 1 nodes
+  OBSEXC: encoding 1 markers
+  OBSEXC: sending 1 pushkey payload (112 bytes)
+  OBSEXC: DONE
+  ## post push state
+  # obstore: main
+  f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pushdest
+  f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pulldest
+  ## pulling "a9bdc8b26820" from main into pulldest
+  pulling from main
+  no changes found
+  OBSEXC: pull obsolescence markers
+  OBSEXC: merging obsolescence markers (89 bytes)
+  OBSEXC: 1 markers added
+  OBSEXC: DONE
+  ## post pull state
+  # obstore: main
+  f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pushdest
+  f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pulldest
+  f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+
+Actual Test (bare push version)
+-----------------------------------
+
+  $ dotest B.2.b
+  ## Running testcase B.2.b
+  ## initial state
+  # obstore: main
+  f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pushdest
+  # obstore: pulldest
+  ## pushing from main to pushdest
+  pushing to pushdest
+  searching for changes
+  no changes found
+  OBSEXC: computing relevant nodes
+  OBSEXC: computing markers relevant to 1 nodes
+  OBSEXC: encoding 1 markers
+  OBSEXC: sending 1 pushkey payload (112 bytes)
+  OBSEXC: DONE
+  ## post push state
+  # obstore: main
+  f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pushdest
+  f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pulldest
+  ## pulling from main into pulldest
+  pulling from main
+  searching for changes
+  no changes found
+  OBSEXC: pull obsolescence markers
+  OBSEXC: merging obsolescence markers (89 bytes)
+  OBSEXC: 1 markers added
+  OBSEXC: DONE
+  ## post pull state
+  # obstore: main
+  f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pushdest
+  f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pulldest
+  f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-exchange-B3.t	Tue Mar 04 11:31:11 2014 -0800
@@ -0,0 +1,107 @@
+
+
+Initial setup
+
+  $ . $TESTDIR/_exc-util.sh
+
+=== B.3 Pruned changeset on non-pushed part of the history ===
+
+.. {{{
+..   ⊗ C
+..   |
+..   ○ B
+..   | ◔ A
+..   |/
+..   ● O
+.. }}}
+..
+.. Marker exist from:
+..
+..  * C (prune)
+..
+.. Command run:
+..
+..  * hg push -r A
+..  * hg push
+..
+.. Expected exchange:
+..
+..  * ø
+..
+.. Expected Exclude:
+..
+..  * chain from B
+
+
+  $ setuprepos B.3
+  creating test repo for test case B.3
+  - pulldest
+  - main
+  - pushdest
+  cd into `main` and proceed with env setup
+  $ cd main
+  $ mkcommit A
+  $ hg up --quiet 0
+  $ mkcommit B
+  created new head
+  $ mkcommit C
+  $ hg prune -qd '0 0' .
+  $ hg log -G --hidden
+  x  e56289ab6378 (draft): C
+  |
+  @  35b183996678 (draft): B
+  |
+  | o  f5bc6836db60 (draft): A
+  |/
+  o  a9bdc8b26820 (public): O
+  
+  $ hg debugobsolete
+  e56289ab6378dc752fd7965f8bf66b58bda740bd 0 {'date': '0 0', 'p1': '35b1839966785d5703a01607229eea932db42f87', 'user': 'test'}
+  $ cd ..
+  $ cd ..
+
+
+Actual Test
+-----------------------------------
+
+  $ dotest B.3 A
+  ## Running testcase B.3
+  # testing echange of "A" (f5bc6836db60)
+  ## initial state
+  # obstore: main
+  e56289ab6378dc752fd7965f8bf66b58bda740bd 0 {'date': '0 0', 'p1': '35b1839966785d5703a01607229eea932db42f87', 'user': 'test'}
+  # obstore: pushdest
+  # obstore: pulldest
+  ## pushing "A" from main to pushdest
+  pushing to pushdest
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  OBSEXC: computing relevant nodes
+  OBSEXC: computing markers relevant to 2 nodes
+  OBSEXC: encoding 0 markers
+  OBSEXC: sending 0 pushkey payload (0 bytes)
+  OBSEXC: DONE
+  ## post push state
+  # obstore: main
+  e56289ab6378dc752fd7965f8bf66b58bda740bd 0 {'date': '0 0', 'p1': '35b1839966785d5703a01607229eea932db42f87', 'user': 'test'}
+  # obstore: pushdest
+  # obstore: pulldest
+  ## pulling "f5bc6836db60" from main into pulldest
+  pulling from main
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  OBSEXC: pull obsolescence markers
+  OBSEXC: DONE
+  (run 'hg update' to get a working copy)
+  ## post pull state
+  # obstore: main
+  e56289ab6378dc752fd7965f8bf66b58bda740bd 0 {'date': '0 0', 'p1': '35b1839966785d5703a01607229eea932db42f87', 'user': 'test'}
+  # obstore: pushdest
+  # obstore: pulldest
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-exchange-B4.t	Tue Mar 04 11:31:11 2014 -0800
@@ -0,0 +1,157 @@
+
+Initial setup
+
+  $ . $TESTDIR/_exc-util.sh
+
+=== B.4 Pruned changeset on common part of history ===
+
+.. {{{
+..   ⊗ C
+..   | ● B
+..   | |
+..   | ● A
+..   |/
+..   ● O
+.. }}}
+..
+.. Marker exist from:
+..
+..  * C (prune)
+..
+.. Command run:
+..
+..  * hg push -r B
+..  * hg push
+..
+.. Expected exchange:
+..
+..  * prune for C
+
+
+  $ setuprepos B.4
+  creating test repo for test case B.4
+  - pulldest
+  - main
+  - pushdest
+  cd into `main` and proceed with env setup
+  $ cd main
+  $ mkcommit A
+  $ mkcommit B
+  $ hg phase --public .
+  $ hg push ../pushdest
+  pushing to ../pushdest
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 2 changesets with 2 changes to 2 files
+  $ hg push ../pulldest
+  pushing to ../pulldest
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 2 changesets with 2 changes to 2 files
+  $ hg update -q 0
+  $ mkcommit C
+  created new head
+  $ hg prune -qd '0 0' .
+  $ hg log -G --hidden
+  x  7f7f229b13a6 (draft): C
+  |
+  | o  f6fbb35d8ac9 (public): B
+  | |
+  | o  f5bc6836db60 (public): A
+  |/
+  @  a9bdc8b26820 (public): O
+  
+  $ hg debugobsolete
+  7f7f229b13a629a5b20581c6cb723f4e2ca54bed 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  $ cd ..
+  $ cd ..
+
+
+  $ cp -r B.4 B.4.a
+  $ cp -r B.4 B.4.b
+
+Actual Test (explicite push version)
+-----------------------------------
+
+  $ dotest B.4.a O
+  ## Running testcase B.4.a
+  # testing echange of "O" (a9bdc8b26820)
+  ## initial state
+  # obstore: main
+  7f7f229b13a629a5b20581c6cb723f4e2ca54bed 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pushdest
+  # obstore: pulldest
+  ## pushing "O" from main to pushdest
+  pushing to pushdest
+  searching for changes
+  no changes found
+  OBSEXC: computing relevant nodes
+  OBSEXC: computing markers relevant to 1 nodes
+  OBSEXC: encoding 1 markers
+  OBSEXC: sending 1 pushkey payload (112 bytes)
+  OBSEXC: DONE
+  ## post push state
+  # obstore: main
+  7f7f229b13a629a5b20581c6cb723f4e2ca54bed 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pushdest
+  7f7f229b13a629a5b20581c6cb723f4e2ca54bed 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pulldest
+  ## pulling "a9bdc8b26820" from main into pulldest
+  pulling from main
+  no changes found
+  OBSEXC: pull obsolescence markers
+  OBSEXC: merging obsolescence markers (89 bytes)
+  OBSEXC: 1 markers added
+  OBSEXC: DONE
+  ## post pull state
+  # obstore: main
+  7f7f229b13a629a5b20581c6cb723f4e2ca54bed 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pushdest
+  7f7f229b13a629a5b20581c6cb723f4e2ca54bed 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pulldest
+  7f7f229b13a629a5b20581c6cb723f4e2ca54bed 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+
+Actual Test (bare push version)
+-----------------------------------
+
+  $ dotest B.4.b
+  ## Running testcase B.4.b
+  ## initial state
+  # obstore: main
+  7f7f229b13a629a5b20581c6cb723f4e2ca54bed 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pushdest
+  # obstore: pulldest
+  ## pushing from main to pushdest
+  pushing to pushdest
+  searching for changes
+  no changes found
+  OBSEXC: computing relevant nodes
+  OBSEXC: computing markers relevant to 3 nodes
+  OBSEXC: encoding 1 markers
+  OBSEXC: sending 1 pushkey payload (112 bytes)
+  OBSEXC: DONE
+  ## post push state
+  # obstore: main
+  7f7f229b13a629a5b20581c6cb723f4e2ca54bed 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pushdest
+  7f7f229b13a629a5b20581c6cb723f4e2ca54bed 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pulldest
+  ## pulling from main into pulldest
+  pulling from main
+  searching for changes
+  no changes found
+  OBSEXC: pull obsolescence markers
+  OBSEXC: merging obsolescence markers (89 bytes)
+  OBSEXC: 1 markers added
+  OBSEXC: DONE
+  ## post pull state
+  # obstore: main
+  7f7f229b13a629a5b20581c6cb723f4e2ca54bed 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pushdest
+  7f7f229b13a629a5b20581c6cb723f4e2ca54bed 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pulldest
+  7f7f229b13a629a5b20581c6cb723f4e2ca54bed 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-exchange-B5.t	Tue Mar 04 11:31:11 2014 -0800
@@ -0,0 +1,185 @@
+
+
+
+Initial setup
+
+  $ . $TESTDIR/_exc-util.sh
+
+
+=== B.5 Push of a children of changeset which successors is pruned ===
+
+.. This case Mirror A.4, with pruned changeset successors.
+..
+.. {{{
+..   B ◔
+..     |
+..   A⇠ø⇠⊗ A'
+..     |/
+..     ● O
+.. }}}
+..
+.. Marker exist from:
+..
+..  * `Aø⇠○ A'`
+..  * chain from A
+..  * `A'`
+..
+.. Command run:
+..
+..  * hg push -r B
+..
+.. Expected exchange:
+..
+..  * `Aø⇠○ A'`
+..  * chain from A
+..  * `A'`
+..
+.. Extra Note:
+..
+..   I'm not totally happy about this case and I believe some more complicated
+..   graph can result in behavior wuite confusing for the user (if some tool create
+..   prune maker in a the middle of a valid chain)
+
+  $ setuprepos B.5
+  creating test repo for test case B.5
+  - pulldest
+  - main
+  - pushdest
+  cd into `main` and proceed with env setup
+  $ cd main
+  $ mkcommit A0
+  $ mkcommit B
+  $ hg up --quiet 0
+  $ mkcommit A1
+  created new head
+  $ hg debugobsolete --hidden `getid 'desc(A0)'` `getid 'desc(A1)'`
+  $ hg prune -qd '0 0' .
+  $ hg log -G --hidden
+  x  e5ea8f9c7314 (draft): A1
+  |
+  | o  06055a7959d4 (draft): B
+  | |
+  | x  28b51eb45704 (draft): A0
+  |/
+  @  a9bdc8b26820 (public): O
+  
+  $ hg debugobsolete
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  $ cd ..
+  $ cd ..
+
+  $ cp -r B.5 B.5.a
+  $ cp -r B.5 B.5.b
+
+Actual Test (explicite push version)
+-------------------------------------
+
+  $ dotest B.5.a B -f
+  ## Running testcase B.5.a
+  # testing echange of "B" (06055a7959d4)
+  ## initial state
+  # obstore: main
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pushdest
+  # obstore: pulldest
+  ## pushing "B" from main to pushdest
+  pushing to pushdest
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 2 changesets with 2 changes to 2 files
+  OBSEXC: computing relevant nodes
+  OBSEXC: computing markers relevant to 3 nodes
+  OBSEXC: encoding 2 markers
+  OBSEXC: sending 1 pushkey payload (188 bytes)
+  OBSEXC: DONE
+  ## post push state
+  # obstore: main
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pushdest
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pulldest
+  ## pulling "06055a7959d4" from main into pulldest
+  pulling from main
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 2 changesets with 2 changes to 2 files
+  OBSEXC: pull obsolescence markers
+  OBSEXC: merging obsolescence markers (150 bytes)
+  OBSEXC: 2 markers added
+  OBSEXC: DONE
+  (run 'hg update' to get a working copy)
+  1 new unstable changesets
+  ## post pull state
+  # obstore: main
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pushdest
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pulldest
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+
+Actual Test (bare push version)
+-------------------------------------
+
+  $ dotest B.5.b B -f
+  ## Running testcase B.5.b
+  # testing echange of "B" (06055a7959d4)
+  ## initial state
+  # obstore: main
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pushdest
+  # obstore: pulldest
+  ## pushing "B" from main to pushdest
+  pushing to pushdest
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 2 changesets with 2 changes to 2 files
+  OBSEXC: computing relevant nodes
+  OBSEXC: computing markers relevant to 3 nodes
+  OBSEXC: encoding 2 markers
+  OBSEXC: sending 1 pushkey payload (188 bytes)
+  OBSEXC: DONE
+  ## post push state
+  # obstore: main
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pushdest
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pulldest
+  ## pulling "06055a7959d4" from main into pulldest
+  pulling from main
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 2 changesets with 2 changes to 2 files
+  OBSEXC: pull obsolescence markers
+  OBSEXC: merging obsolescence markers (150 bytes)
+  OBSEXC: 2 markers added
+  OBSEXC: DONE
+  (run 'hg update' to get a working copy)
+  1 new unstable changesets
+  ## post pull state
+  # obstore: main
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pushdest
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pulldest
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-exchange-B6.t	Tue Mar 04 11:31:11 2014 -0800
@@ -0,0 +1,108 @@
+
+
+
+
+Initial setup
+
+  $ . $TESTDIR/_exc-util.sh
+
+== B.6 Pruned changeset with ancestors not in pushed set ===
+
+.. {{{
+..   B ø⇠⊗ B'
+..     | |
+..   A ○ |
+..     |/
+..     ● O
+.. }}}
+..
+.. Marker exist from:
+..
+..  * `Bø⇠⊗ B'`
+..  * B' prune
+..
+.. Command run:
+..
+..  * hg push -r O
+..
+.. Expected exchange:
+..
+..  * `Bø⇠⊗ B'`
+..  * B' prune
+
+  $ setuprepos B.6
+  creating test repo for test case B.6
+  - pulldest
+  - main
+  - pushdest
+  cd into `main` and proceed with env setup
+  $ cd main
+  $ mkcommit A
+  $ mkcommit B0
+  $ hg up --quiet 0
+  $ mkcommit B1
+  created new head
+  $ hg debugobsolete `getid 'desc(B0)'` `getid 'desc(B1)'`
+  $ hg prune -qd '0 0' .
+  $ hg log -G --hidden
+  x  f6298a8ac3a4 (draft): B1
+  |
+  | x  962ecf6b1afc (draft): B0
+  | |
+  | o  f5bc6836db60 (draft): A
+  |/
+  @  a9bdc8b26820 (public): O
+  
+  $ hg debugobsolete
+  962ecf6b1afc94e15c7e48fdfb76ef8abd11372b f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 {'date': '', 'user': 'test'}
+  f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  $ cd ..
+  $ cd ..
+
+Actual Test
+-------------------------------------
+
+  $ dotest B.6 O
+  ## Running testcase B.6
+  # testing echange of "O" (a9bdc8b26820)
+  ## initial state
+  # obstore: main
+  962ecf6b1afc94e15c7e48fdfb76ef8abd11372b f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 {'date': '', 'user': 'test'}
+  f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pushdest
+  # obstore: pulldest
+  ## pushing "O" from main to pushdest
+  pushing to pushdest
+  searching for changes
+  no changes found
+  OBSEXC: computing relevant nodes
+  OBSEXC: computing markers relevant to 1 nodes
+  OBSEXC: encoding 2 markers
+  OBSEXC: sending 1 pushkey payload (188 bytes)
+  OBSEXC: DONE
+  ## post push state
+  # obstore: main
+  962ecf6b1afc94e15c7e48fdfb76ef8abd11372b f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 {'date': '', 'user': 'test'}
+  f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pushdest
+  f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  962ecf6b1afc94e15c7e48fdfb76ef8abd11372b f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 {'date': '', 'user': 'test'}
+  # obstore: pulldest
+  ## pulling "a9bdc8b26820" from main into pulldest
+  pulling from main
+  no changes found
+  OBSEXC: pull obsolescence markers
+  OBSEXC: merging obsolescence markers (150 bytes)
+  OBSEXC: 2 markers added
+  OBSEXC: DONE
+  ## post pull state
+  # obstore: main
+  962ecf6b1afc94e15c7e48fdfb76ef8abd11372b f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 {'date': '', 'user': 'test'}
+  f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pushdest
+  f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  962ecf6b1afc94e15c7e48fdfb76ef8abd11372b f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 {'date': '', 'user': 'test'}
+  # obstore: pulldest
+  f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  962ecf6b1afc94e15c7e48fdfb76ef8abd11372b f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 {'date': '', 'user': 'test'}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-exchange-B7.t	Tue Mar 04 11:31:11 2014 -0800
@@ -0,0 +1,90 @@
+
+Initial setup
+
+  $ . $TESTDIR/_exc-util.sh
+
+
+=== B.7 Prune on non targeted common changeset ===
+..
+.. {{{
+..     ⊗ B
+..     |
+..     ◕ A
+..     |
+..     ● O
+.. }}}
+..
+.. Marker exist from:
+..
+..  * B (prune)
+..
+.. Command run:
+..
+..  * hg push -r O
+........  * hg push
+..
+.. Expected exchange:
+..
+..  * ø
+.......  * B (prune)
+
+  $ setuprepos B.7
+  creating test repo for test case B.7
+  - pulldest
+  - main
+  - pushdest
+  cd into `main` and proceed with env setup
+  $ cd main
+  $ mkcommit A
+  $ hg push -q ../pushdest
+  $ hg push -q ../pulldest
+  $ mkcommit B
+  $ hg prune -qd '0 0' .
+  $ hg log -G --hidden
+  x  f6fbb35d8ac9 (draft): B
+  |
+  @  f5bc6836db60 (draft): A
+  |
+  o  a9bdc8b26820 (public): O
+  
+  $ hg debugobsolete
+  f6fbb35d8ac958bbe70035e4c789c18471cdc0af 0 {'date': '0 0', 'p1': 'f5bc6836db60e308a17ba08bf050154ba9c4fad7', 'user': 'test'}
+  $ cd ..
+  $ cd ..
+
+Actual Test
+-------------------------------------
+
+  $ dotest B.7 O
+  ## Running testcase B.7
+  # testing echange of "O" (a9bdc8b26820)
+  ## initial state
+  # obstore: main
+  f6fbb35d8ac958bbe70035e4c789c18471cdc0af 0 {'date': '0 0', 'p1': 'f5bc6836db60e308a17ba08bf050154ba9c4fad7', 'user': 'test'}
+  # obstore: pushdest
+  # obstore: pulldest
+  ## pushing "O" from main to pushdest
+  pushing to pushdest
+  searching for changes
+  no changes found
+  OBSEXC: computing relevant nodes
+  OBSEXC: computing markers relevant to 1 nodes
+  OBSEXC: encoding 0 markers
+  OBSEXC: sending 0 pushkey payload (0 bytes)
+  OBSEXC: DONE
+  ## post push state
+  # obstore: main
+  f6fbb35d8ac958bbe70035e4c789c18471cdc0af 0 {'date': '0 0', 'p1': 'f5bc6836db60e308a17ba08bf050154ba9c4fad7', 'user': 'test'}
+  # obstore: pushdest
+  # obstore: pulldest
+  ## pulling "a9bdc8b26820" from main into pulldest
+  pulling from main
+  no changes found
+  OBSEXC: pull obsolescence markers
+  OBSEXC: DONE
+  ## post pull state
+  # obstore: main
+  f6fbb35d8ac958bbe70035e4c789c18471cdc0af 0 {'date': '0 0', 'p1': 'f5bc6836db60e308a17ba08bf050154ba9c4fad7', 'user': 'test'}
+  # obstore: pushdest
+  # obstore: pulldest
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-exchange-C1.t	Tue Mar 04 11:31:11 2014 -0800
@@ -0,0 +1,149 @@
+
+Initial setup
+
+  $ . $TESTDIR/_exc-util.sh
+
+=== C.1 Multiple pruned changeset atop each other ===
+.. 
+.. {{{
+..   ⊗ B
+..   |
+..   ⊗ A
+..   |
+..   ● O
+.. }}}
+.. 
+.. Marker exist from:
+.. 
+..  * A (prune)
+..  * B (prune)
+.. 
+.. Command run:
+.. 
+..  * hg push -r O
+..  * hg push
+.. 
+.. Expected exchange:
+.. 
+..  * A (prune)
+..  * B (prune)
+
+  $ setuprepos C.1
+  creating test repo for test case C.1
+  - pulldest
+  - main
+  - pushdest
+  cd into `main` and proceed with env setup
+  $ cd main
+  $ mkcommit A
+  $ mkcommit B
+  $ hg prune -qd '0 0' .^::.
+  $ hg log -G --hidden
+  x  f6fbb35d8ac9 (draft): B
+  |
+  x  f5bc6836db60 (draft): A
+  |
+  @  a9bdc8b26820 (public): O
+  
+  $ hg debugobsolete
+  f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  f6fbb35d8ac958bbe70035e4c789c18471cdc0af 0 {'date': '0 0', 'p1': 'f5bc6836db60e308a17ba08bf050154ba9c4fad7', 'user': 'test'}
+  $ cd ..
+  $ cd ..
+
+  $ cp -r C.1 C.1.a
+  $ cp -r C.1 C.1.b
+
+Actual Test (explicite push)
+-------------------------------------
+
+  $ dotest C.1.a O
+  ## Running testcase C.1.a
+  # testing echange of "O" (a9bdc8b26820)
+  ## initial state
+  # obstore: main
+  f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  f6fbb35d8ac958bbe70035e4c789c18471cdc0af 0 {'date': '0 0', 'p1': 'f5bc6836db60e308a17ba08bf050154ba9c4fad7', 'user': 'test'}
+  # obstore: pushdest
+  # obstore: pulldest
+  ## pushing "O" from main to pushdest
+  pushing to pushdest
+  searching for changes
+  no changes found
+  OBSEXC: computing relevant nodes
+  OBSEXC: computing markers relevant to 1 nodes
+  OBSEXC: encoding 2 markers
+  OBSEXC: sending 1 pushkey payload (222 bytes)
+  OBSEXC: DONE
+  ## post push state
+  # obstore: main
+  f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  f6fbb35d8ac958bbe70035e4c789c18471cdc0af 0 {'date': '0 0', 'p1': 'f5bc6836db60e308a17ba08bf050154ba9c4fad7', 'user': 'test'}
+  # obstore: pushdest
+  f6fbb35d8ac958bbe70035e4c789c18471cdc0af 0 {'date': '0 0', 'p1': 'f5bc6836db60e308a17ba08bf050154ba9c4fad7', 'user': 'test'}
+  f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pulldest
+  ## pulling "a9bdc8b26820" from main into pulldest
+  pulling from main
+  no changes found
+  OBSEXC: pull obsolescence markers
+  OBSEXC: merging obsolescence markers (177 bytes)
+  OBSEXC: 2 markers added
+  OBSEXC: DONE
+  ## post pull state
+  # obstore: main
+  f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  f6fbb35d8ac958bbe70035e4c789c18471cdc0af 0 {'date': '0 0', 'p1': 'f5bc6836db60e308a17ba08bf050154ba9c4fad7', 'user': 'test'}
+  # obstore: pushdest
+  f6fbb35d8ac958bbe70035e4c789c18471cdc0af 0 {'date': '0 0', 'p1': 'f5bc6836db60e308a17ba08bf050154ba9c4fad7', 'user': 'test'}
+  f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pulldest
+  f6fbb35d8ac958bbe70035e4c789c18471cdc0af 0 {'date': '0 0', 'p1': 'f5bc6836db60e308a17ba08bf050154ba9c4fad7', 'user': 'test'}
+  f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+
+Actual Test (bare push)
+-------------------------------------
+
+  $ dotest C.1.b
+  ## Running testcase C.1.b
+  ## initial state
+  # obstore: main
+  f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  f6fbb35d8ac958bbe70035e4c789c18471cdc0af 0 {'date': '0 0', 'p1': 'f5bc6836db60e308a17ba08bf050154ba9c4fad7', 'user': 'test'}
+  # obstore: pushdest
+  # obstore: pulldest
+  ## pushing from main to pushdest
+  pushing to pushdest
+  searching for changes
+  no changes found
+  OBSEXC: computing relevant nodes
+  OBSEXC: computing markers relevant to 1 nodes
+  OBSEXC: encoding 2 markers
+  OBSEXC: sending 1 pushkey payload (222 bytes)
+  OBSEXC: DONE
+  ## post push state
+  # obstore: main
+  f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  f6fbb35d8ac958bbe70035e4c789c18471cdc0af 0 {'date': '0 0', 'p1': 'f5bc6836db60e308a17ba08bf050154ba9c4fad7', 'user': 'test'}
+  # obstore: pushdest
+  f6fbb35d8ac958bbe70035e4c789c18471cdc0af 0 {'date': '0 0', 'p1': 'f5bc6836db60e308a17ba08bf050154ba9c4fad7', 'user': 'test'}
+  f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pulldest
+  ## pulling from main into pulldest
+  pulling from main
+  searching for changes
+  no changes found
+  OBSEXC: pull obsolescence markers
+  OBSEXC: merging obsolescence markers (177 bytes)
+  OBSEXC: 2 markers added
+  OBSEXC: DONE
+  ## post pull state
+  # obstore: main
+  f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  f6fbb35d8ac958bbe70035e4c789c18471cdc0af 0 {'date': '0 0', 'p1': 'f5bc6836db60e308a17ba08bf050154ba9c4fad7', 'user': 'test'}
+  # obstore: pushdest
+  f6fbb35d8ac958bbe70035e4c789c18471cdc0af 0 {'date': '0 0', 'p1': 'f5bc6836db60e308a17ba08bf050154ba9c4fad7', 'user': 'test'}
+  f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pulldest
+  f6fbb35d8ac958bbe70035e4c789c18471cdc0af 0 {'date': '0 0', 'p1': 'f5bc6836db60e308a17ba08bf050154ba9c4fad7', 'user': 'test'}
+  f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-exchange-C2.t	Tue Mar 04 11:31:11 2014 -0800
@@ -0,0 +1,171 @@
+
+
+Initial setup
+
+  $ . $TESTDIR/_exc-util.sh
+
+=== C.2 Pruned changeset on precursors ===
+
+.. {{{
+..   B ⊗
+..     |
+..   A ø⇠◔ A'
+..     |/
+..     ● O
+.. }}}
+..
+.. Marker exist from:
+..
+..  * A' succeed to A
+..  * B (prune)
+..
+.. Command run:
+..
+..  * hg push -r A'
+..  * hg push
+..
+.. Expected exchange:
+..
+..  * `A ø⇠o A'`
+..  * B (prune)
+
+  $ setuprepos C.2
+  creating test repo for test case C.2
+  - pulldest
+  - main
+  - pushdest
+  cd into `main` and proceed with env setup
+  $ cd main
+  $ mkcommit A0
+  $ mkcommit B
+  $ hg prune -qd '0 0' .
+  $ hg update -q 0
+  $ mkcommit A1
+  created new head
+  $ hg debugobsolete `getid 'desc(A0)'` `getid 'desc(A1)'`
+  $ hg log -G --hidden
+  @  e5ea8f9c7314 (draft): A1
+  |
+  | x  06055a7959d4 (draft): B
+  | |
+  | x  28b51eb45704 (draft): A0
+  |/
+  o  a9bdc8b26820 (public): O
+  
+  $ hg debugobsolete
+  06055a7959d4128e6e3bccfd01482e83a2db8a3a 0 {'date': '0 0', 'p1': '28b51eb45704506b5c603decd6bf7ac5e0f6a52f', 'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  $ cd ..
+  $ cd ..
+
+  $ cp -r C.2 C.2.a
+  $ cp -r C.2 C.2.b
+
+Actual Test (explicite push)
+-------------------------------------
+
+  $ dotest C.2.a A1
+  ## Running testcase C.2.a
+  # testing echange of "A1" (e5ea8f9c7314)
+  ## initial state
+  # obstore: main
+  06055a7959d4128e6e3bccfd01482e83a2db8a3a 0 {'date': '0 0', 'p1': '28b51eb45704506b5c603decd6bf7ac5e0f6a52f', 'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  # obstore: pulldest
+  ## pushing "A1" from main to pushdest
+  pushing to pushdest
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  OBSEXC: computing relevant nodes
+  OBSEXC: computing markers relevant to 2 nodes
+  OBSEXC: encoding 2 markers
+  OBSEXC: sending 1 pushkey payload (188 bytes)
+  OBSEXC: DONE
+  ## post push state
+  # obstore: main
+  06055a7959d4128e6e3bccfd01482e83a2db8a3a 0 {'date': '0 0', 'p1': '28b51eb45704506b5c603decd6bf7ac5e0f6a52f', 'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  06055a7959d4128e6e3bccfd01482e83a2db8a3a 0 {'date': '0 0', 'p1': '28b51eb45704506b5c603decd6bf7ac5e0f6a52f', 'user': 'test'}
+  # obstore: pulldest
+  ## pulling "e5ea8f9c7314" from main into pulldest
+  pulling from main
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  OBSEXC: pull obsolescence markers
+  OBSEXC: merging obsolescence markers (150 bytes)
+  OBSEXC: 2 markers added
+  OBSEXC: DONE
+  (run 'hg update' to get a working copy)
+  ## post pull state
+  # obstore: main
+  06055a7959d4128e6e3bccfd01482e83a2db8a3a 0 {'date': '0 0', 'p1': '28b51eb45704506b5c603decd6bf7ac5e0f6a52f', 'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  06055a7959d4128e6e3bccfd01482e83a2db8a3a 0 {'date': '0 0', 'p1': '28b51eb45704506b5c603decd6bf7ac5e0f6a52f', 'user': 'test'}
+  # obstore: pulldest
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  06055a7959d4128e6e3bccfd01482e83a2db8a3a 0 {'date': '0 0', 'p1': '28b51eb45704506b5c603decd6bf7ac5e0f6a52f', 'user': 'test'}
+
+Actual Test (bare push)
+-------------------------------------
+
+  $ dotest C.2.b
+  ## Running testcase C.2.b
+  ## initial state
+  # obstore: main
+  06055a7959d4128e6e3bccfd01482e83a2db8a3a 0 {'date': '0 0', 'p1': '28b51eb45704506b5c603decd6bf7ac5e0f6a52f', 'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  # obstore: pulldest
+  ## pushing from main to pushdest
+  pushing to pushdest
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  OBSEXC: computing relevant nodes
+  OBSEXC: computing markers relevant to 2 nodes
+  OBSEXC: encoding 2 markers
+  OBSEXC: sending 1 pushkey payload (188 bytes)
+  OBSEXC: DONE
+  ## post push state
+  # obstore: main
+  06055a7959d4128e6e3bccfd01482e83a2db8a3a 0 {'date': '0 0', 'p1': '28b51eb45704506b5c603decd6bf7ac5e0f6a52f', 'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  06055a7959d4128e6e3bccfd01482e83a2db8a3a 0 {'date': '0 0', 'p1': '28b51eb45704506b5c603decd6bf7ac5e0f6a52f', 'user': 'test'}
+  # obstore: pulldest
+  ## pulling from main into pulldest
+  pulling from main
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  OBSEXC: pull obsolescence markers
+  OBSEXC: merging obsolescence markers (150 bytes)
+  OBSEXC: 2 markers added
+  OBSEXC: DONE
+  (run 'hg update' to get a working copy)
+  ## post pull state
+  # obstore: main
+  06055a7959d4128e6e3bccfd01482e83a2db8a3a 0 {'date': '0 0', 'p1': '28b51eb45704506b5c603decd6bf7ac5e0f6a52f', 'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  06055a7959d4128e6e3bccfd01482e83a2db8a3a 0 {'date': '0 0', 'p1': '28b51eb45704506b5c603decd6bf7ac5e0f6a52f', 'user': 'test'}
+  # obstore: pulldest
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  06055a7959d4128e6e3bccfd01482e83a2db8a3a 0 {'date': '0 0', 'p1': '28b51eb45704506b5c603decd6bf7ac5e0f6a52f', 'user': 'test'}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-exchange-C3.t	Tue Mar 04 11:31:11 2014 -0800
@@ -0,0 +1,173 @@
+
+
+Initial setup
+
+  $ . $TESTDIR/_exc-util.sh
+
+
+=== C.3 Pruned changeset on precursors of another pruned one ===
+
+.. {{{
+..   B ⊗
+..     |
+..   A ø⇠⊗ A'
+..     |/
+..     ● O
+.. }}}
+.. 
+.. Marker exist from:
+.. 
+..  * A' succeed to A
+..  * A' (prune
+..  * B (prune)
+.. 
+.. Command run:
+.. 
+..  * hg push -r A'
+..  * hg push
+.. 
+.. Expected exchange:
+.. 
+..  * `A ø⇠⊗ A'`
+..  * A (prune)
+..  * B (prune)
+
+  $ setuprepos C.3
+  creating test repo for test case C.3
+  - pulldest
+  - main
+  - pushdest
+  cd into `main` and proceed with env setup
+  $ cd main
+  $ mkcommit A0
+  $ mkcommit B
+  $ hg prune -qd '0 0' .
+  $ hg update -q 0
+  $ mkcommit A1
+  created new head
+  $ hg debugobsolete `getid 'desc(A0)'` `getid 'desc(A1)'`
+  $ hg prune -qd '0 0' .
+  $ hg log -G --hidden
+  x  e5ea8f9c7314 (draft): A1
+  |
+  | x  06055a7959d4 (draft): B
+  | |
+  | x  28b51eb45704 (draft): A0
+  |/
+  @  a9bdc8b26820 (public): O
+  
+  $ hg debugobsolete
+  06055a7959d4128e6e3bccfd01482e83a2db8a3a 0 {'date': '0 0', 'p1': '28b51eb45704506b5c603decd6bf7ac5e0f6a52f', 'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  $ cd ..
+  $ cd ..
+
+  $ cp -r C.3 C.3.a
+  $ cp -r C.3 C.3.b
+
+Actual Test (explicite push)
+-------------------------------------
+
+  $ dotest C.3.a O
+  ## Running testcase C.3.a
+  # testing echange of "O" (a9bdc8b26820)
+  ## initial state
+  # obstore: main
+  06055a7959d4128e6e3bccfd01482e83a2db8a3a 0 {'date': '0 0', 'p1': '28b51eb45704506b5c603decd6bf7ac5e0f6a52f', 'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pushdest
+  # obstore: pulldest
+  ## pushing "O" from main to pushdest
+  pushing to pushdest
+  searching for changes
+  no changes found
+  OBSEXC: computing relevant nodes
+  OBSEXC: computing markers relevant to 1 nodes
+  OBSEXC: encoding 3 markers
+  OBSEXC: sending 1 pushkey payload (298 bytes)
+  OBSEXC: DONE
+  ## post push state
+  # obstore: main
+  06055a7959d4128e6e3bccfd01482e83a2db8a3a 0 {'date': '0 0', 'p1': '28b51eb45704506b5c603decd6bf7ac5e0f6a52f', 'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pushdest
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  06055a7959d4128e6e3bccfd01482e83a2db8a3a 0 {'date': '0 0', 'p1': '28b51eb45704506b5c603decd6bf7ac5e0f6a52f', 'user': 'test'}
+  e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pulldest
+  ## pulling "a9bdc8b26820" from main into pulldest
+  pulling from main
+  no changes found
+  OBSEXC: pull obsolescence markers
+  OBSEXC: merging obsolescence markers (238 bytes)
+  OBSEXC: 3 markers added
+  OBSEXC: DONE
+  ## post pull state
+  # obstore: main
+  06055a7959d4128e6e3bccfd01482e83a2db8a3a 0 {'date': '0 0', 'p1': '28b51eb45704506b5c603decd6bf7ac5e0f6a52f', 'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pushdest
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  06055a7959d4128e6e3bccfd01482e83a2db8a3a 0 {'date': '0 0', 'p1': '28b51eb45704506b5c603decd6bf7ac5e0f6a52f', 'user': 'test'}
+  e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pulldest
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  06055a7959d4128e6e3bccfd01482e83a2db8a3a 0 {'date': '0 0', 'p1': '28b51eb45704506b5c603decd6bf7ac5e0f6a52f', 'user': 'test'}
+  e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+
+Actual Test (bare push)
+-------------------------------------
+
+  $ dotest C.3.b
+  ## Running testcase C.3.b
+  ## initial state
+  # obstore: main
+  06055a7959d4128e6e3bccfd01482e83a2db8a3a 0 {'date': '0 0', 'p1': '28b51eb45704506b5c603decd6bf7ac5e0f6a52f', 'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pushdest
+  # obstore: pulldest
+  ## pushing from main to pushdest
+  pushing to pushdest
+  searching for changes
+  no changes found
+  OBSEXC: computing relevant nodes
+  OBSEXC: computing markers relevant to 1 nodes
+  OBSEXC: encoding 3 markers
+  OBSEXC: sending 1 pushkey payload (298 bytes)
+  OBSEXC: DONE
+  ## post push state
+  # obstore: main
+  06055a7959d4128e6e3bccfd01482e83a2db8a3a 0 {'date': '0 0', 'p1': '28b51eb45704506b5c603decd6bf7ac5e0f6a52f', 'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pushdest
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  06055a7959d4128e6e3bccfd01482e83a2db8a3a 0 {'date': '0 0', 'p1': '28b51eb45704506b5c603decd6bf7ac5e0f6a52f', 'user': 'test'}
+  e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pulldest
+  ## pulling from main into pulldest
+  pulling from main
+  searching for changes
+  no changes found
+  OBSEXC: pull obsolescence markers
+  OBSEXC: merging obsolescence markers (238 bytes)
+  OBSEXC: 3 markers added
+  OBSEXC: DONE
+  ## post pull state
+  # obstore: main
+  06055a7959d4128e6e3bccfd01482e83a2db8a3a 0 {'date': '0 0', 'p1': '28b51eb45704506b5c603decd6bf7ac5e0f6a52f', 'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pushdest
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  06055a7959d4128e6e3bccfd01482e83a2db8a3a 0 {'date': '0 0', 'p1': '28b51eb45704506b5c603decd6bf7ac5e0f6a52f', 'user': 'test'}
+  e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pulldest
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  06055a7959d4128e6e3bccfd01482e83a2db8a3a 0 {'date': '0 0', 'p1': '28b51eb45704506b5c603decd6bf7ac5e0f6a52f', 'user': 'test'}
+  e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-exchange-C4.t	Tue Mar 04 11:31:11 2014 -0800
@@ -0,0 +1,126 @@
+
+
+Initial setup
+
+  $ . $TESTDIR/_exc-util.sh
+
+=== C.4 multiple successors, one is pruned ===
+
+.. Another case were prune are confusing? (A is killed without its successors being
+.. pushed)
+..
+.. (could split of divergence, if split see the Z section)
+..
+.. {{{
+..        A
+..    B ○⇢ø⇠⊗ C
+..       \|/
+..        ● O
+.. }}}
+..
+.. Marker exist from:
+..
+..  * `A ø⇠○ B`
+..  * `A ø⇠○ C`
+..  * C (prune)
+..
+..
+.. Command run:
+..
+..  * hg push -r O
+..
+.. Expected exchange:
+..
+..  * `A ø⇠○ C`
+..  * C (prune)
+..
+.. Expected exclude:
+..
+..  * `A ø⇠○ B`
+
+Implemented as the non-split version
+
+  $ setuprepos C.4
+  creating test repo for test case C.4
+  - pulldest
+  - main
+  - pushdest
+  cd into `main` and proceed with env setup
+  $ cd main
+  $ mkcommit A
+  $ hg update -q 0
+  $ mkcommit B
+  created new head
+  $ hg update -q 0
+  $ mkcommit C
+  created new head
+  $ hg debugobsolete --hidden `getid 'desc(A)'` `getid 'desc(B)'`
+  $ hg debugobsolete --hidden `getid 'desc(A)'` `getid 'desc(C)'`
+  invalid branchheads cache (served): tip differs
+  $ hg prune -qd '0 0' .
+  $ hg log -G --hidden
+  x  7f7f229b13a6 (draft): C
+  |
+  | o  35b183996678 (draft): B
+  |/
+  | x  f5bc6836db60 (draft): A
+  |/
+  @  a9bdc8b26820 (public): O
+  
+  $ hg debugobsolete
+  f5bc6836db60e308a17ba08bf050154ba9c4fad7 35b1839966785d5703a01607229eea932db42f87 0 {'date': '', 'user': 'test'}
+  f5bc6836db60e308a17ba08bf050154ba9c4fad7 7f7f229b13a629a5b20581c6cb723f4e2ca54bed 0 {'date': '', 'user': 'test'}
+  7f7f229b13a629a5b20581c6cb723f4e2ca54bed 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  $ cd ..
+  $ cd ..
+
+Actual Test
+-------------------------------------
+
+  $ dotest C.4 O
+  ## Running testcase C.4
+  # testing echange of "O" (a9bdc8b26820)
+  ## initial state
+  # obstore: main
+  f5bc6836db60e308a17ba08bf050154ba9c4fad7 35b1839966785d5703a01607229eea932db42f87 0 {'date': '', 'user': 'test'}
+  f5bc6836db60e308a17ba08bf050154ba9c4fad7 7f7f229b13a629a5b20581c6cb723f4e2ca54bed 0 {'date': '', 'user': 'test'}
+  7f7f229b13a629a5b20581c6cb723f4e2ca54bed 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pushdest
+  # obstore: pulldest
+  ## pushing "O" from main to pushdest
+  pushing to pushdest
+  searching for changes
+  no changes found
+  OBSEXC: computing relevant nodes
+  OBSEXC: computing markers relevant to 1 nodes
+  OBSEXC: encoding 2 markers
+  OBSEXC: sending 1 pushkey payload (188 bytes)
+  OBSEXC: DONE
+  ## post push state
+  # obstore: main
+  f5bc6836db60e308a17ba08bf050154ba9c4fad7 35b1839966785d5703a01607229eea932db42f87 0 {'date': '', 'user': 'test'}
+  f5bc6836db60e308a17ba08bf050154ba9c4fad7 7f7f229b13a629a5b20581c6cb723f4e2ca54bed 0 {'date': '', 'user': 'test'}
+  7f7f229b13a629a5b20581c6cb723f4e2ca54bed 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pushdest
+  f5bc6836db60e308a17ba08bf050154ba9c4fad7 7f7f229b13a629a5b20581c6cb723f4e2ca54bed 0 {'date': '', 'user': 'test'}
+  7f7f229b13a629a5b20581c6cb723f4e2ca54bed 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pulldest
+  ## pulling "a9bdc8b26820" from main into pulldest
+  pulling from main
+  no changes found
+  OBSEXC: pull obsolescence markers
+  OBSEXC: merging obsolescence markers (150 bytes)
+  OBSEXC: 2 markers added
+  OBSEXC: DONE
+  ## post pull state
+  # obstore: main
+  f5bc6836db60e308a17ba08bf050154ba9c4fad7 35b1839966785d5703a01607229eea932db42f87 0 {'date': '', 'user': 'test'}
+  f5bc6836db60e308a17ba08bf050154ba9c4fad7 7f7f229b13a629a5b20581c6cb723f4e2ca54bed 0 {'date': '', 'user': 'test'}
+  7f7f229b13a629a5b20581c6cb723f4e2ca54bed 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pushdest
+  f5bc6836db60e308a17ba08bf050154ba9c4fad7 7f7f229b13a629a5b20581c6cb723f4e2ca54bed 0 {'date': '', 'user': 'test'}
+  7f7f229b13a629a5b20581c6cb723f4e2ca54bed 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pulldest
+  f5bc6836db60e308a17ba08bf050154ba9c4fad7 7f7f229b13a629a5b20581c6cb723f4e2ca54bed 0 {'date': '', 'user': 'test'}
+  7f7f229b13a629a5b20581c6cb723f4e2ca54bed 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-exchange-D1.t	Tue Mar 04 11:31:11 2014 -0800
@@ -0,0 +1,112 @@
+
+Initial setup
+
+  $ . $TESTDIR/_exc-util.sh
+
+=== D.1 Pruned changeset based on a missing precursors of something we miss ===
+
+.. {{{
+..   B ⊗
+..     |
+..   A ◌⇠◔ A'
+..     |/
+..     ● O
+.. }}}
+..
+.. Marker exist from:
+..
+..  * A' succeed to A
+..  * B (prune)
+..
+.. Command run:
+..
+..  * hg push -r A'
+..  * hg push
+..
+.. Expected exchange:
+..
+..  * `A ø⇠o A'`
+..  * B (prune)
+
+  $ setuprepos D.1
+  creating test repo for test case D.1
+  - pulldest
+  - main
+  - pushdest
+  cd into `main` and proceed with env setup
+  $ cd main
+  $ mkcommit A0
+  $ mkcommit B
+  $ hg up -q 0
+  $ mkcommit A1
+  created new head
+  $ hg debugobsolete `getid 'desc(A0)'` `getid 'desc(A1)'`
+  $ hg prune -d '0 0' 'desc(B)'
+  1 changesets pruned
+  $ hg strip --hidden -q 'desc(A0)'
+  $ hg log -G --hidden
+  @  e5ea8f9c7314 (draft): A1
+  |
+  o  a9bdc8b26820 (public): O
+  
+  $ hg debugobsolete
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  06055a7959d4128e6e3bccfd01482e83a2db8a3a 0 {'date': '0 0', 'p1': '28b51eb45704506b5c603decd6bf7ac5e0f6a52f', 'user': 'test'}
+  $ cd ..
+  $ cd ..
+
+Actual Test
+-------------------------------------
+
+  $ dotest D.1 A1
+  ## Running testcase D.1
+  # testing echange of "A1" (e5ea8f9c7314)
+  ## initial state
+  # obstore: main
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  06055a7959d4128e6e3bccfd01482e83a2db8a3a 0 {'date': '0 0', 'p1': '28b51eb45704506b5c603decd6bf7ac5e0f6a52f', 'user': 'test'}
+  # obstore: pushdest
+  # obstore: pulldest
+  ## pushing "A1" from main to pushdest
+  pushing to pushdest
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  OBSEXC: computing relevant nodes
+  OBSEXC: computing markers relevant to 2 nodes
+  OBSEXC: encoding 2 markers
+  OBSEXC: sending 1 pushkey payload (188 bytes)
+  OBSEXC: DONE
+  ## post push state
+  # obstore: main
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  06055a7959d4128e6e3bccfd01482e83a2db8a3a 0 {'date': '0 0', 'p1': '28b51eb45704506b5c603decd6bf7ac5e0f6a52f', 'user': 'test'}
+  # obstore: pushdest
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  06055a7959d4128e6e3bccfd01482e83a2db8a3a 0 {'date': '0 0', 'p1': '28b51eb45704506b5c603decd6bf7ac5e0f6a52f', 'user': 'test'}
+  # obstore: pulldest
+  ## pulling "e5ea8f9c7314" from main into pulldest
+  pulling from main
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  OBSEXC: pull obsolescence markers
+  OBSEXC: merging obsolescence markers (150 bytes)
+  OBSEXC: 2 markers added
+  OBSEXC: DONE
+  (run 'hg update' to get a working copy)
+  ## post pull state
+  # obstore: main
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  06055a7959d4128e6e3bccfd01482e83a2db8a3a 0 {'date': '0 0', 'p1': '28b51eb45704506b5c603decd6bf7ac5e0f6a52f', 'user': 'test'}
+  # obstore: pushdest
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  06055a7959d4128e6e3bccfd01482e83a2db8a3a 0 {'date': '0 0', 'p1': '28b51eb45704506b5c603decd6bf7ac5e0f6a52f', 'user': 'test'}
+  # obstore: pulldest
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  06055a7959d4128e6e3bccfd01482e83a2db8a3a 0 {'date': '0 0', 'p1': '28b51eb45704506b5c603decd6bf7ac5e0f6a52f', 'user': 'test'}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-exchange-D2.t	Tue Mar 04 11:31:11 2014 -0800
@@ -0,0 +1,101 @@
+
+
+Initial setup
+
+  $ . $TESTDIR/_exc-util.sh
+
+=== D.2 missing prune target (prune in "pushed set") ===
+
+{{{
+}}}
+
+Marker exist from:
+
+ * A' succeed to A
+ * A' (prune)
+
+Command run:
+
+ * hg push
+
+Expected exchange:
+
+ * `A ø⇠o A'`
+ * A' (prune)
+
+
+  $ setuprepos D.2
+  creating test repo for test case D.2
+  - pulldest
+  - main
+  - pushdest
+  cd into `main` and proceed with env setup
+  $ cd main
+  $ mkcommit A0
+  $ hg up -q 0
+  $ mkcommit A1
+  created new head
+  $ hg debugobsolete `getid 'desc(A0)'` `getid 'desc(A1)'`
+  $ hg prune --date '0 0' .
+  1 changesets pruned
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  working directory now at a9bdc8b26820
+  $ hg strip --hidden -q 'desc(A1)'
+  $ hg log -G --hidden
+  x  28b51eb45704 (draft): A0
+  |
+  @  a9bdc8b26820 (public): O
+  
+  $ hg debugobsolete
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  $ cd ..
+  $ cd ..
+
+Actual Test
+-------------------------------------
+
+  $ dotest D.2
+  ## Running testcase D.2
+  ## initial state
+  # obstore: main
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pushdest
+  # obstore: pulldest
+  ## pushing from main to pushdest
+  pushing to pushdest
+  searching for changes
+  no changes found
+  OBSEXC: computing relevant nodes
+  OBSEXC: computing markers relevant to 1 nodes
+  OBSEXC: encoding 2 markers
+  OBSEXC: sending 1 pushkey payload (188 bytes)
+  OBSEXC: DONE
+  ## post push state
+  # obstore: main
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pushdest
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pulldest
+  ## pulling from main into pulldest
+  pulling from main
+  searching for changes
+  no changes found
+  OBSEXC: pull obsolescence markers
+  OBSEXC: merging obsolescence markers (150 bytes)
+  OBSEXC: 2 markers added
+  OBSEXC: DONE
+  ## post pull state
+  # obstore: main
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pushdest
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+  # obstore: pulldest
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '0 0', 'p1': 'a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04', 'user': 'test'}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-exchange-D3.t	Tue Mar 04 11:31:11 2014 -0800
@@ -0,0 +1,97 @@
+
+
+
+Initial setup
+
+  $ . $TESTDIR/_exc-util.sh
+
+=== D.2 missing prune target (prune in "pushed set") ===
+
+{{{
+}}}
+
+Marker exist from:
+
+ * A' succeed to A
+ * A' (prune)
+
+Command run:
+
+ * hg push
+
+Expected exchange:
+
+ * `A ø⇠o A'`
+ * A' (prune)
+
+
+  $ setuprepos D.2
+  creating test repo for test case D.2
+  - pulldest
+  - main
+  - pushdest
+  cd into `main` and proceed with env setup
+  $ cd main
+  $ mkcommit A0
+  $ hg up -q 0
+  $ mkcommit B
+  created new head
+  $ mkcommit A1
+  $ hg debugobsolete `getid 'desc(A0)'` `getid 'desc(A1)'`
+  $ hg prune -d '0 0' .
+  1 changesets pruned
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  working directory now at 35b183996678
+  $ hg strip --hidden -q 'desc(A1)'
+  $ hg log -G --hidden
+  @  35b183996678 (draft): B
+  |
+  | x  28b51eb45704 (draft): A0
+  |/
+  o  a9bdc8b26820 (public): O
+  
+  $ hg debugobsolete
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f 6aa67a7b4baa6fb41b06aed38d5b1201436546e2 0 {'date': '', 'user': 'test'}
+  6aa67a7b4baa6fb41b06aed38d5b1201436546e2 0 {'date': '0 0', 'p1': '35b1839966785d5703a01607229eea932db42f87', 'user': 'test'}
+  $ cd ..
+  $ cd ..
+
+Actual Test
+-------------------------------------
+
+  $ dotest D.2 O
+  ## Running testcase D.2
+  # testing echange of "O" (a9bdc8b26820)
+  ## initial state
+  # obstore: main
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f 6aa67a7b4baa6fb41b06aed38d5b1201436546e2 0 {'date': '', 'user': 'test'}
+  6aa67a7b4baa6fb41b06aed38d5b1201436546e2 0 {'date': '0 0', 'p1': '35b1839966785d5703a01607229eea932db42f87', 'user': 'test'}
+  # obstore: pushdest
+  # obstore: pulldest
+  ## pushing "O" from main to pushdest
+  pushing to pushdest
+  searching for changes
+  no changes found
+  OBSEXC: computing relevant nodes
+  OBSEXC: computing markers relevant to 1 nodes
+  OBSEXC: encoding 0 markers
+  OBSEXC: sending 0 pushkey payload (0 bytes)
+  OBSEXC: DONE
+  ## post push state
+  # obstore: main
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f 6aa67a7b4baa6fb41b06aed38d5b1201436546e2 0 {'date': '', 'user': 'test'}
+  6aa67a7b4baa6fb41b06aed38d5b1201436546e2 0 {'date': '0 0', 'p1': '35b1839966785d5703a01607229eea932db42f87', 'user': 'test'}
+  # obstore: pushdest
+  # obstore: pulldest
+  ## pulling "a9bdc8b26820" from main into pulldest
+  pulling from main
+  no changes found
+  OBSEXC: pull obsolescence markers
+  OBSEXC: DONE
+  ## post pull state
+  # obstore: main
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f 6aa67a7b4baa6fb41b06aed38d5b1201436546e2 0 {'date': '', 'user': 'test'}
+  6aa67a7b4baa6fb41b06aed38d5b1201436546e2 0 {'date': '0 0', 'p1': '35b1839966785d5703a01607229eea932db42f87', 'user': 'test'}
+  # obstore: pushdest
+  # obstore: pulldest
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-exchange-D4.t	Tue Mar 04 11:31:11 2014 -0800
@@ -0,0 +1,133 @@
+
+
+Initial setup
+
+  $ . $TESTDIR/_exc-util.sh
+
+=== D.4 Unknown changeset in between known one ===
+
+.. Mostly a clarification case
+..
+.. {{{
+..     ø⇠◌⇠○
+..     | |/
+..     | ◔
+..     |/
+..     ● O
+..
+.. }}}
+..
+.. Should be treated as A.3 case:
+..
+.. {{{
+..
+..     ø⇠○
+..     | |
+..     | ◔
+..     |/
+..     ● O
+..
+.. }}}
+
+
+initial
+
+  $ setuprepos A.3.a
+  creating test repo for test case A.3.a
+  - pulldest
+  - main
+  - pushdest
+  cd into `main` and proceed with env setup
+  $ cd main
+  $ mkcommit A0
+  $ mkcommit B0
+  $ hg update -q 0
+  $ mkcommit A1
+  created new head
+  $ mkcommit B1
+  $ hg debugobsolete `getid 'desc(A0)'` aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+  $ hg debugobsolete aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa `getid 'desc(A1)'`
+  $ hg debugobsolete `getid 'desc(B0)'` bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+  $ hg debugobsolete bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb `getid 'desc(B1)'`
+  invalid branchheads cache (served): tip differs
+  $ hg log -G --hidden
+  @  069b05c3876d (draft): B1
+  |
+  o  e5ea8f9c7314 (draft): A1
+  |
+  | x  6e72f0a95b5e (draft): B0
+  | |
+  | x  28b51eb45704 (draft): A0
+  |/
+  o  a9bdc8b26820 (public): O
+  
+  $ hg debugobsolete
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 0 {'date': '', 'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 0 {'date': '', 'user': 'test'}
+  bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 069b05c3876d56f62895e853a501ea58ea85f68d 0 {'date': '', 'user': 'test'}
+  $ cd ..
+  $ cd ..
+
+Actual Test for first version (changeset unknown remotly)
+---------------------------------------------------------
+
+  $ dotest A.3.a A1
+  ## Running testcase A.3.a
+  # testing echange of "A1" (e5ea8f9c7314)
+  ## initial state
+  # obstore: main
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 0 {'date': '', 'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 0 {'date': '', 'user': 'test'}
+  bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 069b05c3876d56f62895e853a501ea58ea85f68d 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  # obstore: pulldest
+  ## pushing "A1" from main to pushdest
+  pushing to pushdest
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  OBSEXC: computing relevant nodes
+  OBSEXC: computing markers relevant to 2 nodes
+  OBSEXC: encoding 2 markers
+  OBSEXC: sending 1 pushkey payload (154 bytes)
+  OBSEXC: DONE
+  ## post push state
+  # obstore: main
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 0 {'date': '', 'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 0 {'date': '', 'user': 'test'}
+  bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 069b05c3876d56f62895e853a501ea58ea85f68d 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 0 {'date': '', 'user': 'test'}
+  # obstore: pulldest
+  ## pulling "e5ea8f9c7314" from main into pulldest
+  pulling from main
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  OBSEXC: pull obsolescence markers
+  OBSEXC: merging obsolescence markers (123 bytes)
+  OBSEXC: 2 markers added
+  OBSEXC: DONE
+  (run 'hg update' to get a working copy)
+  ## post pull state
+  # obstore: main
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 0 {'date': '', 'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 0 {'date': '', 'user': 'test'}
+  bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 069b05c3876d56f62895e853a501ea58ea85f68d 0 {'date': '', 'user': 'test'}
+  # obstore: pushdest
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 0 {'date': '', 'user': 'test'}
+  # obstore: pulldest
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 {'date': '', 'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 0 {'date': '', 'user': 'test'}
+
+
--- a/tests/test-obsolete.t	Tue Mar 04 11:14:24 2014 -0800
+++ b/tests/test-obsolete.t	Tue Mar 04 11:31:11 2014 -0800
@@ -181,6 +181,11 @@
   adding manifests
   adding file changes
   added 5 changesets with 5 changes to 5 files (+1 heads)
+  OBSEXC: computing relevant nodes
+  OBSEXC: computing markers relevant to 5 nodes
+  OBSEXC: encoding 2 markers
+  OBSEXC: sending 1 pushkey payload (154 bytes)
+  OBSEXC: DONE
   $ hg -R ../other-new verify
   checking changesets
   checking manifests
@@ -234,6 +239,11 @@
   adding manifests
   adding file changes
   added 1 changesets with 1 changes to 1 files (+1 heads)
+  OBSEXC: computing relevant nodes
+  OBSEXC: computing markers relevant to 5 nodes
+  OBSEXC: encoding 3 markers
+  OBSEXC: sending 1 pushkey payload (230 bytes)
+  OBSEXC: DONE
   $ qlog -R ../other-new
   5
   - 95de7fc6918d
@@ -255,6 +265,11 @@
   pushing to ../other-new
   searching for changes
   no changes found
+  OBSEXC: computing relevant nodes
+  OBSEXC: computing markers relevant to 5 nodes
+  OBSEXC: encoding 3 markers
+  OBSEXC: sending 1 pushkey payload (230 bytes)
+  OBSEXC: DONE
   [1]
 
   $ hg up --hidden -q .^ # 3
@@ -270,7 +285,11 @@
   adding manifests
   adding file changes
   added 1 changesets with 1 changes to [12] files \(\+1 heads\) (re)
-  \(run 'hg heads( \.)?' to see heads, 'hg merge' to merge\) (re)
+  OBSEXC: pull obsolescence markers
+  OBSEXC: merging obsolescence markers (245 bytes)
+  OBSEXC: 1 markers added
+  OBSEXC: DONE
+  (run 'hg heads' to see heads, 'hg merge' to merge)
   $ qlog -R ../other-new
   6
   - 909a0fb57e5d
@@ -359,7 +378,11 @@
   adding manifests
   adding file changes
   added 1 changesets with 1 changes to [12] files \(\+1 heads\) (re)
-  \(run 'hg heads( \.)?' to see heads, 'hg merge' to merge\) (re)
+  OBSEXC: pull obsolescence markers
+  OBSEXC: merging obsolescence markers (306 bytes)
+  OBSEXC: 1 markers added
+  OBSEXC: DONE
+  (run 'hg heads' to see heads, 'hg merge' to merge)
 
   $ hg up -q 7 # to check rollback update behavior
   $ qlog
@@ -526,6 +549,11 @@
   adding manifests
   adding file changes
   added 2 changesets with 1 changes to [12] files (re)
+  OBSEXC: computing relevant nodes
+  OBSEXC: computing markers relevant to 5 nodes
+  OBSEXC: encoding 7 markers
+  OBSEXC: sending 1 pushkey payload (565 bytes)
+  OBSEXC: DONE
   $ hg up -q 10
   $ mkcommit "obsol_d'''"
   created new head
@@ -537,6 +565,11 @@
   adding manifests
   adding file changes
   added 1 changesets with 1 changes to 1 files (+1 heads)
+  OBSEXC: computing relevant nodes
+  OBSEXC: computing markers relevant to 5 nodes
+  OBSEXC: encoding 8 markers
+  OBSEXC: sending 1 pushkey payload (642 bytes)
+  OBSEXC: DONE
   $ cd ..
 
 check bumped detection
@@ -687,3 +720,132 @@
   $ hg export 9468a5f5d8b2 | hg import -
   applying patch from stdin
   1 new unstable changesets
+
+
+Relevant marker computation
+==============================
+
+  $ hg log -G --hidden
+  @  changeset:   17:a5f7a21fe7bc
+  |  tag:         tip
+  |  parent:      2:4538525df7e2
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     add obsol_d''
+  |
+  | o  changeset:   16:50f11e5e3a63
+  | |  parent:      11:9468a5f5d8b2
+  | |  user:        test
+  | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  summary:     add obsolet_conflicting_d
+  | |
+  | | o  changeset:   15:705ab2a6b72e
+  | | |  parent:      10:2033b4e49474
+  | | |  user:        test
+  | | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | | |  summary:     add f
+  | | |
+  | | | x  changeset:   14:33d458d86621
+  | | | |  user:        test
+  | | | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | | | |  summary:     temporary amend commit for 0b1b6dd009c0
+  | | | |
+  | | | x  changeset:   13:0b1b6dd009c0
+  | | |/   parent:      10:2033b4e49474
+  | | |    user:        test
+  | | |    date:        Thu Jan 01 00:00:00 1970 +0000
+  | | |    summary:     add f
+  | | |
+  | | | o  changeset:   12:6db5e282cb91
+  | | |/   parent:      10:2033b4e49474
+  | | |    user:        test
+  | | |    date:        Thu Jan 01 00:00:00 1970 +0000
+  | | |    summary:     add obsol_d'''
+  | | |
+  | o |  changeset:   11:9468a5f5d8b2
+  | |/   user:        test
+  | |    date:        Thu Jan 01 00:00:00 1970 +0000
+  | |    summary:     add obsol_d''
+  | |
+  | o  changeset:   10:2033b4e49474
+  | |  parent:      4:725c380fe99b
+  | |  user:        test
+  | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  summary:     add obsol_c
+  | |
+  | | x  changeset:   9:83b5778897ad
+  | |    parent:      -1:000000000000
+  | |    user:        test
+  | |    date:        Thu Jan 01 00:00:00 1970 +0000
+  | |    summary:     add toto
+  | |
+  | | x  changeset:   8:159dfc9fa5d3
+  | | |  parent:      3:0d3f46688ccc
+  | | |  user:        test
+  | | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | | |  summary:     add obsol_d''
+  | | |
+  | | | x  changeset:   7:909a0fb57e5d
+  | | |/   parent:      3:0d3f46688ccc
+  | | |    user:        test
+  | | |    date:        Thu Jan 01 00:00:00 1970 +0000
+  | | |    summary:     add obsol_d'
+  | | |
+  | | | x  changeset:   6:95de7fc6918d
+  | | |/   parent:      3:0d3f46688ccc
+  | | |    user:        test
+  | | |    date:        Thu Jan 01 00:00:00 1970 +0000
+  | | |    summary:     add obsol_d
+  | | |
+  | | | x  changeset:   5:a7a6f2b5d8a5
+  | | |/   parent:      3:0d3f46688ccc
+  | | |    user:        test
+  | | |    date:        Thu Jan 01 00:00:00 1970 +0000
+  | | |    summary:     add d
+  | | |
+  | o |  changeset:   4:725c380fe99b
+  | | |  parent:      1:7c3bad9141dc
+  | | |  user:        test
+  | | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | | |  summary:     add obsol_c'
+  | | |
+  | | x  changeset:   3:0d3f46688ccc
+  | |/   parent:      1:7c3bad9141dc
+  | |    user:        test
+  | |    date:        Thu Jan 01 00:00:00 1970 +0000
+  | |    summary:     add obsol_c
+  | |
+  x |  changeset:   2:4538525df7e2
+  |/   user:        test
+  |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    summary:     add c
+  |
+  o  changeset:   1:7c3bad9141dc
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     add b
+  |
+  o  changeset:   0:1f0dee641bb7
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     add a
+  
+
+Simple rewrite
+
+  $ hg  --hidden debugobsoleterelevant 3
+  4538525df7e2b9f09423636c61ef63a4cb872a2d 0d3f46688ccc6e756c7e96cf64c391c411309597 0 {'date': '', 'user': 'test'}
+
+simple rewrite with a prune attached to it
+
+  $ hg debugobsoleterelevant 15
+  0b1b6dd009c037985363e2290a0b579819f659db 705ab2a6b72e2cd86edb799ebe15f2695f86143e 0 {'date': '* *', 'user': 'test'} (glob)
+  33d458d86621f3186c40bfccd77652f4a122743e 0 {'date': '* *', 'p1': '0b1b6dd009c037985363e2290a0b579819f659db', 'user': 'test'} (glob)
+
+Transitive rewrite
+
+  $ hg --hidden debugobsoleterelevant 8
+  909a0fb57e5d909f353d89e394ffd7e0890fec88 159dfc9fa5d334d7e03a0aecfc7f7ab4c3431fea 0 {'date': '', 'user': 'test'}
+  95de7fc6918dea4c9c8d5382f50649794b474c4a 909a0fb57e5d909f353d89e394ffd7e0890fec88 0 {'date': '', 'user': 'test'}
+  a7a6f2b5d8a54b81bc7aa2fba2934ad6d700a79e 95de7fc6918dea4c9c8d5382f50649794b474c4a 0 {'date': '', 'user': 'test'}
+
--- a/tests/test-prune.t	Tue Mar 04 11:14:24 2014 -0800
+++ b/tests/test-prune.t	Tue Mar 04 11:31:11 2014 -0800
@@ -43,7 +43,7 @@
   0 files updated, 0 files merged, 1 files removed, 0 files unresolved
   working directory now at 47d2a3944de8
   $ hg debugobsolete
-  9d206ffc875e1bc304590549be293be36821e66c 0 {'date': '314064000 0', 'user': 'blah'} (glob)
+  9d206ffc875e1bc304590549be293be36821e66c 0 {'date': '314064000 0', ('p1': '47d2a3944de8b013de3be9578e8e344ea2e6c097', )?'user': 'blah'} (re)
 
 prune leaving unstability behind
 
@@ -51,8 +51,8 @@
   1 changesets pruned
   2 new unstable changesets
   $ hg debugobsolete
-  9d206ffc875e1bc304590549be293be36821e66c 0 {'date': '314064000 0', 'user': 'blah'} (glob)
-  7c3bad9141dcb46ff89abf5f61856facd56e476c 0 {'date': '*', 'user': 'test'} (glob)
+  9d206ffc875e1bc304590549be293be36821e66c 0 {'date': '314064000 0', ('p1': '47d2a3944de8b013de3be9578e8e344ea2e6c097', )?'user': 'blah'} (re)
+  7c3bad9141dcb46ff89abf5f61856facd56e476c 0 {'date': '\d+ \d+', ('p1': '1f0dee641bb7258c56bd60e93edfa2405381c41e', )?'user': 'test'} (re)
 
 pruning multiple changeset at once
 
@@ -61,10 +61,10 @@
   0 files updated, 0 files merged, 3 files removed, 0 files unresolved
   working directory now at 1f0dee641bb7
   $ hg debugobsolete
-  9d206ffc875e1bc304590549be293be36821e66c 0 {'date': '314064000 0', 'user': 'blah'} (glob)
-  7c3bad9141dcb46ff89abf5f61856facd56e476c 0 {'date': '*', 'user': 'test'} (glob)
-  4538525df7e2b9f09423636c61ef63a4cb872a2d 0 {'date': '*', 'user': 'test'} (glob)
-  47d2a3944de8b013de3be9578e8e344ea2e6c097 0 {'date': '*', 'user': 'test'} (glob)
+  9d206ffc875e1bc304590549be293be36821e66c 0 {'date': '314064000 0', ('p1': '47d2a3944de8b013de3be9578e8e344ea2e6c097', )?'user': 'blah'} (re)
+  7c3bad9141dcb46ff89abf5f61856facd56e476c 0 {'date': '\d+ \d+', ('p1': '1f0dee641bb7258c56bd60e93edfa2405381c41e', )?'user': 'test'} (re)
+  4538525df7e2b9f09423636c61ef63a4cb872a2d 0 {'date': '\d+ \d+', ('p1': '7c3bad9141dcb46ff89abf5f61856facd56e476c', )?'user': 'test'} (re)
+  47d2a3944de8b013de3be9578e8e344ea2e6c097 0 {'date': '\d+ \d+', ('p1': '4538525df7e2b9f09423636c61ef63a4cb872a2d', )?'user': 'test'} (re)
 
 cannot prune public changesets
 
@@ -73,10 +73,10 @@
   (see "hg help phases" for details)
   [255]
   $ hg debugobsolete
-  9d206ffc875e1bc304590549be293be36821e66c 0 {'date': '314064000 0', 'user': 'blah'} (glob)
-  7c3bad9141dcb46ff89abf5f61856facd56e476c 0 {'date': '*', 'user': 'test'} (glob)
-  4538525df7e2b9f09423636c61ef63a4cb872a2d 0 {'date': '*', 'user': 'test'} (glob)
-  47d2a3944de8b013de3be9578e8e344ea2e6c097 0 {'date': '*', 'user': 'test'} (glob)
+  9d206ffc875e1bc304590549be293be36821e66c 0 {'date': '314064000 0', ('p1': '47d2a3944de8b013de3be9578e8e344ea2e6c097', )?'user': 'blah'} (re)
+  7c3bad9141dcb46ff89abf5f61856facd56e476c 0 {'date': '\d+ \d+', ('p1': '1f0dee641bb7258c56bd60e93edfa2405381c41e', )?'user': 'test'} (re)
+  4538525df7e2b9f09423636c61ef63a4cb872a2d 0 {'date': '\d+ \d+', ('p1': '7c3bad9141dcb46ff89abf5f61856facd56e476c', )?'user': 'test'} (re)
+  47d2a3944de8b013de3be9578e8e344ea2e6c097 0 {'date': '\d+ \d+', ('p1': '4538525df7e2b9f09423636c61ef63a4cb872a2d', )?'user': 'test'} (re)
 
 Check successors addition
 ----------------------------
@@ -118,11 +118,11 @@
   $ hg prune 'desc("add ee")' -s 'desc("add nE")'
   1 changesets pruned
   $ hg debugobsolete
-  9d206ffc875e1bc304590549be293be36821e66c 0 {'date': '314064000 0', 'user': 'blah'} (glob)
-  7c3bad9141dcb46ff89abf5f61856facd56e476c 0 {'date': '*', 'user': 'test'} (glob)
-  4538525df7e2b9f09423636c61ef63a4cb872a2d 0 {'date': '*', 'user': 'test'} (glob)
-  47d2a3944de8b013de3be9578e8e344ea2e6c097 0 {'date': '*', 'user': 'test'} (glob)
-  bb5e90a7ea1f3b4b38b23150a4a597b6146d70ef 6e8148413dd541855b72a920a90c06fca127c7e7 0 {'date': '*', 'user': 'test'} (glob)
+  9d206ffc875e1bc304590549be293be36821e66c 0 {'date': '314064000 0', ('p1': '47d2a3944de8b013de3be9578e8e344ea2e6c097', )?'user': 'blah'} (re)
+  7c3bad9141dcb46ff89abf5f61856facd56e476c 0 {'date': '\d+ \d+', ('p1': '1f0dee641bb7258c56bd60e93edfa2405381c41e', )?'user': 'test'} (re)
+  4538525df7e2b9f09423636c61ef63a4cb872a2d 0 {'date': '\d+ \d+', ('p1': '7c3bad9141dcb46ff89abf5f61856facd56e476c', )?'user': 'test'} (re)
+  47d2a3944de8b013de3be9578e8e344ea2e6c097 0 {'date': '\d+ \d+', ('p1': '4538525df7e2b9f09423636c61ef63a4cb872a2d', )?'user': 'test'} (re)
+  bb5e90a7ea1f3b4b38b23150a4a597b6146d70ef 6e8148413dd541855b72a920a90c06fca127c7e7 0 {'date': '\d+ \d+', 'user': 'test'} (re)
   $ hg log -G
   @  12:6e8148413dd5[] (stable/draft) add nE
   |
@@ -146,10 +146,10 @@
   $ hg prune 'desc("add dd")' -s 'desc("add nD")' -s 'desc("add nC")'
   1 changesets pruned
   $ hg debugobsolete
-  9d206ffc875e1bc304590549be293be36821e66c 0 {'date': '314064000 0', 'user': 'blah'} (glob)
-  7c3bad9141dcb46ff89abf5f61856facd56e476c 0 {'date': '*', 'user': 'test'} (glob)
-  4538525df7e2b9f09423636c61ef63a4cb872a2d 0 {'date': '*', 'user': 'test'} (glob)
-  47d2a3944de8b013de3be9578e8e344ea2e6c097 0 {'date': '*', 'user': 'test'} (glob)
+  9d206ffc875e1bc304590549be293be36821e66c 0 {'date': '314064000 0', ('p1': '47d2a3944de8b013de3be9578e8e344ea2e6c097', )?'user': 'blah'} (re)
+  7c3bad9141dcb46ff89abf5f61856facd56e476c 0 {'date': '\d+ \d+', ('p1': '1f0dee641bb7258c56bd60e93edfa2405381c41e', )?'user': 'test'} (re)
+  4538525df7e2b9f09423636c61ef63a4cb872a2d 0 {'date': '\d+ \d+', ('p1': '7c3bad9141dcb46ff89abf5f61856facd56e476c', )?'user': 'test'} (re)
+  47d2a3944de8b013de3be9578e8e344ea2e6c097 0 {'date': '\d+ \d+', ('p1': '4538525df7e2b9f09423636c61ef63a4cb872a2d', )?'user': 'test'} (re)
   bb5e90a7ea1f3b4b38b23150a4a597b6146d70ef 6e8148413dd541855b72a920a90c06fca127c7e7 0 {'date': '*', 'user': 'test'} (glob)
   00ded550b1e28bba454bd34cec1269d22cf3ef25 aa96dc3f04c2c2341fe6880aeb6dc9fbffff9ef9 8ee176ff1d4b2034ce51e3efc579c2de346b631d 0 {'date': '**', 'user': 'test'} (glob)
   $ hg log -G
@@ -174,10 +174,10 @@
   abort: Can't use multiple successors for multiple precursors
   [255]
   $ hg debugobsolete
-  9d206ffc875e1bc304590549be293be36821e66c 0 {'date': '314064000 0', 'user': 'blah'} (glob)
-  7c3bad9141dcb46ff89abf5f61856facd56e476c 0 {'date': '*', 'user': 'test'} (glob)
-  4538525df7e2b9f09423636c61ef63a4cb872a2d 0 {'date': '*', 'user': 'test'} (glob)
-  47d2a3944de8b013de3be9578e8e344ea2e6c097 0 {'date': '*', 'user': 'test'} (glob)
+  9d206ffc875e1bc304590549be293be36821e66c 0 {'date': '314064000 0', ('p1': '47d2a3944de8b013de3be9578e8e344ea2e6c097', )?'user': 'blah'} (re)
+  7c3bad9141dcb46ff89abf5f61856facd56e476c 0 {'date': '\d+ \d+', ('p1': '1f0dee641bb7258c56bd60e93edfa2405381c41e', )?'user': 'test'} (re)
+  4538525df7e2b9f09423636c61ef63a4cb872a2d 0 {'date': '\d+ \d+', ('p1': '7c3bad9141dcb46ff89abf5f61856facd56e476c', )?'user': 'test'} (re)
+  47d2a3944de8b013de3be9578e8e344ea2e6c097 0 {'date': '\d+ \d+', ('p1': '4538525df7e2b9f09423636c61ef63a4cb872a2d', )?'user': 'test'} (re)
   bb5e90a7ea1f3b4b38b23150a4a597b6146d70ef 6e8148413dd541855b72a920a90c06fca127c7e7 0 {'date': '*', 'user': 'test'} (glob)
   00ded550b1e28bba454bd34cec1269d22cf3ef25 aa96dc3f04c2c2341fe6880aeb6dc9fbffff9ef9 8ee176ff1d4b2034ce51e3efc579c2de346b631d 0 {'date': '**', 'user': 'test'} (glob)
 
@@ -186,10 +186,10 @@
   $ hg prune 'desc("add cc")' 'desc("add bb")' -s 'desc("add nB")'
   2 changesets pruned
   $ hg debugobsolete
-  9d206ffc875e1bc304590549be293be36821e66c 0 {'date': '314064000 0', 'user': 'blah'} (glob)
-  7c3bad9141dcb46ff89abf5f61856facd56e476c 0 {'date': '*', 'user': 'test'} (glob)
-  4538525df7e2b9f09423636c61ef63a4cb872a2d 0 {'date': '*', 'user': 'test'} (glob)
-  47d2a3944de8b013de3be9578e8e344ea2e6c097 0 {'date': '*', 'user': 'test'} (glob)
+  9d206ffc875e1bc304590549be293be36821e66c 0 {'date': '314064000 0', ('p1': '47d2a3944de8b013de3be9578e8e344ea2e6c097', )?'user': 'blah'} (re)
+  7c3bad9141dcb46ff89abf5f61856facd56e476c 0 {'date': '\d+ \d+', ('p1': '1f0dee641bb7258c56bd60e93edfa2405381c41e', )?'user': 'test'} (re)
+  4538525df7e2b9f09423636c61ef63a4cb872a2d 0 {'date': '\d+ \d+', ('p1': '7c3bad9141dcb46ff89abf5f61856facd56e476c', )?'user': 'test'} (re)
+  47d2a3944de8b013de3be9578e8e344ea2e6c097 0 {'date': '\d+ \d+', ('p1': '4538525df7e2b9f09423636c61ef63a4cb872a2d', )?'user': 'test'} (re)
   bb5e90a7ea1f3b4b38b23150a4a597b6146d70ef 6e8148413dd541855b72a920a90c06fca127c7e7 0 {'date': '*', 'user': 'test'} (glob)
   00ded550b1e28bba454bd34cec1269d22cf3ef25 aa96dc3f04c2c2341fe6880aeb6dc9fbffff9ef9 8ee176ff1d4b2034ce51e3efc579c2de346b631d 0 {'date': '**', 'user': 'test'} (glob)
   814c38b95e72dfe2cbf675b1649ea9d780c89a80 6f6f25e4f748d8f7571777e6e168aedf50350ce8 0 {'date': '*', 'user': 'test'} (glob)
@@ -208,10 +208,10 @@
   0 files updated, 0 files merged, 2 files removed, 0 files unresolved
   working directory now at 1f0dee641bb7
   $ hg debugobsolete
-  9d206ffc875e1bc304590549be293be36821e66c 0 {'date': '314064000 0', 'user': 'blah'} (glob)
-  7c3bad9141dcb46ff89abf5f61856facd56e476c 0 {'date': '*', 'user': 'test'} (glob)
-  4538525df7e2b9f09423636c61ef63a4cb872a2d 0 {'date': '*', 'user': 'test'} (glob)
-  47d2a3944de8b013de3be9578e8e344ea2e6c097 0 {'date': '*', 'user': 'test'} (glob)
+  9d206ffc875e1bc304590549be293be36821e66c 0 {'date': '314064000 0', ('p1': '47d2a3944de8b013de3be9578e8e344ea2e6c097', )?'user': 'blah'} (re)
+  7c3bad9141dcb46ff89abf5f61856facd56e476c 0 {'date': '\d+ \d+', ('p1': '1f0dee641bb7258c56bd60e93edfa2405381c41e', )?'user': 'test'} (re)
+  4538525df7e2b9f09423636c61ef63a4cb872a2d 0 {'date': '\d+ \d+', ('p1': '7c3bad9141dcb46ff89abf5f61856facd56e476c', )?'user': 'test'} (re)
+  47d2a3944de8b013de3be9578e8e344ea2e6c097 0 {'date': '\d+ \d+', ('p1': '4538525df7e2b9f09423636c61ef63a4cb872a2d', )?'user': 'test'} (re)
   bb5e90a7ea1f3b4b38b23150a4a597b6146d70ef 6e8148413dd541855b72a920a90c06fca127c7e7 0 {'date': '*', 'user': 'test'} (glob)
   00ded550b1e28bba454bd34cec1269d22cf3ef25 aa96dc3f04c2c2341fe6880aeb6dc9fbffff9ef9 8ee176ff1d4b2034ce51e3efc579c2de346b631d 0 {'date': '**', 'user': 'test'} (glob)
   814c38b95e72dfe2cbf675b1649ea9d780c89a80 6f6f25e4f748d8f7571777e6e168aedf50350ce8 0 {'date': '* *', 'user': 'test'} (glob)
@@ -256,3 +256,28 @@
   abort: unknown revision '2702dd0c91e7'!
   [255]
 
+  $ hg debugobsstorestat
+  markers total:                      4
+      for known precursors:           4
+      with parents data:              [04] (re)
+  markers with no successors:         4
+                1 successors:         0
+                2 successors:         0
+      more than 2 successors:         0
+  average meta length:               (27|71) (re)
+      available  keys:
+                 date:                4
+                   p1:                [04] (re)
+                 user:                4
+  disconnected clusters:              4
+          any known node:             4
+          smallest length:            1
+          longer length:              1
+          median length:              1
+          mean length:                1
+      using parents data:             [42] (re)
+          any known node:             4
+          smallest length:            1
+          longer length:              [13] (re)
+          median length:              [13] (re)
+          mean length:                [12] (re)
--- a/tests/test-tutorial.t	Tue Mar 04 11:14:24 2014 -0800
+++ b/tests/test-tutorial.t	Tue Mar 04 11:31:11 2014 -0800
@@ -224,6 +224,8 @@
   adding manifests
   adding file changes
   added 1 changesets with 1 changes to 1 files (+1 heads)
+  OBSEXC: pull obsolescence markers
+  OBSEXC: DONE
   (run 'hg heads' to see heads, 'hg merge' to merge)
 
 I now have a new heads. Note that this remote head is immutable
@@ -402,6 +404,11 @@
   adding manifests
   adding file changes
   added 3 changesets with 3 changes to 1 files
+  OBSEXC: computing relevant nodes
+  OBSEXC: computing markers relevant to 5 nodes
+  OBSEXC: encoding 6 markers
+  OBSEXC: sending 1 pushkey payload (609 bytes)
+  OBSEXC: DONE
 
 for simplicity sake we get the bathroom change in line again
 
@@ -509,6 +516,10 @@
   adding manifests
   adding file changes
   added 1 changesets with 1 changes to 1 files
+  OBSEXC: pull obsolescence markers
+  OBSEXC: merging obsolescence markers (560 bytes)
+  OBSEXC: 1 markers added
+  OBSEXC: DONE
   (run 'hg update' to get a working copy)
   $ hg log -G
   o  75954b8cd933 (public): bathroom stuff
@@ -565,6 +576,10 @@
   adding manifests
   adding file changes
   added 1 changesets with 1 changes to 1 files
+  OBSEXC: pull obsolescence markers
+  OBSEXC: merging obsolescence markers (560 bytes)
+  OBSEXC: 1 markers added
+  OBSEXC: DONE
   (run 'hg update' to get a working copy)
   $ hg log -G
   o  75954b8cd933 (draft): bathroom stuff
@@ -624,6 +639,10 @@
   adding manifests
   adding file changes
   added 1 changesets with 1 changes to 1 files (+1 heads)
+  OBSEXC: pull obsolescence markers
+  OBSEXC: merging obsolescence markers (560 bytes)
+  OBSEXC: 0 markers added
+  OBSEXC: DONE
   (run 'hg heads' to see heads, 'hg merge' to merge)
   1 new unstable changesets
 
@@ -712,6 +731,11 @@
   adding manifests
   adding file changes
   added 2 changesets with 2 changes to 1 files (+1 heads)
+  OBSEXC: computing relevant nodes
+  OBSEXC: computing markers relevant to 7 nodes
+  OBSEXC: encoding 10 markers
+  OBSEXC: sending 1 pushkey payload (1004 bytes)
+  OBSEXC: DONE
 
 remote get a warning that current working directory is based on an obsolete changeset
 
@@ -720,6 +744,10 @@
   pulling from $TESTTMP/local
   searching for changes
   no changes found
+  OBSEXC: pull obsolescence markers
+  OBSEXC: merging obsolescence markers (803 bytes)
+  OBSEXC: 0 markers added
+  OBSEXC: DONE
   working directory parent is obsolete!
 
 now let's see where we are, and update to the successor
@@ -749,6 +777,10 @@
   adding manifests
   adding file changes
   added 1 changesets with 1 changes to 1 files
+  OBSEXC: pull obsolescence markers
+  OBSEXC: merging obsolescence markers (803 bytes)
+  OBSEXC: 0 markers added
+  OBSEXC: DONE
   (run 'hg update' to get a working copy)
   $ hg log -G
   o  99f039c5ec9e (draft): SPAM SPAM SPAM