--- a/README Tue Mar 14 14:47:20 2017 -0700
+++ b/README Fri Mar 31 15:44:10 2017 +0200
@@ -57,7 +57,7 @@
$ hg clone https://www.mercurial-scm.org/repo/evolve/
$ cd evolve
- $ make install-home
+ $ pip install --user .
Then just enable it in you hgrc::
@@ -67,8 +67,8 @@
Documentation lives in ``doc/``.
-Server Only Version
-===================
+Server Only Setup
+=================
It is possible to enable a smaller subset of the extensions aimed at server
serving repository. It skips the additions of the new commands and local UI
@@ -87,8 +87,9 @@
.. _evolution: https://bz.mercurial-scm.org/buglist.cgi?component=evolution&query_format=advanced&resolution=---
-Please use the patchbomb extension to send email to mercurial devel. Please
-make sure to use the evolve-ext flag when doing so. You can use a command like
+Please use the patchbomb extension to send email to `mercurial devel
+<https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel>`_. Please make
+sure to use the evolve-ext flag when doing so. You can use a command like
this::
$ hg email --to mercurial-devel@mercurial-scm.org --flag evolve-ext --rev '<your patches>'
@@ -114,6 +115,7 @@
6.0.0 -- In progress
--------------------
+- push: improved detection of obsoleted remote branch (issue4354),
- drop compatibility for Mercurial < 3.8,
- removed old (unpackaged) pushexperiment extension,
- move all extensions in the official 'hgext3rd' namespace package,
@@ -125,6 +127,24 @@
to disable obsmarkers echange. The old '__temporary__.advertiseobsolete'
option is no longer supported.
+- a new prototype of obsmarker discovery is available. The prototype is still
+ at early stage and not recommended for production.
+ Examples of current limitations:
+
+ - write access to the repo is highly recommanded for all operation,
+ - large memory footprint,
+ - initial caching is slow,
+ - unusable on large repo (because of various issue pointed earlier),
+ - likely to constains various bugs.
+
+ It can be tested by setting `experimental.obshashrange=1` on both client and
+ server. It is recommanded to get in touch with the evolve maintainer if you
+ decide to test it.
+
+- the 'debugrecordpruneparents' have been moved into the 'evolve.legacy'
+ separate extension. enable that extentions if you need to convert/update
+ markers in an old repository.
+
5.6.1 -- 2017-02-28
-------------------
--- a/hgext3rd/evolve/__init__.py Tue Mar 14 14:47:20 2017 -0700
+++ b/hgext3rd/evolve/__init__.py Fri Mar 31 15:44:10 2017 +0200
@@ -111,6 +111,8 @@
from mercurial.node import nullid
from . import (
+ checkheads,
+ debugcmd,
obsdiscovery,
obsexchange,
exthelper,
@@ -143,8 +145,10 @@
# - Older format compat
eh = exthelper.exthelper()
+eh.merge(debugcmd.eh)
eh.merge(obsdiscovery.eh)
eh.merge(obsexchange.eh)
+eh.merge(checkheads.eh)
uisetup = eh.final_uisetup
extsetup = eh.final_extsetup
reposetup = eh.final_reposetup
@@ -814,153 +818,6 @@
_deprecatealias('gup', 'next')
_deprecatealias('gdown', 'previous')
-@eh.command('debugrecordpruneparents', [], '')
-def cmddebugrecordpruneparents(ui, repo):
- """add parent data to prune markers when possible
-
- This command searches the repo for prune markers without parent information.
- If the pruned node is locally known, it creates a new marker with parent
- data.
- """
- 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]
- parents = tuple(p.node() for p in ctx.parents())
- before = len(store._all)
- store.create(tr, mark[0], mark[1], mark[2], mark[3],
- parents=parents)
- 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:
- lockmod.release(tr, lock, wlock)
-
-@eh.command('debugobsstorestat', [], '')
-def cmddebugobsstorestat(ui, repo):
- """print statistics about obsolescence markers in the repo"""
- def _updateclustermap(nodes, mark, clustersmap):
- 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
-
- 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
- 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
- meta = mark[3]
- for key, value in meta:
- metakeys.setdefault(key, 0)
- metakeys[key] += 1
- meta = dict(meta)
- 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(mark[1])
- nodes.add(mark[0])
- _updateclustermap(nodes, mark, clustersmap)
- # same with parent data
- nodes.update(parents)
- _updateclustermap(nodes, mark, pclustersmap)
-
- # 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((' 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))
-
def _solveone(ui, repo, ctx, dryrun, confirm, progresscb, category):
"""Resolve the troubles affecting one revision"""
wlock = lock = tr = None
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hgext3rd/evolve/checkheads.py Fri Mar 31 15:44:10 2017 +0200
@@ -0,0 +1,281 @@
+# Code dedicated to the postprocessing new heads check with obsolescence
+#
+# Copyright 2017 Pierre-Yves David <pierre-yves.david@ens-lyon.org>
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+
+import functools
+
+from mercurial import (
+ discovery,
+ error,
+ extensions,
+ node as nodemod,
+ phases,
+ util,
+)
+
+from mercurial.i18n import _
+
+from . import exthelper
+
+nullid = nodemod.nullid
+short = nodemod.short
+_headssummary = discovery._headssummary
+_oldheadssummary = discovery._oldheadssummary
+_nowarnheads = discovery._nowarnheads
+
+eh = exthelper.exthelper()
+
+@eh.uisetup
+def setupcheckheadswrapper(ui):
+ if util.safehasattr(discovery, '_postprocessobsolete'):
+ extensions.wrapfunction(discovery, '_postprocessobsolete',
+ checkheadslightoverlay)
+ else:
+ extensions.wrapfunction(discovery, 'checkheads',
+ checkheadsfulloverlay)
+
+# have dedicated wrapper to keep the rest as close as core as possible
+def checkheadsfulloverlay(orig, pushop):
+ if pushop.repo.obsstore:
+ return corecheckheads(pushop)
+ else:
+ return orig(pushop)
+
+def checkheadslightoverlay(orig, *args, **kwargs):
+ return _postprocessobsolete(*args, **kwargs)
+
+# copied from mercurial.discovery.checkheads as in a5bad127128d (4.1)
+#
+# The only differences are:
+# * the _postprocessobsolete section have been extracted,
+# * minor test adjustment to please flake8
+def corecheckheads(pushop):
+ """Check that a push won't add any outgoing head
+
+ raise Abort error and display ui message as needed.
+ """
+
+ repo = pushop.repo.unfiltered()
+ remote = pushop.remote
+ outgoing = pushop.outgoing
+ remoteheads = pushop.remoteheads
+ newbranch = pushop.newbranch
+ inc = bool(pushop.incoming)
+
+ # Check for each named branch if we're creating new remote heads.
+ # To be a remote head after push, node must be either:
+ # - unknown locally
+ # - a local outgoing head descended from update
+ # - a remote head that's known locally and not
+ # ancestral to an outgoing head
+ if remoteheads == [nullid]:
+ # remote is empty, nothing to check.
+ return
+
+ if remote.capable('branchmap'):
+ headssum = _headssummary(repo, remote, outgoing)
+ else:
+ headssum = _oldheadssummary(repo, remoteheads, outgoing, inc)
+ newbranches = [branch for branch, heads in headssum.iteritems()
+ if heads[0] is None]
+ # 1. Check for new branches on the remote.
+ if newbranches and not newbranch: # new branch requires --new-branch
+ branchnames = ', '.join(sorted(newbranches))
+ raise error.Abort(_("push creates new remote branches: %s!")
+ % branchnames,
+ hint=_("use 'hg push --new-branch' to create"
+ " new remote branches"))
+
+ # 2. Find heads that we need not warn about
+ nowarnheads = _nowarnheads(pushop)
+
+ # 3. Check for new heads.
+ # If there are more heads after the push than before, a suitable
+ # error message, depending on unsynced status, is displayed.
+ errormsg = None
+ # If there is no obsstore, allfuturecommon won't be used, so no
+ # need to compute it.
+ if repo.obsstore:
+ allmissing = set(outgoing.missing)
+ cctx = repo.set('%ld', outgoing.common)
+ allfuturecommon = set(c.node() for c in cctx)
+ allfuturecommon.update(allmissing)
+ for branch, heads in sorted(headssum.iteritems()):
+ remoteheads, newheads, unsyncedheads = heads
+ candidate_newhs = set(newheads)
+ # add unsynced data
+ if remoteheads is None:
+ oldhs = set()
+ else:
+ oldhs = set(remoteheads)
+ oldhs.update(unsyncedheads)
+ candidate_newhs.update(unsyncedheads)
+ dhs = None # delta heads, the new heads on branch
+ if not repo.obsstore:
+ discardedheads = set()
+ newhs = candidate_newhs
+ else:
+ newhs, discardedheads = _postprocessobsolete(pushop,
+ allfuturecommon,
+ candidate_newhs)
+ unsynced = sorted(h for h in unsyncedheads if h not in discardedheads)
+ if unsynced:
+ if None in unsynced:
+ # old remote, no heads data
+ heads = None
+ elif len(unsynced) <= 4 or repo.ui.verbose:
+ heads = ' '.join(short(h) for h in unsynced)
+ else:
+ heads = (' '.join(short(h) for h in unsynced[:4]) +
+ ' ' + _("and %s others") % (len(unsynced) - 4))
+ if heads is None:
+ repo.ui.status(_("remote has heads that are "
+ "not known locally\n"))
+ elif branch is None:
+ repo.ui.status(_("remote has heads that are "
+ "not known locally: %s\n") % heads)
+ else:
+ repo.ui.status(_("remote has heads on branch '%s' that are "
+ "not known locally: %s\n") % (branch, heads))
+ if remoteheads is None:
+ if len(newhs) > 1:
+ dhs = list(newhs)
+ if errormsg is None:
+ errormsg = (_("push creates new branch '%s' "
+ "with multiple heads") % (branch))
+ hint = _("merge or"
+ " see 'hg help push' for details about"
+ " pushing new heads")
+ elif len(newhs) > len(oldhs):
+ # remove bookmarked or existing remote heads from the new heads list
+ dhs = sorted(newhs - nowarnheads - oldhs)
+ if dhs:
+ if errormsg is None:
+ if branch not in ('default', None):
+ errormsg = _("push creates new remote head %s "
+ "on branch '%s'!") % (short(dhs[0]), branch)
+ elif repo[dhs[0]].bookmarks():
+ errormsg = (_("push creates new remote head %s "
+ "with bookmark '%s'!")
+ % (short(dhs[0]), repo[dhs[0]].bookmarks()[0]))
+ else:
+ errormsg = _("push creates new remote head %s!"
+ ) % short(dhs[0])
+ if unsyncedheads:
+ hint = _("pull and merge or"
+ " see 'hg help push' for details about"
+ " pushing new heads")
+ else:
+ hint = _("merge or"
+ " see 'hg help push' for details about"
+ " pushing new heads")
+ if branch is None:
+ repo.ui.note(_("new remote heads:\n"))
+ else:
+ repo.ui.note(_("new remote heads on branch '%s':\n") % branch)
+ for h in dhs:
+ repo.ui.note((" %s\n") % short(h))
+ if errormsg:
+ raise error.Abort(errormsg, hint=hint)
+
+def _postprocessobsolete(pushop, futurecommon, candidate):
+ """post process the list of new heads with obsolescence information
+
+ Exist as a subfunction to contains the complexity and allow extensions to
+ experiment with smarter logic.
+ Returns (newheads, discarded_heads) tuple
+ """
+ # remove future heads which are actually obsoleted by another
+ # pushed element:
+ #
+ # known issue
+ #
+ # * We "silently" skip processing on all changeset unknown locally
+ #
+ # * if <nh> is public on the remote, it won't be affected by obsolete
+ # marker and a new is created
+ repo = pushop.repo
+ unfi = repo.unfiltered()
+ tonode = unfi.changelog.node
+ public = phases.public
+ getphase = unfi._phasecache.phase
+ ispublic = (lambda r: getphase(unfi, r) == public)
+ hasoutmarker = functools.partial(pushingmarkerfor, unfi.obsstore, futurecommon)
+ successorsmarkers = unfi.obsstore.successors
+ newhs = set()
+ discarded = set()
+ # I leave the print in the code because they are so handy at debugging
+ # and I keep getting back to this piece of code.
+ #
+ localcandidate = set()
+ unknownheads = set()
+ for h in candidate:
+ if h in unfi:
+ localcandidate.add(h)
+ else:
+ if successorsmarkers.get(h) is not None:
+ msg = ('checkheads: remote head unknown locally has'
+ ' local marker: %s\n')
+ repo.ui.debug(msg % nodemod.hex(h))
+ unknownheads.add(h)
+ if len(localcandidate) == 1:
+ return unknownheads | set(candidate), set()
+ while localcandidate:
+ nh = localcandidate.pop()
+ # run this check early to skip the revset on the whole branch
+ if (nh in futurecommon
+ or unfi[nh].phase() <= public):
+ newhs.add(nh)
+ continue
+ # XXX there is a corner case if there is a merge in the branch. we
+ # might end up with -more- heads. However, these heads are not "added"
+ # by the push, but more by the "removal" on the remote so I think is a
+ # okay to ignore them,
+ branchrevs = unfi.revs('only(%n, (%ln+%ln))',
+ nh, localcandidate, newhs)
+ branchnodes = [tonode(r) for r in branchrevs]
+
+ # The branch will still exist on the remote if
+ # * any part of it is public,
+ # * any part of it is considered part of the result by previous logic,
+ # * if we have no markers to push to obsolete it.
+ if (any(ispublic(r) for r in branchrevs)
+ or any(n in futurecommon for n in branchnodes)
+ or any(not hasoutmarker(n) for n in branchnodes)):
+ newhs.add(nh)
+ else:
+ discarded.add(nh)
+ newhs |= unknownheads
+ return newhs, discarded
+
+def pushingmarkerfor(obsstore, pushset, node):
+ """True if some markers are to be pushed for node
+
+ We cannot just look in to the pushed obsmarkers from the pushop because
+ discover might have filtered relevant markers. In addition listing all
+ markers relevant to all changeset in the pushed set would be too expensive.
+
+ The is probably some cache opportunity in this function. but it would
+ requires a two dimentions stack.
+ """
+ successorsmarkers = obsstore.successors
+ stack = [node]
+ seen = set(stack)
+ while stack:
+ current = stack.pop()
+ if current in pushset:
+ return True
+ markers = successorsmarkers.get(current, ())
+ # markers fields = ('prec', 'succs', 'flag', 'meta', 'date', 'parents')
+ for m in markers:
+ nexts = m[1] # successors
+ if not nexts: # this is a prune marker
+ nexts = m[5] # parents
+ for n in nexts:
+ if n not in seen:
+ seen.add(n)
+ stack.append(n)
+ return False
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hgext3rd/evolve/debugcmd.py Fri Mar 31 15:44:10 2017 +0200
@@ -0,0 +1,129 @@
+# Code dedicated to debug commands around evolution
+#
+# Copyright 2017 Pierre-Yves David <pierre-yves.david@ens-lyon.org>
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+
+# Status: Ready to Upstream
+#
+# * We could have the same code in core as `hg debugobsolete --stat`,
+# * We probably want a way for the extension to hook in for extra data.
+
+from mercurial import node
+
+from mercurial.i18n import _
+
+from . import exthelper
+
+eh = exthelper.exthelper()
+
+@eh.command('debugobsstorestat', [], '')
+def cmddebugobsstorestat(ui, repo):
+ """print statistics about obsolescence markers in the repo"""
+ def _updateclustermap(nodes, mark, clustersmap):
+ 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
+
+ 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
+ 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
+ meta = mark[3]
+ for key, value in meta:
+ metakeys.setdefault(key, 0)
+ metakeys[key] += 1
+ meta = dict(meta)
+ 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(mark[1])
+ nodes.add(mark[0])
+ _updateclustermap(nodes, mark, clustersmap)
+ # same with parent data
+ nodes.update(parents)
+ _updateclustermap(nodes, mark, pclustersmap)
+
+ # 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((' 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))
--- a/hgext3rd/evolve/legacy.py Tue Mar 14 14:47:20 2017 -0700
+++ b/hgext3rd/evolve/legacy.py Fri Mar 31 15:44:10 2017 +0200
@@ -26,6 +26,7 @@
from mercurial import cmdutil
from mercurial.i18n import _
+from mercurial import lock as lockmod
from mercurial.node import bin, nullid
from mercurial import util
@@ -163,3 +164,40 @@
ui.status('%i obsolete marker converted\n' % cnt)
if err:
ui.write_err('%i conversion failed. check you graph!\n' % err)
+
+@command('debugrecordpruneparents', [], '')
+def cmddebugrecordpruneparents(ui, repo):
+ """add parent data to prune markers when possible
+
+ This command searches the repo for prune markers without parent information.
+ If the pruned node is locally known, it creates a new marker with parent
+ data.
+ """
+ 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]
+ parents = tuple(p.node() for p in ctx.parents())
+ before = len(store._all)
+ store.create(tr, mark[0], mark[1], mark[2], mark[3],
+ parents=parents)
+ 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:
+ lockmod.release(tr, lock, wlock)
--- a/hgext3rd/evolve/metadata.py Tue Mar 14 14:47:20 2017 -0700
+++ b/hgext3rd/evolve/metadata.py Fri Mar 31 15:44:10 2017 +0200
@@ -5,7 +5,7 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-__version__ = '5.6.0'
+__version__ = '6.0.0.dev'
testedwith = '3.8.4 3.9.2 4.0.2 4.1'
minimumhgversion = '3.8'
buglink = 'https://bz.mercurial-scm.org/'
--- a/hgext3rd/evolve/obsdiscovery.py Tue Mar 14 14:47:20 2017 -0700
+++ b/hgext3rd/evolve/obsdiscovery.py Fri Mar 31 15:44:10 2017 +0200
@@ -5,6 +5,14 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
+# Status: Experiment in progress // open question
+#
+# The final discovery algorithm and protocol will go into core when we'll be
+# happy with it.
+#
+# Some of the code in this module is for compatiblity with older version
+# of evolve and will be eventually dropped.
+
from __future__ import absolute_import
try:
@@ -14,16 +22,13 @@
import io
StringIO = io.StringIO
-import collections
import hashlib
import heapq
-import math
+import sqlite3
import struct
+import weakref
from mercurial import (
- bundle2,
- cmdutil,
- commands,
dagutil,
error,
exchange,
@@ -42,12 +47,15 @@
from . import (
exthelper,
utility,
+ stablerange,
)
_pack = struct.pack
_unpack = struct.unpack
+_calcsize = struct.calcsize
eh = exthelper.exthelper()
+eh.merge(stablerange.eh)
obsexcmsg = utility.obsexcmsg
##########################################
@@ -145,32 +153,6 @@
### Code performing discovery ###
##################################
-def _canobshashrange(local, remote):
- return (local.ui.configbool('experimental', 'obshashrange', False)
- and remote.capable('_donotusemeever_evoext_obshashrange_1'))
-
-
-def _obshashrange_capabilities(orig, repo, proto):
- """wrapper to advertise new capability"""
- caps = orig(repo, proto)
- enabled = repo.ui.configbool('experimental', 'obshashrange', False)
- if obsolete.isenabled(repo, obsolete.exchangeopt) and enabled:
- caps = caps.split()
- caps.append('_donotusemeever_evoext_obshashrange_1')
- caps.sort()
- caps = ' '.join(caps)
- return caps
-
-@eh.extsetup
-def obshashrange_extsetup(ui):
- extensions.wrapfunction(wireproto, 'capabilities', _obshashrange_capabilities)
- # wrap command content
- oldcap, args = wireproto.commands['capabilities']
-
- def newcap(repo, proto):
- return _obshashrange_capabilities(oldcap, repo, proto)
- wireproto.commands['capabilities'] = (newcap, args)
-
def findcommonobsmarkers(ui, local, remote, probeset,
initialsamplesize=100,
fullsamplesize=200):
@@ -234,7 +216,10 @@
missing = set()
heads = local.revs('heads(%ld)', probeset)
+ local.stablerange.warmup(local)
+ rangelength = local.stablerange.rangelength
+ subranges = local.stablerange.subranges
# size of slice ?
heappop = heapq.heappop
heappush = heapq.heappush
@@ -253,7 +238,7 @@
return True
for h in heads:
- entry = _range(local, h, 0)
+ entry = (h, 0)
addentry(entry)
querycount = 0
@@ -269,21 +254,23 @@
overflow = sample[samplesize:]
sample = sample[:samplesize]
elif len(sample) < samplesize:
+ ui.debug("query %i; add more sample (target %i, current %i)\n"
+ % (querycount, samplesize, len(sample)))
# we need more sample !
needed = samplesize - len(sample)
sliceme = []
heapify(sliceme)
for entry in sample:
- if 1 < len(entry):
- heappush(sliceme, (-len(entry), entry))
+ if 1 < rangelength(local, entry):
+ heappush(sliceme, (-rangelength(local, entry), entry))
while sliceme and 0 < needed:
_key, target = heappop(sliceme)
- for new in target.subranges():
+ for new in subranges(local, target):
# XXX we could record hierarchy to optimise drop
- if addentry(entry):
- if 1 < len(entry):
- heappush(sliceme, (-len(entry), entry))
+ if addentry(new):
+ if 1 < len(new):
+ heappush(sliceme, (-rangelength(local, new), new))
needed -= 1
if needed <= 0:
break
@@ -292,181 +279,37 @@
samplesize = fullsamplesize
nbsample = len(sample)
- maxsize = max([len(r) for r in sample])
+ maxsize = max([rangelength(local, r) for r in sample])
ui.debug("query %i; sample size is %i, largest range %i\n"
- % (querycount, maxsize, nbsample))
+ % (querycount, nbsample, maxsize))
nbreplies = 0
replies = list(_queryrange(ui, local, remote, sample))
sample = []
+ n = local.changelog.node
for entry, remotehash in replies:
nbreplies += 1
- if remotehash == entry.obshash:
+ if remotehash == _obshashrange(local, entry):
continue
- elif 1 == len(entry):
- missing.add(entry.node)
+ elif 1 == rangelength(local, entry):
+ missing.add(n(entry[0]))
else:
- for new in entry.subranges():
+ for new in subranges(local, entry):
addentry(new)
assert nbsample == nbreplies
querycount += 1
ui.progress(_("comparing obsmarker with other"), querycount)
ui.progress(_("comparing obsmarker with other"), None)
+ local.obsstore.rangeobshashcache.save(local)
return sorted(missing)
def _queryrange(ui, repo, remote, allentries):
- mapping = {}
-
- def gen():
- for entry in allentries:
- key = entry.node + _pack('>I', entry.index)
- mapping[key] = entry
- yield key
-
- bundler = bundle2.bundle20(ui, bundle2.bundle2caps(remote))
- capsblob = bundle2.encodecaps(bundle2.getrepocaps(repo))
- bundler.newpart('replycaps', data=capsblob)
- bundler.newpart('_donotusemeever_evoext_obshashrange_1', data=gen())
-
- stream = util.chunkbuffer(bundler.getchunks())
- try:
- reply = remote.unbundle(
- stream, ['force'], remote.url())
- except error.BundleValueError as exc:
- raise error.Abort(_('missing support for %s') % exc)
- try:
- op = bundle2.processbundle(repo, reply)
- except error.BundleValueError as exc:
- raise error.Abort(_('missing support for %s') % exc)
- except bundle2.AbortFromPart as exc:
- ui.status(_('remote: %s\n') % exc)
- if exc.hint is not None:
- ui.status(_('remote: %s\n') % ('(%s)' % exc.hint))
- raise error.Abort(_('push failed on remote'))
- for rep in op.records['_donotusemeever_evoext_obshashrange_1']:
- yield mapping[rep['key']], rep['value']
-
-
-@bundle2.parthandler('_donotusemeever_evoext_obshashrange_1', ())
-def _processqueryrange(op, inpart):
- assert op.reply is not None
- replies = []
- data = inpart.read(24)
- while data:
- n = data[:20]
- index = _unpack('>I', data[20:])[0]
- r = op.repo.changelog.rev(n)
- rhash = _range(op.repo, r, index).obshash
- replies.append(data + rhash)
- data = inpart.read(24)
- op.reply.newpart('reply:_donotusemeever_evoext_obshashrange_1', data=iter(replies))
-
-
-@bundle2.parthandler('reply:_donotusemeever_evoext_obshashrange_1', ())
-def _processqueryrangereply(op, inpart):
- data = inpart.read(44)
- while data:
- key = data[:24]
- rhash = data[24:]
- op.records.add('_donotusemeever_evoext_obshashrange_1', {'key': key, 'value': rhash})
- data = inpart.read(44)
-
-##################################
-### Stable topological sorting ###
-##################################
-@eh.command(
- 'debugstablesort',
- [
- ('', 'rev', [], 'heads to start from'),
- ] + commands.formatteropts,
- _(''))
-def debugstablesort(ui, repo, **opts):
- """display the ::REVS set topologically sorted in a stable way
- """
- revs = scmutil.revrange(repo, opts['rev'])
- displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
- for r in _stablesort(repo, revs):
- ctx = repo[r]
- displayer.show(ctx)
- displayer.flush(ctx)
- displayer.close()
-
-def _stablesort(repo, revs):
- """return '::revs' topologically sorted in "stable" order
-
- This is a depth first traversal starting from 'nullrev', using node as a
- tie breaker.
- """
- # Various notes:
- #
- # * Bitbucket is used dates as tie breaker, that might be a good idea.
- #
- # * It seemds we can traverse in the same order from (one) head to bottom,
- # if we the following record data for each merge:
- #
- # - highest (stablesort-wise) common ancestors,
- # - order of parents (tablesort-wise)
- cl = repo.changelog
- parents = cl.parentrevs
- nullrev = node.nullrev
- n = cl.node
- # step 1: We need a parents -> children mapping for 2 reasons.
- #
- # * we build the order from nullrev to tip
- #
- # * we need to detect branching
- children = collections.defaultdict(list)
- for r in cl.ancestors(revs, inclusive=True):
- p1, p2 = parents(r)
- children[p1].append(r)
- if p2 != nullrev:
- children[p2].append(r)
- # step two: walk back up
- # * pick lowest node in case of branching
- # * stack disregarded part of the branching
- # * process merge when both parents are yielded
-
- # track what changeset has been
- seen = [0] * (max(revs) + 2)
- seen[-1] = True # nullrev is known
- # starts from repository roots
- # reuse the list form the mapping as we won't need it again anyway
- stack = children[nullrev]
- if not stack:
- return []
- if 1 < len(stack):
- stack.sort(key=n, reverse=True)
-
- # list of rev, maybe we should yield, but since we built a children mapping we are 'O(N)' already
+ # question are asked with node
+ n = repo.changelog.node
+ noderanges = [(n(entry[0]), entry[1]) for entry in allentries]
+ replies = remote.evoext_obshashrange_v0(noderanges)
result = []
-
- current = stack.pop()
- while current is not None or stack:
- if current is None:
- # previous iteration reached a merge or an unready merge,
- current = stack.pop()
- if seen[current]:
- current = None
- continue
- p1, p2 = parents(current)
- if not (seen[p1] and seen[p2]):
- # we can't iterate on this merge yet because other child is not
- # yielded yet (and we are topo sorting) we can discard it for now
- # because it will be reached from the other child.
- current = None
- continue
- assert not seen[current]
- seen[current] = True
- result.append(current) # could be yield, cf earlier comment
- cs = children[current]
- if not cs:
- current = None
- elif 1 == len(cs):
- current = cs[0]
- else:
- cs.sort(key=n, reverse=True)
- current = cs.pop() # proceed on smallest
- stack.extend(cs) # stack the rest for later
- assert len(result) == len(set(result))
+ for idx, entry in enumerate(allentries):
+ result.append((entry, replies[idx]))
return result
##############################
@@ -474,188 +317,330 @@
##############################
@eh.command(
- 'debugstablerange',
+ 'debugobshashrange',
[
- ('', 'rev', [], 'heads to start from'),
+ ('', 'rev', [], 'display obshash for all (rev, 0) range in REVS'),
+ ('', 'subranges', False, 'display all subranges'),
],
_(''))
-def debugstablerange(ui, repo, **opts):
+def debugobshashrange(ui, repo, **opts):
"""display the ::REVS set topologically sorted in a stable way
"""
s = node.short
revs = scmutil.revrange(repo, opts['rev'])
# prewarm depth cache
- for r in repo.revs("::%ld", revs):
- utility.depth(repo, r)
- toproceed = [_range(repo, r, 0, ) for r in revs]
- ranges = set(toproceed)
- while toproceed:
- entry = toproceed.pop()
- for r in entry.subranges():
- if r not in ranges:
- ranges.add(r)
- toproceed.append(r)
- ranges = list(ranges)
- ranges.sort(key=lambda r: (-len(r), r.node))
- ui.status('rev node index size depth obshash\n')
+ if revs:
+ repo.stablerange.warmup(repo, max(revs))
+ cl = repo.changelog
+ rangelength = repo.stablerange.rangelength
+ depthrev = repo.stablerange.depthrev
+ if opts['subranges']:
+ ranges = stablerange.subrangesclosure(repo, revs)
+ else:
+ ranges = [(r, 0) for r in revs]
+ headers = ('rev', 'node', 'index', 'size', 'depth', 'obshash')
+ linetemplate = '%12d %12s %12d %12d %12d %12s\n'
+ headertemplate = linetemplate.replace('d', 's')
+ ui.status(headertemplate % headers)
for r in ranges:
- d = (r.head, s(r.node), r.index, len(r), r.depth, node.short(r.obshash))
- ui.status('%3d %s %5d %4d %5d %s\n' % d)
+ d = (r[0],
+ s(cl.node(r[0])),
+ r[1],
+ rangelength(repo, r),
+ depthrev(repo, r[0]),
+ node.short(_obshashrange(repo, r)))
+ ui.status(linetemplate % d)
+ repo.obsstore.rangeobshashcache.save(repo)
-def _hlp2(i):
- """return highest power of two lower than 'i'"""
- return 2 ** int(math.log(i - 1, 2))
+def _obshashrange(repo, rangeid):
+ """return the obsolete hash associated to a range"""
+ cache = repo.obsstore.rangeobshashcache
+ cl = repo.changelog
+ obshash = cache.get(rangeid)
+ if obshash is not None:
+ return obshash
+ pieces = []
+ nullid = node.nullid
+ if repo.stablerange.rangelength(repo, rangeid) == 1:
+ rangenode = cl.node(rangeid[0])
+ tmarkers = repo.obsstore.relevantmarkers([rangenode])
+ pieces = []
+ for m in tmarkers:
+ mbin = obsolete._fm1encodeonemarker(m)
+ pieces.append(mbin)
+ pieces.sort()
+ else:
+ for subrange in repo.stablerange.subranges(repo, rangeid):
+ obshash = _obshashrange(repo, subrange)
+ if obshash != nullid:
+ pieces.append(obshash)
-class _range(object):
+ sha = hashlib.sha1()
+ # note: if there is only one subrange with actual data, we'll just
+ # reuse the same hash.
+ if not pieces:
+ obshash = node.nullid
+ elif len(pieces) != 1 or obshash is None:
+ sha = hashlib.sha1()
+ for p in pieces:
+ sha.update(p)
+ obshash = sha.digest()
+ cache[rangeid] = obshash
+ return obshash
+
+### sqlite caching
- def __init__(self, repo, head, index, revs=None):
- self._repo = repo.unfiltered()
- self.head = head
- self.index = index
- if revs is not None:
- assert len(revs) == len(self)
- self._revs = revs
- assert index < self.depth, (head, index, self.depth, revs)
+_sqliteschema = [
+ """CREATE TABLE meta(schemaversion INTEGER NOT NULL,
+ nbobsmarker INTEGER NOT NULL,
+ obstipdata BLOB NOT NULL,
+ tiprev INTEGER NOT NULL,
+ tipnode BLOB NOT NULL
+ );""",
+ """CREATE TABLE obshashrange(rev INTEGER NOT NULL,
+ idx INTEGER NOT NULL,
+ obshash BLOB NOT NULL,
+ PRIMARY KEY(rev, idx));""",
+ "CREATE INDEX range_index ON obshashrange(rev, idx);",
+]
+_queryexist = "SELECT name FROM sqlite_master WHERE type='table' AND name='meta';"
+_newmeta = """INSERT INTO meta (schemaversion, nbobsmarker, obstipdata, tiprev, tipnode)
+ VALUES (?,?,?,?,?);"""
+_updateobshash = "INSERT INTO obshashrange(rev, idx, obshash) VALUES (?,?,?);"
+_querymeta = "SELECT schemaversion, nbobsmarker, obstipdata, tiprev, tipnode FROM meta;"
+_queryobshash = "SELECT obshash FROM obshashrange WHERE (rev = ? AND idx = ?);"
- def __repr__(self):
- return '%s %d %d %s' % (node.short(self.node), self.depth, self.index, node.short(self.obshash))
+class _obshashcache(dict):
- def __hash__(self):
- return self._id
+ _schemaversion = 0
- def __eq__(self, other):
- if type(self) != type(other):
- raise NotImplementedError()
- return self.stablekey == other.stablekey
+ def __init__(self, repo):
+ super(_obshashcache, self).__init__()
+ self._path = repo.vfs.join('cache/evoext_obshashrange_v0.sqlite')
+ self._new = set()
+ self._valid = True
+ self._repo = weakref.ref(repo.unfiltered())
+ # cache status
+ self._ondiskcachekey = None
- @util.propertycache
- def _id(self):
- return hash(self.stablekey)
+ def clear(self):
+ self._valid = False
+ super(_obshashcache, self).clear()
+ self._new.clear()
- @util.propertycache
- def stablekey(self):
- return (self.node, self.index)
+ def get(self, rangeid):
+ value = super(_obshashcache, self).get(rangeid)
+ if value is None and self._con is not None:
+ nrange = (rangeid[0], rangeid[1])
+ obshash = self._con.execute(_queryobshash, nrange).fetchone()
+ if obshash is not None:
+ value = obshash[0]
+ return value
- @util.propertycache
- def node(self):
- return self._repo.changelog.node(self.head)
+ def __setitem__(self, rangeid, obshash):
+ self._new.add(rangeid)
+ super(_obshashcache, self).__setitem__(rangeid, obshash)
- def __len__(self):
- return self.depth - self.index
-
- @util.propertycache
- def depth(self):
- return utility.depth(self._repo, self.head)
+ def _cachekey(self, repo):
+ # XXX for now the cache is very volatile, but this is still a win
+ nbobsmarker = len(repo.obsstore._all)
+ if nbobsmarker:
+ tipdata = obsolete._fm1encodeonemarker(repo.obsstore._all[-1])
+ else:
+ tipdata = node.nullid
+ tiprev = len(repo.changelog) - 1
+ tipnode = repo.changelog.node(tiprev)
+ return (self._schemaversion, nbobsmarker, tipdata, tiprev, tipnode)
@util.propertycache
- def _revs(self):
- r = _stablesort(self._repo, [self.head])[self.index:]
- assert len(r) == len(self), (self.head, self.index, len(r), len(self))
- return r
-
- def _slicesat(self, globalindex):
- localindex = globalindex - self.index
-
- cl = self._repo.changelog
-
- result = []
- bottom = self._revs[:localindex]
- top = _range(self._repo, self.head, globalindex, self._revs[localindex:])
- #
- toprootdepth = utility.depth(self._repo, top._revs[0])
- if toprootdepth + len(top) == self.depth + 1:
- bheads = [bottom[-1]]
- else:
- bheads = set(bottom)
- parentrevs = cl.parentrevs
- du = bheads.difference_update
- for r in bottom:
- du(parentrevs(r))
- # if len(bheads) == 1:
- # assert 1 == len(self._repo.revs('roots(%ld)', top._revs))
- if len(bheads) == 1:
- newhead = bottom[-1]
- bottomdepth = utility.depth(self._repo, newhead)
- newstart = bottomdepth - len(bottom)
- result.append(_range(self._repo, newhead, newstart, bottom))
- else:
- # assert 1 < len(bheads), (toprootdepth, len(top), len(self))
- cl = self._repo.changelog
- for h in bheads:
- subset = cl.ancestors([h], inclusive=True)
- hrevs = [r for r in bottom if r in subset]
- start = utility.depth(self._repo, h) - len(hrevs)
- entry = _range(self._repo, h, start, [r for r in bottom if r in subset])
- result.append(entry)
- result.append(top)
- return result
+ def _con(self):
+ if not self._valid:
+ return None
+ repo = self._repo()
+ if repo is None:
+ return None
+ cachekey = self._cachekey(repo)
+ con = sqlite3.connect(self._path)
+ con.text_factory = str
+ cur = con.execute(_queryexist)
+ if cur.fetchone() is None:
+ self._valid = False
+ return None
+ meta = con.execute(_querymeta).fetchone()
+ if meta != cachekey:
+ self._valid = False
+ return None
+ self._ondiskcachekey = meta
+ return con
- def subranges(self):
- if not util.safehasattr(self._repo, '_subrangecache'):
- self._repo._subrangecache = {}
- cached = self._repo._subrangecache.get(self)
- if cached is not None:
- return cached
- if len(self) == 1:
- return []
- step = _hlp2(self.depth)
- standard_start = 0
- while standard_start < self.index and 0 < step:
- if standard_start + step < self.depth:
- standard_start += step
- step //= 2
- if self.index == standard_start:
- slicesize = _hlp2(len(self))
- slicepoint = self.index + slicesize
- else:
- assert standard_start < self.depth
- slicepoint = standard_start
- result = self._slicesat(slicepoint)
- self._repo._subrangecache[self] = result
- return result
+ def save(self, repo):
+ repo = repo.unfiltered()
+ try:
+ if not self._new:
+ return
+ with repo.lock():
+ self._save(repo)
+ except error.LockError:
+ # Exceptionnally we are noisy about it since performance impact
+ # is large We should address that before using this more
+ # widely.
+ msg = _('obshashrange cache: skipping save unable to lock repo\n')
+ repo.ui.warn(msg)
+
+ def _save(self, repo):
+ if self._con is None:
+ util.unlinkpath(self._path, ignoremissing=True)
+ if '_con' in vars(self):
+ del self._con
- @util.propertycache
- def obshash(self):
- cache = self._repo.obsstore.rangeobshashcache
- obshash = cache.get(self)
- if obshash is not None:
- return obshash
- pieces = []
- nullid = node.nullid
- if len(self) == 1:
- tmarkers = self._repo.obsstore.relevantmarkers([self.node])
- pieces = []
- for m in tmarkers:
- mbin = obsolete._fm1encodeonemarker(m)
- pieces.append(mbin)
- pieces.sort()
+ con = sqlite3.connect(self._path)
+ con.text_factory = str
+ with con:
+ for req in _sqliteschema:
+ con.execute(req)
+
+ con.execute(_newmeta, self._cachekey(repo))
else:
- for subrange in self.subranges():
- obshash = subrange.obshash
- if obshash != nullid:
- pieces.append(obshash)
-
- sha = hashlib.sha1()
- # note: if there is only one subrange with actual data, we'll just
- # reuse the same hash.
- if not pieces:
- obshash = node.nullid
- elif len(pieces) != 1 or obshash is None:
- sha = hashlib.sha1()
- for p in pieces:
- sha.update(p)
- obshash = cache[self] = sha.digest()
- return obshash
+ con = self._con
+ if self._ondiskcachekey is not None:
+ meta = con.execute(_querymeta).fetchone()
+ if meta != self._ondiskcachekey:
+ # drifting is currently an issue because this means another
+ # process might have already added the cache line we are about
+ # to add. This will confuse sqlite
+ msg = _('obshashrange cache: skipping write, '
+ 'database drifted under my feet\n')
+ data = (meta[2], meta[1], self._ondisktiprev, self._ondisktipnode)
+ repo.ui.warn(msg)
+ data = ((rangeid[0], rangeid[1], self[rangeid]) for rangeid in self._new)
+ con.executemany(_updateobshash, data)
+ cachekey = self._cachekey(repo)
+ con.execute(_newmeta, cachekey)
+ con.commit()
+ self._new.clear()
+ self._ondiskcachekey = cachekey
@eh.wrapfunction(obsolete.obsstore, '_addmarkers')
def _addmarkers(orig, obsstore, *args, **kwargs):
obsstore.rangeobshashcache.clear()
return orig(obsstore, *args, **kwargs)
-@eh.addattr(obsolete.obsstore, 'rangeobshashcache')
-@util.propertycache
-def rangeobshashcache(obsstore):
- return {}
+try:
+ obsstorefilecache = localrepo.localrepository.obsstore
+except AttributeError:
+ # XXX hg-3.8 compat
+ #
+ # mercurial 3.8 has issue with accessing file cache property from their
+ # cache. This is fix by 36fbd72c2f39fef8ad52d7c559906c2bc388760c in core
+ # and shipped in 3.9
+ obsstorefilecache = localrepo.localrepository.__dict__['obsstore']
+
+
+# obsstore is a filecache so we have do to some spacial dancing
+@eh.wrapfunction(obsstorefilecache, 'func')
+def obsstorewithcache(orig, repo):
+ obsstore = orig(repo)
+ obsstore.rangeobshashcache = _obshashcache(repo.unfiltered())
+ return obsstore
+
+@eh.reposetup
+def setupcache(ui, repo):
+
+ class obshashrepo(repo.__class__):
+ @localrepo.unfilteredmethod
+ def destroyed(self):
+ if 'stablerange' in vars(self):
+ del self.stablerange
+
+ repo.__class__ = obshashrepo
+
+### wire protocol commands
+
+def _obshashrange_v0(repo, ranges):
+ """return a list of hash from a list of range
+
+ The range have the id encoded as a node
+
+ return 'wdirid' for unknown range"""
+ nm = repo.changelog.nodemap
+ ranges = [(nm.get(n), idx) for n, idx in ranges]
+ if ranges:
+ maxrev = max(r for r, i in ranges)
+ if maxrev is not None:
+ repo.stablerange.warmup(repo, upto=maxrev)
+ result = []
+ for r in ranges:
+ if r[0] is None:
+ result.append(node.wdirid)
+ else:
+ result.append(_obshashrange(repo, r))
+ repo.obsstore.rangeobshashcache.save(repo)
+ return result
+
+@eh.addattr(localrepo.localpeer, 'evoext_obshashrange_v0')
+def local_obshashrange_v0(peer, ranges):
+ return _obshashrange_v0(peer._repo, ranges)
+
+
+_indexformat = '>I'
+_indexsize = _calcsize(_indexformat)
+def _encrange(node_rangeid):
+ """encode a (node) range"""
+ headnode, index = node_rangeid
+ return headnode + _pack(_indexformat, index)
+
+def _decrange(data):
+ """encode a (node) range"""
+ assert _indexsize < len(data), len(data)
+ headnode = data[:-_indexsize]
+ index = _unpack(_indexformat, data[-_indexsize:])[0]
+ return (headnode, index)
+
+@eh.addattr(wireproto.wirepeer, 'evoext_obshashrange_v0')
+def peer_obshashrange_v0(self, ranges):
+ binranges = [_encrange(r) for r in ranges]
+ encranges = wireproto.encodelist(binranges)
+ d = self._call("evoext_obshashrange_v0", ranges=encranges)
+ try:
+ return wireproto.decodelist(d)
+ except ValueError:
+ self._abort(error.ResponseError(_("unexpected response:"), d))
+
+def srv_obshashrange_v0(repo, proto, ranges):
+ ranges = wireproto.decodelist(ranges)
+ ranges = [_decrange(r) for r in ranges]
+ hashes = _obshashrange_v0(repo, ranges)
+ return wireproto.encodelist(hashes)
+
+
+def _canobshashrange(local, remote):
+ return (local.ui.configbool('experimental', 'obshashrange', False)
+ and remote.capable('_evoext_obshashrange_v0'))
+
+def _obshashrange_capabilities(orig, repo, proto):
+ """wrapper to advertise new capability"""
+ caps = orig(repo, proto)
+ enabled = repo.ui.configbool('experimental', 'obshashrange', False)
+ if obsolete.isenabled(repo, obsolete.exchangeopt) and enabled:
+ caps = caps.split()
+ caps.append('_evoext_obshashrange_v0')
+ caps.sort()
+ caps = ' '.join(caps)
+ return caps
+
+@eh.extsetup
+def obshashrange_extsetup(ui):
+ hgweb_mod.perms['evoext_obshashrange_v0'] = 'pull'
+
+ wireproto.commands['evoext_obshashrange_v0'] = (srv_obshashrange_v0, 'ranges')
+ ###
+ extensions.wrapfunction(wireproto, 'capabilities', _obshashrange_capabilities)
+ # wrap command content
+ oldcap, args = wireproto.commands['capabilities']
+
+ def newcap(repo, proto):
+ return _obshashrange_capabilities(oldcap, repo, proto)
+ wireproto.commands['capabilities'] = (newcap, args)
#############################
### Tree Hash computation ###
--- a/hgext3rd/evolve/obsexchange.py Tue Mar 14 14:47:20 2017 -0700
+++ b/hgext3rd/evolve/obsexchange.py Fri Mar 31 15:44:10 2017 +0200
@@ -34,7 +34,6 @@
from . import (
exthelper,
- serveronly,
utility,
obsdiscovery,
)
@@ -338,7 +337,7 @@
@eh.addattr(localrepo.localpeer, 'evoext_pushobsmarkers_0')
def local_pushobsmarkers(peer, obsfile):
data = obsfile.read()
- serveronly._pushobsmarkers(peer._repo, data)
+ _pushobsmarkers(peer._repo, data)
# compat-code: _pullobsolete
#
@@ -417,8 +416,8 @@
@eh.addattr(localrepo.localpeer, 'evoext_pullobsmarkers_0')
def local_pullobsmarkers(self, heads=None, common=None):
- return serveronly._getobsmarkersstream(self._repo, heads=heads,
- common=common)
+ return _getobsmarkersstream(self._repo, heads=heads,
+ common=common)
def _legacypush_capabilities(orig, repo, proto):
"""wrapper to advertise new capability"""
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hgext3rd/evolve/stablerange.py Fri Mar 31 15:44:10 2017 +0200
@@ -0,0 +1,907 @@
+# Code dedicated to the computation and properties of "stable ranges"
+#
+# These stable ranges are use for obsolescence markers discovery
+#
+# Copyright 2017 Pierre-Yves David <pierre-yves.david@ens-lyon.org>
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+
+import collections
+import heapq
+import math
+import sqlite3
+import weakref
+
+from mercurial import (
+ commands,
+ cmdutil,
+ error,
+ localrepo,
+ node as nodemod,
+ scmutil,
+ util,
+)
+
+from mercurial.i18n import _
+
+from . import (
+ exthelper,
+)
+
+eh = exthelper.exthelper()
+
+##################################
+### Stable topological sorting ###
+##################################
+@eh.command(
+ 'debugstablesort',
+ [
+ ('', 'rev', [], 'heads to start from'),
+ ] + commands.formatteropts,
+ _(''))
+def debugstablesort(ui, repo, **opts):
+ """display the ::REVS set topologically sorted in a stable way
+ """
+ revs = scmutil.revrange(repo, opts['rev'])
+ displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
+ for r in stablesort(repo, revs):
+ ctx = repo[r]
+ displayer.show(ctx)
+ displayer.flush(ctx)
+ displayer.close()
+
+def stablesort(repo, revs, mergecallback=None):
+ """return '::revs' topologically sorted in "stable" order
+
+ This is a depth first traversal starting from 'nullrev', using node as a
+ tie breaker.
+ """
+ # Various notes:
+ #
+ # * Bitbucket is used dates as tie breaker, that might be a good idea.
+ #
+ # * It seemds we can traverse in the same order from (one) head to bottom,
+ # if we the following record data for each merge:
+ #
+ # - highest (stablesort-wise) common ancestors,
+ # - order of parents (tablesort-wise)
+ cl = repo.changelog
+ parents = cl.parentrevs
+ nullrev = nodemod.nullrev
+ n = cl.node
+ # step 1: We need a parents -> children mapping for 2 reasons.
+ #
+ # * we build the order from nullrev to tip
+ #
+ # * we need to detect branching
+ children = collections.defaultdict(list)
+ for r in cl.ancestors(revs, inclusive=True):
+ p1, p2 = parents(r)
+ children[p1].append(r)
+ if p2 != nullrev:
+ children[p2].append(r)
+ # step two: walk back up
+ # * pick lowest node in case of branching
+ # * stack disregarded part of the branching
+ # * process merge when both parents are yielded
+
+ # track what changeset has been
+ seen = [0] * (max(revs) + 2)
+ seen[-1] = True # nullrev is known
+ # starts from repository roots
+ # reuse the list form the mapping as we won't need it again anyway
+ stack = children[nullrev]
+ if not stack:
+ return []
+ if 1 < len(stack):
+ stack.sort(key=n, reverse=True)
+
+ # list of rev, maybe we should yield, but since we built a children mapping we are 'O(N)' already
+ result = []
+
+ current = stack.pop()
+ while current is not None or stack:
+ if current is None:
+ # previous iteration reached a merge or an unready merge,
+ current = stack.pop()
+ if seen[current]:
+ current = None
+ continue
+ p1, p2 = parents(current)
+ if not (seen[p1] and seen[p2]):
+ # we can't iterate on this merge yet because other child is not
+ # yielded yet (and we are topo sorting) we can discard it for now
+ # because it will be reached from the other child.
+ current = None
+ continue
+ assert not seen[current]
+ seen[current] = True
+ result.append(current) # could be yield, cf earlier comment
+ if mergecallback is not None and p2 != nullrev:
+ mergecallback(result, current)
+ cs = children[current]
+ if not cs:
+ current = None
+ elif 1 == len(cs):
+ current = cs[0]
+ else:
+ cs.sort(key=n, reverse=True)
+ current = cs.pop() # proceed on smallest
+ stack.extend(cs) # stack the rest for later
+ assert len(result) == len(set(result))
+ return result
+
+#################################
+### Stable Range computation ###
+#################################
+
+def _hlp2(i):
+ """return highest power of two lower than 'i'"""
+ return 2 ** int(math.log(i - 1, 2))
+
+def subrangesclosure(repo, heads):
+ """set of all standard subrange under heads
+
+ This is intended for debug purposes. Range are returned from largest to
+ smallest in terms of number of revision it contains."""
+ subranges = repo.stablerange.subranges
+ toproceed = [(r, 0, ) for r in heads]
+ ranges = set(toproceed)
+ while toproceed:
+ entry = toproceed.pop()
+ for r in subranges(repo, entry):
+ if r not in ranges:
+ ranges.add(r)
+ toproceed.append(r)
+ ranges = list(ranges)
+ n = repo.changelog.node
+ rangelength = repo.stablerange.rangelength
+ ranges.sort(key=lambda r: (-rangelength(repo, r), n(r[0])))
+ return ranges
+
+@eh.command(
+ 'debugstablerange',
+ [
+ ('', 'rev', [], 'operate on (rev, 0) ranges for rev in REVS'),
+ ('', 'subranges', False, 'recursively display data for subranges too'),
+ ('', 'verify', False, 'checks subranges content (EXPENSIVE)'),
+ ],
+ _(''))
+def debugstablerange(ui, repo, **opts):
+ """display standard stable subrange for a set of ranges
+
+ Range as displayed as '<node>-<index> (<rev>, <depth>, <length>)', use
+ --verbose to get the extra details in ().
+ """
+ short = nodemod.short
+ revs = scmutil.revrange(repo, opts['rev'])
+ # prewarm depth cache
+ unfi = repo.unfiltered()
+ node = unfi.changelog.node
+ stablerange = unfi.stablerange
+ depth = stablerange.depthrev
+ length = stablerange.rangelength
+ subranges = stablerange.subranges
+ repo.stablerange.warmup(repo, max(revs))
+ if opts['subranges']:
+ ranges = subrangesclosure(repo, revs)
+ else:
+ ranges = [(r, 0) for r in revs]
+ if ui.verbose:
+ template = '%s-%d (%d, %d, %d)'
+
+ def _rangestring(repo, rangeid):
+ return template % (
+ short(node(rangeid[0])),
+ rangeid[1],
+ rangeid[0],
+ depth(unfi, rangeid[0]),
+ length(unfi, rangeid)
+ )
+ else:
+ template = '%s-%d'
+
+ def _rangestring(repo, rangeid):
+ return template % (
+ short(node(rangeid[0])),
+ rangeid[1],
+ )
+
+ for r in ranges:
+ subs = subranges(unfi, r)
+ subsstr = ', '.join(_rangestring(unfi, s) for s in subs)
+ rstr = _rangestring(unfi, r)
+ if opts['verify']:
+ status = 'leaf'
+ if 1 < length(unfi, r):
+ status = 'complete'
+ revs = set(stablerange.revsfromrange(unfi, r))
+ subrevs = set()
+ for s in subs:
+ subrevs.update(stablerange.revsfromrange(unfi, s))
+ if revs != subrevs:
+ status = 'missing'
+ ui.status('%s [%s] - %s\n' % (rstr, status, subsstr))
+ else:
+ ui.status('%s - %s\n' % (rstr, subsstr))
+
+class stablerange(object):
+
+ def __init__(self):
+ # The point up to which we have data in cache
+ self._tiprev = None
+ self._tipnode = None
+ # cache the 'depth' of a changeset, the size of '::rev'
+ self._depthcache = {}
+ # cache the standard stable subranges or a range
+ self._subrangescache = {}
+ # To slices merge, we need to walk their descendant in reverse stable
+ # sort order. For now we perform a full stable sort their descendant
+ # and then use the relevant top most part. This order is going to be
+ # the same for all ranges headed at the same merge. So we cache these
+ # value to reuse them accross the same invocation.
+ self._stablesortcache = {}
+ # something useful to compute the above
+ # mergerev -> stablesort, length
+ self._stablesortprepared = {}
+ # caching parent call # as we do so many of them
+ self._parentscache = {}
+ # The first part of the stable sorted list of revision of a merge will
+ # shared with the one of others. This means we can reuse subranges
+ # computed from that point to compute some of the subranges from the
+ # merge.
+ self._inheritancecache = {}
+
+ def warmup(self, repo, upto=None):
+ """warm the cache up"""
+ repo = repo.unfiltered()
+ cl = repo.changelog
+ # subrange should be warmed from head to range to be able to benefit
+ # from revsfromrange cache. otherwise each merge will trigger its own
+ # stablesort.
+ #
+ # we use the revnumber as an approximation for depth
+ ui = repo.ui
+
+ if upto is None:
+ upto = len(cl) - 1
+ if self._tiprev is None:
+ revs = cl.revs(stop=upto)
+ nbrevs = upto + 1
+ else:
+ assert cl.node(self._tiprev) == self._tipnode
+ if upto <= self._tiprev:
+ return
+ revs = cl.revs(start=self._tiprev + 1, stop=upto)
+ nbrevs = upto - self._tiprev
+ rangeheap = []
+ for idx, r in enumerate(revs):
+ if not idx % 1000:
+ ui.progress(_("filling depth cache"), idx, total=nbrevs)
+ # warm up depth
+ self.depthrev(repo, r)
+ rangeheap.append((-r, (r, 0)))
+ ui.progress(_("filling depth cache"), None, total=nbrevs)
+
+ heappop = heapq.heappop
+ heappush = heapq.heappush
+ heapify = heapq.heapify
+
+ original = set(rangeheap)
+ seen = 0
+ heapify(rangeheap)
+ while rangeheap:
+ value = heappop(rangeheap)
+ if value in original:
+ if not seen % 1000:
+ ui.progress(_("filling stablerange cache"), seen, total=nbrevs)
+ seen += 1
+ original.remove(value) # might have been added from other source
+ __, rangeid = value
+ if self._getsub(rangeid) is None:
+ for sub in self.subranges(repo, rangeid):
+ if self._getsub(sub) is None:
+ heappush(rangeheap, (-sub[0], sub))
+ ui.progress(_("filling stablerange cache"), None, total=nbrevs)
+
+ self._tiprev = upto
+ self._tipnode = cl.node(upto)
+
+ def depthrev(self, repo, rev):
+ repo = repo.unfiltered()
+ cl = repo.changelog
+ depth = self._getdepth
+ nullrev = nodemod.nullrev
+ stack = [rev]
+ while stack:
+ revdepth = None
+ current = stack[-1]
+ revdepth = depth(current)
+ if revdepth is not None:
+ stack.pop()
+ continue
+ p1, p2 = self._parents(current, cl.parentrevs)
+ if p1 == nullrev:
+ # root case
+ revdepth = 1
+ elif p2 == nullrev:
+ # linear commit case
+ parentdepth = depth(p1)
+ if parentdepth is None:
+ stack.append(p1)
+ else:
+ revdepth = parentdepth + 1
+ else:
+ # merge case
+ revdepth = self._depthmerge(cl, current, p1, p2, stack)
+ if revdepth is not None:
+ self._setdepth(current, revdepth)
+ stack.pop()
+ # actual_depth = len(list(cl.ancestors([rev], inclusive=True)))
+ # assert revdepth == actual_depth, (rev, revdepth, actual_depth)
+ return revdepth
+
+ def rangelength(self, repo, rangeid):
+ headrev, index = rangeid[0], rangeid[1]
+ return self.depthrev(repo, headrev) - index
+
+ def subranges(self, repo, rangeid):
+ cached = self._getsub(rangeid)
+ if cached is not None:
+ return cached
+ value = self._subranges(repo, rangeid)
+ self._setsub(rangeid, value)
+ return value
+
+ def revsfromrange(self, repo, rangeid):
+ headrev, index = rangeid
+ rangelength = self.rangelength(repo, rangeid)
+ if rangelength == 1:
+ revs = [headrev]
+ else:
+ # get all revs under heads in stable order
+ #
+ # note: In the general case we can just walk down and then request
+ # data about the merge. But I'm not sure this function will be even
+ # call for the general case.
+ allrevs = self._stablesortcache.get(headrev)
+ if allrevs is None:
+ allrevs = self._getrevsfrommerge(repo, headrev)
+ if allrevs is None:
+ allrevs = stablesort(repo, [headrev],
+ mergecallback=self._filestablesortcache)
+ self._stablesortcache[headrev] = allrevs
+ # takes from index
+ revs = allrevs[index:]
+ # sanity checks
+ assert len(revs) == rangelength
+ return revs
+
+ def _parents(self, rev, func):
+ parents = self._parentscache.get(rev)
+ if parents is None:
+ parents = func(rev)
+ self._parentscache[rev] = parents
+ return parents
+
+ def _getdepth(self, rev):
+ """utility function used to access the depth cache
+
+ This mostly exist to help the on disk persistence."""
+ return self._depthcache.get(rev)
+
+ def _setdepth(self, rev, value):
+ """utility function used to set the depth cache
+
+ This mostly exist to help the on disk persistence."""
+ self._depthcache[rev] = value
+
+ def _getsub(self, rev):
+ """utility function used to access the subranges cache
+
+ This mostly exist to help the on disk persistence"""
+ return self._subrangescache.get(rev)
+
+ def _setsub(self, rev, value):
+ """utility function used to set the subranges cache
+
+ This mostly exist to help the on disk persistence."""
+ self._subrangescache[rev] = value
+
+ def _filestablesortcache(self, sortedrevs, merge):
+ if merge not in self._stablesortprepared:
+ self._stablesortprepared[merge] = (sortedrevs, len(sortedrevs))
+
+ def _getrevsfrommerge(self, repo, merge):
+ prepared = self._stablesortprepared.get(merge)
+ if prepared is None:
+ return None
+
+ mergedepth = self.depthrev(repo, merge)
+ allrevs = prepared[0][:prepared[1]]
+ nbextrarevs = prepared[1] - mergedepth
+ if not nbextrarevs:
+ return allrevs
+
+ anc = repo.changelog.ancestors([merge], inclusive=True)
+ top = []
+ counter = nbextrarevs
+ for rev in reversed(allrevs):
+ if rev in anc:
+ top.append(rev)
+ else:
+ counter -= 1
+ if counter <= 0:
+ break
+
+ bottomidx = prepared[1] - (nbextrarevs + len(top))
+ revs = allrevs[:bottomidx]
+ revs.extend(reversed(top))
+ return revs
+
+ def _inheritancepoint(self, repo, merge):
+ """Find the inheritance point of a Merge
+
+ The first part of the stable sorted list of revision of a merge will shared with
+ the one of others. This means we can reuse subranges computed from that point to
+ compute some of the subranges from the merge.
+
+ That point is latest point in the stable sorted list where the depth of the
+ revisions match its index (that means all revision earlier in the stable sorted
+ list are its ancestors, no dangling unrelated branches exists).
+ """
+ value = self._inheritancecache.get(merge)
+ if value is None:
+ revs = self.revsfromrange(repo, (merge, 0))
+ i = reversed(revs)
+ i.next() # pop the merge
+ expected = len(revs) - 1
+ # Since we do warmup properly, we can expect the cache to be hot
+ # for everythin under the merge we investigate
+ cache = self._depthcache
+ # note: we cannot do a binary search because element under the
+ # inherited point might have mismatching depth because of inner
+ # branching.
+ for rev in i:
+ if cache[rev] == expected:
+ break
+ expected -= 1
+ value = (expected - 1, rev)
+ self._inheritancecache[merge] = value
+ return value
+
+ def _depthmerge(self, cl, rev, p1, p2, stack):
+ # sub method to simplify the main 'depthrev' one
+ revdepth = None
+ depth = self._getdepth
+ depth_p1 = depth(p1)
+ depth_p2 = depth(p2)
+ missingparent = False
+ if depth_p1 is None:
+ stack.append(p1)
+ missingparent = True
+ if depth_p2 is None:
+ stack.append(p2)
+ missingparent = True
+ if missingparent:
+ return None
+ # computin depth of a merge
+ # XXX the common ancestors heads could be cached
+ ancnodes = cl.commonancestorsheads(cl.node(p1), cl.node(p2))
+ ancrevs = [cl.rev(a) for a in ancnodes]
+ anyunkown = False
+ ancdepth = []
+ for r in ancrevs:
+ d = depth(r)
+ if d is None:
+ anyunkown = True
+ stack.append(r)
+ ancdepth.append((r, d))
+ if anyunkown:
+ return None
+ if not ancrevs:
+ # unrelated branch, (no common root)
+ revdepth = depth_p1 + depth_p2 + 1
+ elif len(ancrevs) == 1:
+ # one unique branch point:
+ # we can compute depth without any walk
+ depth_anc = ancdepth[0][1]
+ revdepth = depth_p1 + (depth_p2 - depth_anc) + 1
+ else:
+ # multiple ancestors, we pick one that is
+ # * the deepest (less changeset outside of it),
+ # * lowest revs because more chance to have descendant of other "above"
+ anc, revdepth = max(ancdepth, key=lambda x: (x[1], -x[0]))
+ revdepth += len(cl.findmissingrevs(common=[anc], heads=[rev]))
+ return revdepth
+
+ def _subranges(self, repo, rangeid):
+ if self.rangelength(repo, rangeid) == 1:
+ return []
+ slicepoint = self._slicepoint(repo, rangeid)
+
+ # make sure we have cache for all relevant parent first to prevent
+ # recursion (python is bad with recursion
+ stack = []
+ current = rangeid
+ while current is not None:
+ current = self._cold_reusable(repo, current, slicepoint)
+ if current is not None:
+ stack.append(current)
+ while stack:
+ # these call will directly compute the subranges
+ self.subranges(repo, stack.pop())
+ return self._slicesrangeat(repo, rangeid, slicepoint)
+
+ def _cold_reusable(self, repo, rangeid, slicepoint):
+ """return parent range that it would be useful to prepare to slice
+ rangeid at slicepoint
+
+ This function also have the important task to update the revscache of
+ the parent rev s if possible and needed"""
+ p1, p2 = self._parents(rangeid[0], repo.changelog.parentrevs)
+ if p2 == nodemod.nullrev:
+ # regular changesets, we pick the parent
+ reusablerev = p1
+ else:
+ # merge, we try the inheritance point
+ # if it is too low, it will be ditched by the depth check anyway
+ index, reusablerev = self._inheritancepoint(repo, rangeid[0])
+
+ # if we reached the slicepoint, no need to go further
+ if self.depthrev(repo, reusablerev) <= slicepoint:
+ return None
+
+ reurange = (reusablerev, rangeid[1])
+ # if we have an entry for the current range, lets update the cache
+ # if we already have subrange for this range, no need to prepare it.
+ if self._getsub(reurange) is not None:
+ return None
+
+ # look like we found a relevent parentrange with no cache yet
+ return reurange
+
+ def _slicepoint(self, repo, rangeid):
+ rangedepth = self.depthrev(repo, rangeid[0])
+ step = _hlp2(rangedepth)
+ standard_start = 0
+ while standard_start < rangeid[1] and 0 < step:
+ if standard_start + step < rangedepth:
+ standard_start += step
+ step //= 2
+ if rangeid[1] == standard_start:
+ slicesize = _hlp2(self.rangelength(repo, rangeid))
+ slicepoint = rangeid[1] + slicesize
+ else:
+ assert standard_start < rangedepth
+ slicepoint = standard_start
+ return slicepoint
+
+ def _slicesrangeat(self, repo, rangeid, globalindex):
+ p1, p2 = self._parents(rangeid[0], repo.changelog.parentrevs)
+ if p2 == nodemod.nullrev:
+ reuserev = p1
+ else:
+ index, reuserev = self._inheritancepoint(repo, rangeid[0])
+ if index < globalindex:
+ return self._slicesrangeatmerge(repo, rangeid, globalindex)
+
+ assert reuserev != nodemod.nullrev
+
+ reuserange = (reuserev, rangeid[1])
+ top = (rangeid[0], globalindex)
+
+ if rangeid[1] + self.rangelength(repo, reuserange) == globalindex:
+ return [reuserange, top]
+ # This will not initiate a recursion since we took appropriate
+ # precaution in the caller of this method to ensure it will be so.
+ # It the parent is a merge that will not be the case but computing
+ # subranges from a merge will not recurse.
+ reusesubranges = self.subranges(repo, reuserange)
+ slices = reusesubranges[:-1] # pop the top
+ slices.append(top)
+ return slices
+
+ def _slicesrangeatmerge(self, repo, rangeid, globalindex):
+ localindex = globalindex - rangeid[1]
+ cl = repo.changelog
+
+ result = []
+ allrevs = self.revsfromrange(repo, rangeid)
+ bottomrevs = allrevs[:localindex]
+
+ if globalindex == self.depthrev(repo, bottomrevs[-1]):
+ # simple case, top revision in the bottom set contains exactly the
+ # revision we needs
+ result.append((bottomrevs[-1], rangeid[1]))
+ else:
+ parentrevs = cl.parentrevs
+ parents = self._parents
+ bheads = set(bottomrevs)
+ du = bheads.difference_update
+ reachableroots = repo.changelog.reachableroots
+ minrev = min(bottomrevs)
+ for r in bottomrevs:
+ du(parents(r, parentrevs))
+ for h in bheads:
+ # reachable roots is fast because is C
+ #
+ # It is worth noting that will use this kind of filtering from
+ # "h" multiple time in a warming run. So using "ancestors" and
+ # caching that should be faster. But python code filtering on
+ # the ancestors end up being slower.
+ hrevs = reachableroots(minrev, [h], bottomrevs, True)
+ start = self.depthrev(repo, h) - len(hrevs)
+ entry = (h, start)
+ result.append(entry)
+
+ # Talking about python code being slow, the following code is an
+ # alternative implementation.
+ #
+ # It complexity is better since is does a single traversal on the
+ # bottomset. However since it is all python it end up being
+ # slower.
+ # I'm keeping it here as an inspiration for a future C version
+ # branches = []
+ # for current in reversed(bottomrevs):
+ # ps = parents(current, parentrevs)
+ # found = False
+ # for brevs, bexpect in branches:
+ # if current in bexpect:
+ # found = True
+ # brevs.append(current)
+ # bexpect.discard(current)
+ # bexpect.update(ps)
+ # if not found:
+ # branches.append(([current], set(ps)))
+ # for revs, __ in reversed(branches):
+ # head = revs[0]
+ # index = self.depthrev(repo, head) - len(revs)
+ # result.append((head, index))
+
+ # top part is trivial
+ top = (rangeid[0], globalindex)
+ result.append(top)
+ return result
+
+#############################
+### simple sqlite caching ###
+#############################
+
+_sqliteschema = [
+ """CREATE TABLE meta(schemaversion INTEGER NOT NULL,
+ tiprev INTEGER NOT NULL,
+ tipnode BLOB NOT NULL
+ );""",
+ "CREATE TABLE depth(rev INTEGER NOT NULL PRIMARY KEY, depth INTEGER NOT NULL);",
+ """CREATE TABLE range(rev INTEGER NOT NULL,
+ idx INTEGER NOT NULL,
+ PRIMARY KEY(rev, idx));""",
+ """CREATE TABLE subranges(listidx INTEGER NOT NULL,
+ suprev INTEGER NOT NULL,
+ supidx INTEGER NOT NULL,
+ subrev INTEGER NOT NULL,
+ subidx INTEGER NOT NULL,
+ PRIMARY KEY(listidx, suprev, supidx),
+ FOREIGN KEY (suprev, supidx) REFERENCES range(rev, idx),
+ FOREIGN KEY (subrev, subidx) REFERENCES range(rev, idx)
+ );""",
+ "CREATE INDEX subranges_index ON subranges (suprev, supidx);",
+ "CREATE INDEX range_index ON range (rev, idx);",
+ "CREATE INDEX depth_index ON depth (rev);"
+]
+_newmeta = "INSERT INTO meta (schemaversion, tiprev, tipnode) VALUES (?,?,?);"
+_updatemeta = "UPDATE meta SET tiprev = ?, tipnode = ?;"
+_updatedepth = "INSERT INTO depth(rev, depth) VALUES (?,?);"
+_updaterange = "INSERT INTO range(rev, idx) VALUES (?,?);"
+_updatesubranges = """INSERT
+ INTO subranges(listidx, suprev, supidx, subrev, subidx)
+ VALUES (?,?,?,?,?);"""
+_queryexist = "SELECT name FROM sqlite_master WHERE type='table' AND name='meta';"
+_querymeta = "SELECT schemaversion, tiprev, tipnode FROM meta;"
+_querydepth = "SELECT depth FROM depth WHERE rev = ?;"
+_batchdepth = "SELECT rev, depth FROM depth;"
+_queryrange = "SELECT * FROM range WHERE (rev = ? AND idx = ?);"
+_querysubranges = """SELECT subrev, subidx
+ FROM subranges
+ WHERE (suprev = ? AND supidx = ?)
+ ORDER BY listidx;"""
+
+class sqlstablerange(stablerange):
+
+ _schemaversion = 0
+
+ def __init__(self, repo):
+ super(sqlstablerange, self).__init__()
+ self._path = repo.vfs.join('cache/evoext_stablerange_v0.sqlite')
+ self._cl = repo.unfiltered().changelog # (okay to keep an old one)
+ self._ondisktiprev = None
+ self._ondisktipnode = None
+ self._unsaveddepth = {}
+ self._unsavedsubranges = {}
+ self._fulldepth = False
+
+ def warmup(self, repo, upto=None):
+ self._con # make sure the data base is loaded
+ try:
+ # samelessly lock the repo to ensure nobody will update the repo
+ # concurently. This should not be too much of an issue if we warm
+ # at the end of the transaction.
+ #
+ # XXX However, we lock even if we are up to date so we should check
+ # before locking
+ with repo.lock():
+ super(sqlstablerange, self).warmup(repo, upto)
+ self._save(repo)
+ except error.LockError:
+ # Exceptionnally we are noisy about it since performance impact is
+ # large We should address that before using this more widely.
+ repo.ui.warn('stable-range cache: unable to lock repo while warming\n')
+ repo.ui.warn('(cache will not be saved)\n')
+ super(sqlstablerange, self).warmup(repo, upto)
+
+ def _getdepth(self, rev):
+ cache = self._depthcache
+ if rev not in cache and rev <= self._ondisktiprev and self._con is not None:
+ value = None
+ result = self._con.execute(_querydepth, (rev,)).fetchone()
+ if result is not None:
+ value = result[0]
+ # in memory caching of the value
+ cache[rev] = value
+ return cache.get(rev)
+
+ def _setdepth(self, rev, depth):
+ assert rev not in self._unsaveddepth
+ self._unsaveddepth[rev] = depth
+ super(sqlstablerange, self)._setdepth(rev, depth)
+
+ def _getsub(self, rangeid):
+ cache = self._subrangescache
+ if rangeid not in cache and rangeid[0] <= self._ondisktiprev and self._con is not None:
+ value = None
+ result = self._con.execute(_queryrange, rangeid).fetchone()
+ if result is not None: # database know about this node (skip in the future?)
+ value = self._con.execute(_querysubranges, rangeid).fetchall()
+ # in memory caching of the value
+ cache[rangeid] = value
+ return cache.get(rangeid)
+
+ def _setsub(self, rangeid, value):
+ assert rangeid not in self._unsavedsubranges
+ self._unsavedsubranges[rangeid] = value
+ super(sqlstablerange, self)._setsub(rangeid, value)
+
+ def _inheritancepoint(self, *args, **kwargs):
+ self._loaddepth()
+ return super(sqlstablerange, self)._inheritancepoint(*args, **kwargs)
+
+ @util.propertycache
+ def _con(self):
+ con = sqlite3.connect(self._path)
+ con.text_factory = str
+ cur = con.execute(_queryexist)
+ if cur.fetchone() is None:
+ return None
+ meta = con.execute(_querymeta).fetchone()
+ if meta is None:
+ return None
+ if meta[0] != self._schemaversion:
+ return None
+ if len(self._cl) <= meta[1]:
+ return None
+ if self._cl.node(meta[1]) != meta[2]:
+ return None
+ self._ondisktiprev = meta[1]
+ self._ondisktipnode = meta[2]
+ if self._tiprev < self._ondisktiprev:
+ self._tiprev = self._ondisktiprev
+ self._tipnode = self._ondisktipnode
+ return con
+
+ def _save(self, repo):
+ repo = repo.unfiltered()
+ if not (self._unsavedsubranges or self._unsaveddepth):
+ return # no new data
+
+ if self._con is None:
+ util.unlinkpath(self._path, ignoremissing=True)
+ if '_con' in vars(self):
+ del self._con
+
+ con = sqlite3.connect(self._path)
+ con.text_factory = str
+ with con:
+ for req in _sqliteschema:
+ con.execute(req)
+
+ meta = [self._schemaversion,
+ self._tiprev,
+ self._tipnode,
+ ]
+ con.execute(_newmeta, meta)
+ else:
+ con = self._con
+ meta = con.execute(_querymeta).fetchone()
+ if meta[2] != self._ondisktipnode or meta[1] != self._ondisktiprev:
+ # drifting is currently an issue because this means another
+ # process might have already added the cache line we are about
+ # to add. This will confuse sqlite
+ msg = _('stable-range cache: skipping write, '
+ 'database drifted under my feet\n')
+ hint = _('(disk: %s-%s vs mem: %s%s)\n')
+ data = (meta[2], meta[1], self._ondisktiprev, self._ondisktipnode)
+ repo.ui.warn(msg)
+ repo.ui.warn(hint % data)
+ return
+ meta = [self._tiprev,
+ self._tipnode,
+ ]
+ con.execute(_updatemeta, meta)
+
+ self._savedepth(con, repo)
+ self._saverange(con, repo)
+ con.commit()
+ self._ondisktiprev = self._tiprev
+ self._ondisktipnode = self._tipnode
+ self._unsaveddepth.clear()
+ self._unsavedsubranges.clear()
+
+ def _savedepth(self, con, repo):
+ repo = repo.unfiltered()
+ data = self._unsaveddepth.items()
+ con.executemany(_updatedepth, data)
+
+ def _loaddepth(self):
+ """batch load all data about depth"""
+ if not (self._fulldepth or self._con is None):
+ result = self._con.execute(_batchdepth)
+ self._depthcache.update(result.fetchall())
+ self._fulldepth = True
+
+ def _saverange(self, con, repo):
+ repo = repo.unfiltered()
+ data = []
+ allranges = set()
+ for key, value in self._unsavedsubranges.items():
+ allranges.add(key)
+ for idx, sub in enumerate(value):
+ data.append((idx, key[0], key[1], sub[0], sub[1]))
+
+ con.executemany(_updaterange, allranges)
+ con.executemany(_updatesubranges, data)
+
+
+@eh.reposetup
+def setupcache(ui, repo):
+
+ class stablerangerepo(repo.__class__):
+
+ @localrepo.unfilteredpropertycache
+ def stablerange(self):
+ return sqlstablerange(repo)
+
+ @localrepo.unfilteredmethod
+ def destroyed(self):
+ if 'stablerange' in vars(self):
+ del self.stablerange
+
+ def transaction(self, *args, **kwargs):
+ tr = super(stablerangerepo, self).transaction(*args, **kwargs)
+ if not repo.ui.configbool('experimental', 'obshashrange', False):
+ return tr
+ reporef = weakref.ref(self)
+
+ def _warmcache(tr):
+ repo = reporef()
+ if repo is None:
+ return
+ if 'node' in tr.hookargs:
+ # new nodes !
+ repo.stablerange.warmup(repo)
+
+ tr.addpostclose('warmcache-stablerange', _warmcache)
+ return tr
+
+ repo.__class__ = stablerangerepo
--- a/hgext3rd/evolve/utility.py Tue Mar 14 14:47:20 2017 -0700
+++ b/hgext3rd/evolve/utility.py Fri Mar 31 15:44:10 2017 +0200
@@ -4,7 +4,6 @@
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-from mercurial import node
def obsexcmsg(ui, message, important=False):
verbose = ui.configbool('experimental', 'verbose-obsolescence-exchange',
@@ -19,36 +18,3 @@
if ui.configbool('experimental', 'verbose-obsolescence-exchange', False):
topic = 'OBSEXC'
ui.progress(topic, *args, **kwargs)
-
-_depthcache = {}
-def depth(repo, rev):
- cl = repo.changelog
- n = cl.node(rev)
- revdepth = _depthcache.get(n, None)
- if revdepth is None:
- p1, p2 = cl.parentrevs(rev)
- if p1 == node.nullrev:
- revdepth = 1
- elif p2 == node.nullrev:
- revdepth = depth(repo, p1) + 1
- else:
- ancs = cl.commonancestorsheads(cl.node(p1), cl.node(p2))
- depth_p1 = depth(repo, p1)
- depth_p2 = depth(repo, p2)
- if not ancs:
- revdepth = depth_p1 + depth_p2 + 1
- elif len(ancs) == 1:
- anc = cl.rev(ancs[0])
- revdepth = depth_anc = depth(repo, anc)
- revdepth += depth_p1 - depth_anc
- revdepth += depth_p2 - depth_anc
- revdepth += 1
- else:
- # multiple ancestors, we pick the highest and search all missing bits
- anc = max(cl.rev(a) for a in ancs)
- revdepth = depth(repo, anc)
- revdepth += len(cl.findmissingrevs(common=[anc], heads=[rev]))
- _depthcache[n] = revdepth
- # actual_depth = len(list(cl.ancestors([rev], inclusive=True)))
- # assert revdepth == actual_depth, (rev, revdepth, actual_depth)
- return revdepth
--- a/tests/_exc-util.sh Tue Mar 14 14:47:20 2017 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,110 +0,0 @@
-#!/bin/sh
-
-cat >> $HGRCPATH <<EOF
-[web]
-push_ssl = false
-allow_push = *
-
-[ui]
-logtemplate ="{node|short} ({phase}): {desc}\n"
-
-[phases]
-publish=False
-
-[experimental]
-verbose-obsolescence-exchange=false
-bundle2-exp=true
-bundle2-output-capture=True
-
-[alias]
-debugobsolete=debugobsolete -d '0 0'
-
-[extensions]
-hgext.strip=
-EOF
-echo "evolve=$(echo $(dirname $TESTDIR))/hgext3rd/evolve/" >> $HGRCPATH
-
-mkcommit() {
- echo "$1" > "$1"
- hg add "$1"
- hg ci -m "$1"
-}
-getid() {
- hg log --hidden --template '{node}\n' --rev "$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 | sort
- echo "# obstore: pushdest"
- hg -R pushdest debugobsolete | sort
- echo "# obstore: pulldest"
- hg -R pulldest debugobsolete | sort
-
- 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 | sort
- echo "# obstore: pushdest"
- hg -R pushdest debugobsolete | sort
- echo "# obstore: pulldest"
- hg -R pulldest debugobsolete | sort
- 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 | sort
- echo "# obstore: pushdest"
- hg -R pushdest debugobsolete | sort
- echo "# obstore: pulldest"
- hg -R pulldest debugobsolete | sort
-
- cd ..
-
-}
--- a/tests/test-check-flake8.t Tue Mar 14 14:47:20 2017 -0700
+++ b/tests/test-check-flake8.t Fri Mar 31 15:44:10 2017 +0200
@@ -14,5 +14,5 @@
run flake8 if it exists; if it doesn't, then just skip
- $ hg files -0 'set:(**.py or grep("^!#.*python")) - removed()' 2>/dev/null \
+ $ hg files -0 'set:(**.py or grep("^#!.*python")) - removed()' 2>/dev/null \
> | xargs -0 flake8
--- a/tests/test-check-pyflakes.t Tue Mar 14 14:47:20 2017 -0700
+++ b/tests/test-check-pyflakes.t Fri Mar 31 15:44:10 2017 +0200
@@ -7,5 +7,5 @@
run pyflakes on all tracked files ending in .py or without a file ending
(skipping binary file random-seed)
- $ hg locate 'set:(**.py or grep("^!#.*python")) - removed()' 2>/dev/null \
+ $ hg locate 'set:(**.py or grep("^#!.*python")) - removed()' 2>/dev/null \
> | xargs pyflakes 2>/dev/null
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-check-setup-manifest.t Fri Mar 31 15:44:10 2017 +0200
@@ -0,0 +1,19 @@
+#require test-repo
+
+ $ checkcm() {
+ > if ! (which check-manifest > /dev/null); then
+ > echo skipped: missing tool: check-manifest;
+ > exit 80;
+ > fi;
+ > };
+ $ checkcm
+ $ cat << EOF >> $HGRCPATH
+ > [experimental]
+ > evolution=all
+ > EOF
+
+Run check manifest:
+
+ $ cd $TESTDIR/..
+ $ check-manifest
+ lists of files in version control and sdist match
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-checkheads-partial-C1.t Fri Mar 31 15:44:10 2017 +0200
@@ -0,0 +1,79 @@
+====================================
+Testing head checking code: Case C-1
+====================================
+
+Mercurial checks for the introduction of multiple heads on push. Evolution
+comes into play to detect if existing heads on the server are being replaced by
+some of the new heads we push.
+
+This test file is part of a series of tests checking this behavior.
+
+Category C: checking case were the branch is only partially obsoleted.
+TestCase 1: 2 changeset branch, only the head is rewritten
+
+.. old-state:
+..
+.. * 2 changeset branch
+..
+.. new-state:
+..
+.. * 1 new changesets branches superceeding only the head of the old one
+.. * base of the old branch is still alive
+..
+.. expected-result:
+..
+.. * push denied
+..
+.. graph-summary:
+..
+.. B ø⇠◔ B'
+.. | |
+.. A ○ |
+.. |/
+.. ○
+
+ $ . $TESTDIR/testlib/checkheads-util.sh
+
+Test setup
+----------
+
+ $ setuprepos
+ creating basic server and client repo
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd server
+ $ mkcommit B0
+ $ cd ../client
+ $ hg pull
+ pulling from $TESTTMP/server
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ (run 'hg update' to get a working copy)
+ $ hg up 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ mkcommit B1
+ created new head
+ $ hg debugobsolete `getid "desc(B0)" ` `getid "desc(B1)"`
+ $ hg log -G --hidden
+ @ 25c56d33e4c4 (draft): B1
+ |
+ | x d73caddc5533 (draft): B0
+ | |
+ | o 8aaa48160adc (draft): A0
+ |/
+ o 1e4be0697311 (public): root
+
+
+
+Actual testing
+--------------
+
+ $ hg push
+ pushing to $TESTTMP/server
+ searching for changes
+ abort: push creates new remote head 25c56d33e4c4!
+ (merge or see 'hg help push' for details about pushing new heads)
+ [255]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-checkheads-partial-C2.t Fri Mar 31 15:44:10 2017 +0200
@@ -0,0 +1,79 @@
+====================================
+Testing head checking code: Case C-2
+====================================
+
+Mercurial checks for the introduction of multiple heads on push. Evolution
+comes into play to detect if existing heads on the server are being replaced by
+some of the new heads we push.
+
+This test file is part of a series of tests checking this behavior.
+
+Category C: checking case were the branch is only partially obsoleted.
+TestCase 2: 2 changeset branch, only the base is rewritten
+
+.. old-state:
+..
+.. * 2 changeset branch
+..
+.. new-state:
+..
+.. * 1 new changesets branches superceeding only the base of the old one
+.. * The old branch is still alive (base is obsolete, head is alive)
+..
+.. expected-result:
+..
+.. * push denied
+..
+.. graph-summary:
+..
+.. B ○
+.. |
+.. A ø⇠◔ A'
+.. |/
+.. ○
+
+ $ . $TESTDIR/testlib/checkheads-util.sh
+
+Test setup
+----------
+
+ $ setuprepos
+ creating basic server and client repo
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd server
+ $ mkcommit B0
+ $ cd ../client
+ $ hg pull
+ pulling from $TESTTMP/server
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ (run 'hg update' to get a working copy)
+ $ hg up 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ mkcommit A1
+ created new head
+ $ hg debugobsolete `getid "desc(A0)" ` `getid "desc(A1)"`
+ $ hg log -G --hidden
+ @ f6082bc4ffef (draft): A1
+ |
+ | o d73caddc5533 (draft): B0
+ | |
+ | x 8aaa48160adc (draft): A0
+ |/
+ o 1e4be0697311 (public): root
+
+
+
+Actual testing
+--------------
+
+ $ hg push --rev 'desc(A1)'
+ pushing to $TESTTMP/server
+ searching for changes
+ abort: push creates new remote head f6082bc4ffef!
+ (merge or see 'hg help push' for details about pushing new heads)
+ [255]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-checkheads-partial-C3.t Fri Mar 31 15:44:10 2017 +0200
@@ -0,0 +1,78 @@
+====================================
+Testing head checking code: Case C-3
+====================================
+
+Mercurial checks for the introduction of multiple heads on push. Evolution
+comes into play to detect if existing heads on the server are being replaced by
+some of the new heads we push.
+
+This test file is part of a series of tests checking this behavior.
+
+Category C: checking case were the branch is only partially obsoleted.
+TestCase 3: 2 changeset branch, only the head is pruned
+
+.. old-state:
+..
+.. * 2 changeset branch
+..
+.. new-state:
+..
+.. * old head is pruned
+.. * 1 new unrelated branch
+..
+.. expected-result:
+..
+.. * push denied
+..
+.. graph-summary:
+..
+.. B ⊗
+.. |
+.. A ◔ ◔ C
+.. |/
+.. ○
+
+ $ . $TESTDIR/testlib/checkheads-util.sh
+
+Test setup
+----------
+
+ $ setuprepos
+ creating basic server and client repo
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd server
+ $ mkcommit B0
+ $ cd ../client
+ $ hg pull
+ pulling from $TESTTMP/server
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ (run 'hg update' to get a working copy)
+ $ hg up 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ mkcommit C0
+ created new head
+ $ hg debugobsolete --record-parents `getid "desc(B0)"`
+ $ hg log -G --hidden
+ @ 0f88766e02d6 (draft): C0
+ |
+ | x d73caddc5533 (draft): B0
+ | |
+ | o 8aaa48160adc (draft): A0
+ |/
+ o 1e4be0697311 (public): root
+
+
+Actual testing
+--------------
+
+ $ hg push
+ pushing to $TESTTMP/server
+ searching for changes
+ abort: push creates new remote head 0f88766e02d6!
+ (merge or see 'hg help push' for details about pushing new heads)
+ [255]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-checkheads-partial-C4.t Fri Mar 31 15:44:10 2017 +0200
@@ -0,0 +1,78 @@
+====================================
+Testing head checking code: Case C-4
+====================================
+
+Mercurial checks for the introduction of multiple heads on push. Evolution
+comes into play to detect if existing heads on the server are being replaced by
+some of the new heads we push.
+
+This test file is part of a series of tests checking this behavior.
+
+Category C: checking case were the branch is only partially obsoleted.
+TestCase 4: 2 changeset branch, only the base is pruned
+
+.. old-state:
+..
+.. * 2 changeset branch
+..
+.. new-state:
+..
+.. * old base is pruned
+.. * 1 new unrelated branch
+..
+.. expected-result:
+..
+.. * push denied
+..
+.. graph-summary:
+..
+.. B ◔
+.. |
+.. A ⊗ ◔ C
+.. |/
+.. ○
+
+ $ . $TESTDIR/testlib/checkheads-util.sh
+
+Test setup
+----------
+
+ $ setuprepos
+ creating basic server and client repo
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd server
+ $ mkcommit B0
+ $ cd ../client
+ $ hg pull
+ pulling from $TESTTMP/server
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ (run 'hg update' to get a working copy)
+ $ hg up 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ mkcommit C0
+ created new head
+ $ hg debugobsolete --record-parents `getid "desc(A0)"`
+ $ hg log -G --hidden
+ @ 0f88766e02d6 (draft): C0
+ |
+ | o d73caddc5533 (draft): B0
+ | |
+ | x 8aaa48160adc (draft): A0
+ |/
+ o 1e4be0697311 (public): root
+
+
+Actual testing
+--------------
+
+ $ hg push --rev 'desc(C0)'
+ pushing to $TESTTMP/server
+ searching for changes
+ abort: push creates new remote head 0f88766e02d6!
+ (merge or see 'hg help push' for details about pushing new heads)
+ [255]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-checkheads-pruned-B1.t Fri Mar 31 15:44:10 2017 +0200
@@ -0,0 +1,71 @@
+====================================
+Testing head checking code: Case B-1
+====================================
+
+Mercurial checks for the introduction of multiple heads on push. Evolution
+comes into play to detect if existing heads on the server are being replaced by
+some of the new heads we push.
+
+This test file is part of a series of tests checking this behavior.
+
+Category B: checking simple case involving pruned changesets
+TestCase 1: single pruned changeset
+
+.. old-state:
+..
+.. * 1 changeset branch
+..
+.. new-state:
+..
+.. * old branch is pruned
+.. * 1 new unrelated branch
+..
+.. expected-result:
+..
+.. * push allowed
+..
+.. graph-summary:
+..
+.. ◔ B
+.. |
+.. A ⊗ |
+.. |/
+.. ○
+
+ $ . $TESTDIR/testlib/checkheads-util.sh
+
+Test setup
+----------
+
+ $ setuprepos
+ creating basic server and client repo
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd client
+ $ hg up 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ mkcommit B0
+ created new head
+ $ hg debugobsolete --record-parents `getid "desc(A0)"`
+ $ hg log -G --hidden
+ @ 74ff5441d343 (draft): B0
+ |
+ | x 8aaa48160adc (draft): A0
+ |/
+ o 1e4be0697311 (public): root
+
+
+Actual testing
+--------------
+
+ $ hg push
+ pushing to $TESTTMP/server
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ 1 new obsolescence markers
+
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-checkheads-pruned-B2.t Fri Mar 31 15:44:10 2017 +0200
@@ -0,0 +1,82 @@
+====================================
+Testing head checking code: Case B-2
+====================================
+
+Mercurial checks for the introduction of multiple heads on push. Evolution
+comes into play to detect if existing heads on the server are being replaced by
+some of the new heads we push.
+
+This test file is part of a series of tests checking this behavior.
+
+Category B: checking simple case involving pruned changesets
+TestCase 2: multi-changeset branch, head is pruned, rest is superceeded
+
+.. old-state:
+..
+.. * 2 changeset branch
+..
+.. new-state:
+..
+.. * old head is pruned
+.. * 1 new branch succeeding to the other changeset in the old branch
+..
+.. expected-result:
+..
+.. * push allowed
+..
+.. graph-summary:
+..
+.. B ⊗
+.. |
+.. A ø⇠◔ A'
+.. |/
+.. ○
+
+ $ . $TESTDIR/testlib/checkheads-util.sh
+
+Test setup
+----------
+
+ $ setuprepos
+ creating basic server and client repo
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd server
+ $ mkcommit B0
+ $ cd ../client
+ $ hg pull
+ pulling from $TESTTMP/server
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ (run 'hg update' to get a working copy)
+ $ hg up 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ mkcommit A1
+ created new head
+ $ hg debugobsolete `getid "desc(A0)" ` `getid "desc(A1)"`
+ $ hg debugobsolete --record-parents `getid "desc(B0)"`
+ $ hg log -G --hidden
+ @ f6082bc4ffef (draft): A1
+ |
+ | x d73caddc5533 (draft): B0
+ | |
+ | x 8aaa48160adc (draft): A0
+ |/
+ o 1e4be0697311 (public): root
+
+
+Actual testing
+--------------
+
+ $ hg push
+ pushing to $TESTTMP/server
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ 2 new obsolescence markers
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-checkheads-pruned-B3.t Fri Mar 31 15:44:10 2017 +0200
@@ -0,0 +1,82 @@
+====================================
+Testing head checking code: Case B-3
+====================================
+
+Mercurial checks for the introduction of multiple heads on push. Evolution
+comes into play to detect if existing heads on the server are being replaced by
+some of the new heads we push.
+
+This test file is part of a series of tests checking this behavior.
+
+Category B: checking simple case involving pruned changesets
+TestCase 3: multi-changeset branch, other is pruned, rest is superceeded
+
+.. old-state:
+..
+.. * 2 changeset branch
+..
+.. new-state:
+..
+.. * old head is superceeded
+.. * old other is pruned
+..
+.. expected-result:
+..
+.. * push allowed
+..
+.. graph-summary:
+..
+.. B ø⇠◔ B'
+.. | |
+.. A ⊗ |
+.. |/
+.. ○
+
+ $ . $TESTDIR/testlib/checkheads-util.sh
+
+Test setup
+----------
+
+ $ setuprepos
+ creating basic server and client repo
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd server
+ $ mkcommit B0
+ $ cd ../client
+ $ hg pull
+ pulling from $TESTTMP/server
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ (run 'hg update' to get a working copy)
+ $ hg up 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ mkcommit B1
+ created new head
+ $ hg debugobsolete --record-parents `getid "desc(A0)"`
+ $ hg debugobsolete `getid "desc(B0)" ` `getid "desc(B1)"`
+ $ hg log -G --hidden
+ @ 25c56d33e4c4 (draft): B1
+ |
+ | x d73caddc5533 (draft): B0
+ | |
+ | x 8aaa48160adc (draft): A0
+ |/
+ o 1e4be0697311 (public): root
+
+
+Actual testing
+--------------
+
+ $ hg push
+ pushing to $TESTTMP/server
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ 2 new obsolescence markers
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-checkheads-pruned-B4.t Fri Mar 31 15:44:10 2017 +0200
@@ -0,0 +1,83 @@
+====================================
+Testing head checking code: Case B-4
+====================================
+
+Mercurial checks for the introduction of multiple heads on push. Evolution
+comes into play to detect if existing heads on the server are being replaced by
+some of the new heads we push.
+
+This test file is part of a series of tests checking this behavior.
+
+Category B: checking simple case involving pruned changesets
+TestCase 4: multi-changeset branch, all are pruned
+
+.. old-state:
+..
+.. * 2 changeset branch
+..
+.. new-state:
+..
+.. * old branch is pruned
+..
+.. expected-result:
+..
+.. * push allowed
+..
+.. graph-summary:
+..
+.. B ⊗
+.. |
+.. A ⊗
+.. |
+.. | ◔ C
+.. |/
+.. ○
+
+ $ . $TESTDIR/testlib/checkheads-util.sh
+
+Test setup
+----------
+
+ $ setuprepos
+ creating basic server and client repo
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd server
+ $ mkcommit B0
+ $ cd ../client
+ $ hg pull
+ pulling from $TESTTMP/server
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ (run 'hg update' to get a working copy)
+ $ hg up 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ mkcommit C0
+ created new head
+ $ hg debugobsolete --record-parents `getid "desc(A0)"`
+ $ hg debugobsolete --record-parents `getid "desc(B0)"`
+ $ hg log -G --hidden
+ @ 0f88766e02d6 (draft): C0
+ |
+ | x d73caddc5533 (draft): B0
+ | |
+ | x 8aaa48160adc (draft): A0
+ |/
+ o 1e4be0697311 (public): root
+
+
+Actual testing
+--------------
+
+ $ hg push
+ pushing to $TESTTMP/server
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ 2 new obsolescence markers
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-checkheads-pruned-B5.t Fri Mar 31 15:44:10 2017 +0200
@@ -0,0 +1,89 @@
+====================================
+Testing head checking code: Case B-5
+====================================
+
+Mercurial checks for the introduction of multiple heads on push. Evolution
+comes into play to detect if existing heads on the server are being replaced by
+some of the new heads we push.
+
+This test file is part of a series of tests checking this behavior.
+
+Category B: checking simple case involving pruned changesets
+TestCase 5: multi-changeset branch, mix of pruned and superceeded
+
+.. old-state:
+..
+.. * 3 changeset branch
+..
+.. new-state:
+..
+.. * old head is pruned
+.. * old mid is superceeded
+.. * old root is pruned
+..
+.. expected-result:
+..
+.. * push allowed
+..
+.. graph-summary:
+..
+.. B ⊗
+.. |
+.. A ø⇠◔ A'
+.. | |
+.. B ⊗ |
+.. |/
+.. ○
+
+ $ . $TESTDIR/testlib/checkheads-util.sh
+
+Test setup
+----------
+
+ $ setuprepos
+ creating basic server and client repo
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd server
+ $ mkcommit B0
+ $ mkcommit C0
+ $ cd ../client
+ $ hg pull
+ pulling from $TESTTMP/server
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 2 files
+ (run 'hg update' to get a working copy)
+ $ hg up 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ mkcommit B1
+ created new head
+ $ hg debugobsolete --record-parents `getid "desc(A0)"`
+ $ hg debugobsolete `getid "desc(B0)"` `getid "desc(B1)"`
+ $ hg debugobsolete --record-parents `getid "desc(C0)"`
+ $ hg log -G --hidden
+ @ 25c56d33e4c4 (draft): B1
+ |
+ | x 821fb21d0dd2 (draft): C0
+ | |
+ | x d73caddc5533 (draft): B0
+ | |
+ | x 8aaa48160adc (draft): A0
+ |/
+ o 1e4be0697311 (public): root
+
+
+Actual testing
+--------------
+
+ $ hg push
+ pushing to $TESTTMP/server
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ 3 new obsolescence markers
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-checkheads-pruned-B6.t Fri Mar 31 15:44:10 2017 +0200
@@ -0,0 +1,74 @@
+====================================
+Testing head checking code: Case B-6
+====================================
+
+Mercurial checks for the introduction of multiple heads on push. Evolution
+comes into play to detect if existing heads on the server are being replaced by
+some of the new heads we push.
+
+This test file is part of a series of tests checking this behavior.
+
+Category B: checking simple case involving pruned changesets
+TestCase 6: single changesets, pruned then superseeded (on a new changeset)
+
+.. old-state:
+..
+.. * 1 changeset branch
+..
+.. new-state:
+..
+.. * old branch is rewritten onto another one,
+.. * the new version is then pruned.
+..
+.. expected-result:
+..
+.. * push allowed
+..
+.. graph-summary:
+..
+.. A ø⇠⊗ A'
+.. | |
+.. | ◔ B
+.. |/
+.. ○
+
+ $ . $TESTDIR/testlib/checkheads-util.sh
+
+Test setup
+----------
+
+ $ setuprepos
+ creating basic server and client repo
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd client
+ $ hg up 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ mkcommit B0
+ created new head
+ $ mkcommit A1
+ $ hg up 'desc(B0)'
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg debugobsolete `getid "desc(A0)"` `getid "desc(A1)"`
+ $ hg debugobsolete --record-parents `getid "desc(A1)"`
+ $ hg log -G --hidden
+ x ba93660aff8d (draft): A1
+ |
+ @ 74ff5441d343 (draft): B0
+ |
+ | x 8aaa48160adc (draft): A0
+ |/
+ o 1e4be0697311 (public): root
+
+
+Actual testing
+--------------
+
+ $ hg push
+ pushing to $TESTTMP/server
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ 2 new obsolescence markers
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-checkheads-pruned-B7.t Fri Mar 31 15:44:10 2017 +0200
@@ -0,0 +1,73 @@
+====================================
+Testing head checking code: Case B-7
+====================================
+
+Mercurial checks for the introduction of multiple heads on push. Evolution
+comes into play to detect if existing heads on the server are being replaced by
+some of the new heads we push.
+
+This test file is part of a series of tests checking this behavior.
+
+Category B: checking simple case involving pruned changesets
+TestCase 7: single changesets, pruned then superseeded (on an existing changeset)
+
+.. old-state:
+..
+.. * 1 changeset branch
+..
+.. new-state:
+..
+.. * old branch is rewritten onto the common set,
+.. * the new version is then pruned.
+..
+.. expected-result:
+..
+.. * push allowed
+..
+.. graph-summary:
+..
+.. A ø⇠⊗ A'
+.. B ◔ | |
+.. \|/
+.. ●
+
+ $ . $TESTDIR/testlib/checkheads-util.sh
+
+Test setup
+----------
+
+ $ setuprepos
+ creating basic server and client repo
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd client
+ $ hg up 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ mkcommit B0
+ created new head
+ $ mkcommit A1
+ $ hg up 'desc(B0)'
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg debugobsolete `getid "desc(A0)"` `getid "desc(A1)"`
+ $ hg debugobsolete --record-parents `getid "desc(A1)"`
+ $ hg log -G --hidden
+ x ba93660aff8d (draft): A1
+ |
+ @ 74ff5441d343 (draft): B0
+ |
+ | x 8aaa48160adc (draft): A0
+ |/
+ o 1e4be0697311 (public): root
+
+
+Actual testing
+--------------
+
+ $ hg push
+ pushing to $TESTTMP/server
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ 2 new obsolescence markers
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-checkheads-pruned-B8.t Fri Mar 31 15:44:10 2017 +0200
@@ -0,0 +1,95 @@
+====================================
+Testing head checking code: Case B-2
+====================================
+
+Mercurial checks for the introduction of multiple heads on push. Evolution
+comes into play to detect if existing heads on the server are being replaced by
+some of the new heads we push.
+
+This test file is part of a series of tests checking this behavior.
+
+Category B: checking simple case involving pruned changesets
+TestCase 2: multi-changeset branch, head is pruned, rest is superceeded, through other
+
+.. old-state:
+..
+.. * 2 changeset branch
+..
+.. new-state:
+..
+.. * old head is rewritten then pruned
+.. * 1 new branch succeeding to the other changeset in the old branch (through another obsolete branch)
+..
+.. expected-result:
+..
+.. * push allowed
+..
+.. graph-summary:
+..
+.. B ø⇠⊗ B'
+.. | | A'
+.. A ø⇠ø⇠◔ A''
+.. |/ /
+.. | /
+.. |/
+.. ○
+
+ $ . $TESTDIR/testlib/checkheads-util.sh
+
+Test setup
+----------
+
+ $ setuprepos
+ creating basic server and client repo
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd server
+ $ mkcommit B0
+ $ cd ../client
+ $ hg pull
+ pulling from $TESTTMP/server
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ (run 'hg update' to get a working copy)
+ $ hg up 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ mkcommit A1
+ created new head
+ $ mkcommit B1
+ $ hg up 0
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ mkcommit A2
+ created new head
+ $ hg debugobsolete `getid "desc(A0)" ` `getid "desc(A1)"`
+ $ hg debugobsolete `getid "desc(B0)" ` `getid "desc(B1)"`
+ $ hg debugobsolete --record-parents `getid "desc(B1)"`
+ $ hg debugobsolete `getid "desc(A1)" ` `getid "desc(A2)"`
+ $ hg log -G --hidden
+ @ c1f8d089020f (draft): A2
+ |
+ | x 262c8c798096 (draft): B1
+ | |
+ | x f6082bc4ffef (draft): A1
+ |/
+ | x d73caddc5533 (draft): B0
+ | |
+ | x 8aaa48160adc (draft): A0
+ |/
+ o 1e4be0697311 (public): root
+
+
+Actual testing
+--------------
+
+ $ hg push
+ pushing to $TESTTMP/server
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ 4 new obsolescence markers
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-checkheads-superceed-A1.t Fri Mar 31 15:44:10 2017 +0200
@@ -0,0 +1,68 @@
+====================================
+Testing head checking code: Case A-1
+====================================
+
+Mercurial checks for the introduction of multiple heads on push. Evolution
+comes into play to detect if existing heads on the server are being replaced by
+some of the new heads we push.
+
+This test file is part of a series of tests checking this behavior.
+
+Category A: checking simple case invoving a branch being superceeded by another.
+TestCase 1: single-changeset branch
+
+.. old-state:
+..
+.. * 1 changeset branch
+..
+.. new-state:
+..
+.. * 1 changeset branch succeeding to A
+..
+.. expected-result:
+..
+.. * push allowed
+..
+.. graph-summary:
+..
+.. A ø⇠◔ A'
+.. |/
+.. ○
+
+ $ . $TESTDIR/testlib/checkheads-util.sh
+
+Test setup
+----------
+
+ $ setuprepos
+ creating basic server and client repo
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd client
+ $ hg up 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ mkcommit A1
+ created new head
+ $ hg debugobsolete `getid "desc(A0)" ` `getid "desc(A1)"`
+ $ hg log -G --hidden
+ @ f6082bc4ffef (draft): A1
+ |
+ | x 8aaa48160adc (draft): A0
+ |/
+ o 1e4be0697311 (public): root
+
+
+Actual testing
+--------------
+
+ $ hg push
+ pushing to $TESTTMP/server
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ 1 new obsolescence markers
+
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-checkheads-superceed-A2.t Fri Mar 31 15:44:10 2017 +0200
@@ -0,0 +1,84 @@
+====================================
+Testing head checking code: Case A-2
+====================================
+
+Mercurial checks for the introduction of multiple heads on push. Evolution
+comes into play to detect if existing heads on the server are being replaced by
+some of the new heads we push.
+
+This test file is part of a series of tests checking this behavior.
+
+Category A: checking simple case invoving a branch being superceeded by another.
+TestCase 2: multi-changeset branch
+
+.. old-state:
+..
+.. * 2 changeset branch
+..
+.. new-state:
+..
+.. * 2 changeset branch succeeding the old one
+..
+.. expected-result:
+..
+.. * push allowed
+..
+.. graph-summary:
+..
+.. B ø⇠◔ B'
+.. | |
+.. A ø⇠◔ A'
+.. |/
+.. ○
+
+ $ . $TESTDIR/testlib/checkheads-util.sh
+
+Test setup
+----------
+
+ $ setuprepos
+ creating basic server and client repo
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd server
+ $ mkcommit B0
+ $ cd ../client
+ $ hg pull
+ pulling from $TESTTMP/server
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ (run 'hg update' to get a working copy)
+ $ hg up 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ mkcommit A1
+ created new head
+ $ mkcommit B1
+ $ hg debugobsolete `getid "desc(A0)" ` `getid "desc(A1)"`
+ $ hg debugobsolete `getid "desc(B0)" ` `getid "desc(B1)"`
+ $ hg log -G --hidden
+ @ 262c8c798096 (draft): B1
+ |
+ o f6082bc4ffef (draft): A1
+ |
+ | x d73caddc5533 (draft): B0
+ | |
+ | x 8aaa48160adc (draft): A0
+ |/
+ o 1e4be0697311 (public): root
+
+
+
+Actual testing
+--------------
+
+ $ hg push
+ pushing to $TESTTMP/server
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 2 files (+1 heads)
+ 2 new obsolescence markers
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-checkheads-superceed-A3.t Fri Mar 31 15:44:10 2017 +0200
@@ -0,0 +1,87 @@
+====================================
+Testing head checking code: Case A-3
+====================================
+
+Mercurial checks for the introduction of multiple heads on push. Evolution
+comes into play to detect if existing heads on the server are being replaced by
+some of the new heads we push.
+
+This test file is part of a series of tests checking this behavior.
+
+Category A: checking simple case invoving a branch being superceeded by another.
+TestCase 3: multi-changeset branch with reordering
+
+Push should be allowed
+.. old-state:
+..
+.. * 2 changeset branch
+..
+.. new-state:
+..
+.. * 2 changeset branch succeeding the old one with reordering
+..
+.. expected-result:
+..
+.. * push allowed
+..
+.. graph-summary:
+..
+.. B ø⇠⇠
+.. | ⇡
+.. A ø⇠⇠⇠○ A'
+.. | ⇡/
+.. | ○ B'
+.. |/
+.. ● O
+
+ $ . $TESTDIR/testlib/checkheads-util.sh
+
+Test setup
+----------
+
+ $ setuprepos
+ creating basic server and client repo
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd server
+ $ mkcommit B0
+ $ cd ../client
+ $ hg pull
+ pulling from $TESTTMP/server
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ (run 'hg update' to get a working copy)
+ $ hg up 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ mkcommit B1
+ created new head
+ $ mkcommit A1
+ $ hg debugobsolete `getid "desc(A0)" ` `getid "desc(A1)"`
+ $ hg debugobsolete `getid "desc(B0)" ` `getid "desc(B1)"`
+ $ hg log -G --hidden
+ @ c1c7524e9488 (draft): A1
+ |
+ o 25c56d33e4c4 (draft): B1
+ |
+ | x d73caddc5533 (draft): B0
+ | |
+ | x 8aaa48160adc (draft): A0
+ |/
+ o 1e4be0697311 (public): root
+
+
+
+Actual testing
+--------------
+
+ $ hg push
+ pushing to $TESTTMP/server
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 2 files (+1 heads)
+ 2 new obsolescence markers
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-checkheads-superceed-A4.t Fri Mar 31 15:44:10 2017 +0200
@@ -0,0 +1,74 @@
+====================================
+Testing head checking code: Case A-4
+====================================
+
+Mercurial checks for the introduction of multiple heads on push. Evolution
+comes into play to detect if existing heads on the server are being replaced by
+some of the new heads we push.
+
+This test file is part of a series of tests checking this behavior.
+
+Category A: checking simple case invoving a branch being superceeded by another.
+TestCase 4: New changeset as children of the successor
+
+.. old-state:
+..
+.. * 1 changeset branch
+..
+.. new-state:
+..
+.. * 2 changeset branch, first is a successor, but head is new
+..
+.. expected-result:
+..
+.. * push allowed
+..
+.. graph-summary:
+..
+.. ◔ B
+.. |
+.. A ø⇠◔ A'
+.. |/
+.. ○
+
+ $ . $TESTDIR/testlib/checkheads-util.sh
+
+Test setup
+----------
+
+ $ setuprepos
+ creating basic server and client repo
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd client
+ $ hg up 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ mkcommit A1
+ created new head
+ $ hg debugobsolete `getid "desc(A0)" ` `getid "desc(A1)"`
+ $ mkcommit B0
+ $ hg log -G --hidden
+ @ f40ded968333 (draft): B0
+ |
+ o f6082bc4ffef (draft): A1
+ |
+ | x 8aaa48160adc (draft): A0
+ |/
+ o 1e4be0697311 (public): root
+
+
+
+Actual testing
+--------------
+
+ $ hg push
+ pushing to $TESTTMP/server
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 2 files (+1 heads)
+ 1 new obsolescence markers
+
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-checkheads-superceed-A5.t Fri Mar 31 15:44:10 2017 +0200
@@ -0,0 +1,74 @@
+====================================
+Testing head checking code: Case A-5
+====================================
+
+Mercurial checks for the introduction of multiple heads on push. Evolution
+comes into play to detect if existing heads on the server are being replaced by
+some of the new heads we push.
+
+This test file is part of a series of tests checking this behavior.
+
+Category A: checking simple case invoving a branch being superceeded by another.
+TestCase 5: New changeset as parent of the successor
+
+.. old-state:
+..
+.. * 1 changeset branch
+..
+.. new-state:
+..
+.. * 2 changeset branch, head is a successor, but other is new
+..
+.. expected-result:
+..
+.. * push allowed
+..
+.. graph-summary:
+..
+.. A ø⇠◔ A'
+.. | |
+.. | ◔ B
+.. |/
+.. ○
+
+ $ . $TESTDIR/testlib/checkheads-util.sh
+
+Test setup
+----------
+
+ $ setuprepos
+ creating basic server and client repo
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd client
+ $ hg up 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ mkcommit B0
+ created new head
+ $ mkcommit A1
+ $ hg debugobsolete `getid "desc(A0)" ` `getid "desc(A1)"`
+ $ hg log -G --hidden
+ @ ba93660aff8d (draft): A1
+ |
+ o 74ff5441d343 (draft): B0
+ |
+ | x 8aaa48160adc (draft): A0
+ |/
+ o 1e4be0697311 (public): root
+
+
+
+Actual testing
+--------------
+
+ $ hg push
+ pushing to $TESTTMP/server
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 2 files (+1 heads)
+ 1 new obsolescence markers
+
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-checkheads-superceed-A6.t Fri Mar 31 15:44:10 2017 +0200
@@ -0,0 +1,95 @@
+====================================
+Testing head checking code: Case A-6
+====================================
+
+Mercurial checks for the introduction of multiple heads on push. Evolution
+comes into play to detect if existing heads on the server are being replaced by
+some of the new heads we push.
+
+This test file is part of a series of tests checking this behavior.
+
+Category A: checking simple case invoving a branch being superceeded by another.
+TestCase 6: multi-changeset branch, split on multiple other, (base on its own branch)
+
+.. old-state:
+..
+.. * 2 branch (1 changeset, and 2 changesets)
+..
+.. new-state:
+..
+.. * 1 new branch superceeding the base of the old-2-changesets-branch,
+.. * 1 new changesets on the old-1-changeset-branch superceeding the head of the other
+..
+.. expected-result:
+..
+.. * push allowed
+..
+.. graph-summary:
+..
+.. B'◔⇢ø B
+.. | |
+.. A | ø⇠◔ A'
+.. | |/
+.. C ● |
+.. \|
+.. ●
+
+ $ . $TESTDIR/testlib/checkheads-util.sh
+
+Test setup
+----------
+
+ $ setuprepos
+ creating basic server and client repo
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd server
+ $ mkcommit B0
+ $ hg up 0
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ mkcommit C0
+ created new head
+ $ cd ../client
+ $ hg pull
+ pulling from $TESTTMP/server
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 2 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ hg up 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ mkcommit A1
+ created new head
+ $ hg up 'desc(C0)'
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ mkcommit B1
+ $ hg debugobsolete `getid "desc(A0)" ` `getid "desc(A1)"`
+ $ hg debugobsolete `getid "desc(B0)" ` `getid "desc(B1)"`
+ $ hg log -G --hidden
+ @ d70a1f75a020 (draft): B1
+ |
+ | o f6082bc4ffef (draft): A1
+ | |
+ o | 0f88766e02d6 (draft): C0
+ |/
+ | x d73caddc5533 (draft): B0
+ | |
+ | x 8aaa48160adc (draft): A0
+ |/
+ o 1e4be0697311 (public): root
+
+
+
+Actual testing
+--------------
+
+ $ hg push
+ pushing to $TESTTMP/server
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 2 files (+1 heads)
+ 2 new obsolescence markers
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-checkheads-superceed-A7.t Fri Mar 31 15:44:10 2017 +0200
@@ -0,0 +1,95 @@
+====================================
+Testing head checking code: Case A-7
+====================================
+
+Mercurial checks for the introduction of multiple heads on push. Evolution
+comes into play to detect if existing heads on the server are being replaced by
+some of the new heads we push.
+
+This test file is part of a series of tests checking this behavior.
+
+Category A: checking simple case invoving a branch being superceeded by another.
+TestCase 7: multi-changeset branch, split on multiple other, (head on its own branch)
+
+.. old-state:
+..
+.. * 2 branch (1 changeset, and 2 changesets)
+..
+.. new-state:
+..
+.. * 1 new branch superceeding the head of the old-2-changesets-branch,
+.. * 1 new changesets on the old-1-changeset-branch superceeding the base of the other
+..
+.. expected-result:
+..
+.. * push allowed
+..
+.. graph-summary:
+..
+.. B ø⇠◔ B'
+.. | |
+.. A'◔⇢ø |
+.. | |/
+.. C ● |
+.. \|
+.. ●
+
+ $ . $TESTDIR/testlib/checkheads-util.sh
+
+Test setup
+----------
+
+ $ setuprepos
+ creating basic server and client repo
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd server
+ $ mkcommit B0
+ $ hg up 0
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ mkcommit C0
+ created new head
+ $ cd ../client
+ $ hg pull
+ pulling from $TESTTMP/server
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 2 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ hg up 'desc(C0)'
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ mkcommit A1
+ $ hg up 0
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ 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
+ @ 25c56d33e4c4 (draft): B1
+ |
+ | o a0802eb7fc1b (draft): A1
+ | |
+ | o 0f88766e02d6 (draft): C0
+ |/
+ | x d73caddc5533 (draft): B0
+ | |
+ | x 8aaa48160adc (draft): A0
+ |/
+ o 1e4be0697311 (public): root
+
+
+
+Actual testing
+--------------
+
+ $ hg push
+ pushing to $TESTTMP/server
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 2 files (+1 heads)
+ 2 new obsolescence markers
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-checkheads-superceed-A8.t Fri Mar 31 15:44:10 2017 +0200
@@ -0,0 +1,78 @@
+====================================
+Testing head checking code: Case A-8
+====================================
+
+Mercurial checks for the introduction of multiple heads on push. Evolution
+comes into play to detect if existing heads on the server are being replaced by
+some of the new heads we push.
+
+This test file is part of a series of tests checking this behavior.
+
+Category A: checking simple case invoving a branch being superceeded by another.
+TestCase 8: single-changeset branch indirect rewrite
+
+.. old-state:
+..
+.. * 1 changeset branch
+..
+.. new-state:
+..
+.. * 1 changeset branch succeeding to A, through another unpushed changesets
+..
+.. expected-result:
+..
+.. * push allowed
+..
+.. graph-summary:
+..
+.. A'
+.. A ø⇠ø⇠◔ A''
+.. |/ /
+.. | /
+.. |/
+.. ○
+
+ $ . $TESTDIR/testlib/checkheads-util.sh
+
+Test setup
+----------
+
+ $ setuprepos
+ creating basic server and client repo
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd client
+ $ hg up 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ mkcommit A1
+ created new head
+ $ hg up 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ mkcommit A2
+ created new head
+ $ hg debugobsolete `getid "desc(A0)" ` `getid "desc(A1)"`
+ $ hg debugobsolete `getid "desc(A1)" ` `getid "desc(A2)"`
+ $ hg log -G --hidden
+ @ c1f8d089020f (draft): A2
+ |
+ | x f6082bc4ffef (draft): A1
+ |/
+ | x 8aaa48160adc (draft): A0
+ |/
+ o 1e4be0697311 (public): root
+
+
+Actual testing
+--------------
+
+ $ hg push
+ pushing to $TESTTMP/server
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ 2 new obsolescence markers
+
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-checkheads-unpushed-D1.t Fri Mar 31 15:44:10 2017 +0200
@@ -0,0 +1,75 @@
+====================================
+Testing head checking code: Case D-1
+====================================
+
+Mercurial checks for the introduction of multiple heads on push. Evolution
+comes into play to detect if existing heads on the server are being replaced by
+some of the new heads we push.
+
+This test file is part of a series of tests checking this behavior.
+
+Category D: remote head is "obs-affected" locally, but result is not part of the push.
+TestCase 1: remote head is rewritten, but successors is not part of the push
+
+.. old-state:
+..
+.. * 1 changeset branch
+..
+.. new-state:
+..
+.. * 1 changeset branch succeeding the old branch
+.. * 1 new unrelated branch
+..
+.. expected-result:
+..
+.. * pushing only the unrelated branch: denied
+..
+.. graph-summary:
+..
+.. A ø⇠○ A'
+.. |/
+.. | ◔ B
+.. |/
+.. ○
+
+ $ . $TESTDIR/testlib/checkheads-util.sh
+
+Test setup
+----------
+
+ $ setuprepos
+ creating basic server and client repo
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd client
+ $ hg up 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ mkcommit A1
+ created new head
+ $ hg debugobsolete `getid "desc(A0)" ` `getid "desc(A1)"`
+ $ hg up 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ mkcommit B0
+ created new head
+ $ hg log -G --hidden
+ @ 74ff5441d343 (draft): B0
+ |
+ | o f6082bc4ffef (draft): A1
+ |/
+ | x 8aaa48160adc (draft): A0
+ |/
+ o 1e4be0697311 (public): root
+
+
+Actual testing
+--------------
+
+ $ hg push -r 'desc(B0)'
+ pushing to $TESTTMP/server
+ searching for changes
+ abort: push creates new remote head 74ff5441d343!
+ (merge or see 'hg help push' for details about pushing new heads)
+ [255]
+
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-checkheads-unpushed-D2.t Fri Mar 31 15:44:10 2017 +0200
@@ -0,0 +1,90 @@
+====================================
+Testing head checking code: Case D-2
+====================================
+
+Mercurial checks for the introduction of multiple heads on push. Evolution
+comes into play to detect if existing heads on the server are being replaced by
+some of the new heads we push.
+
+This test file is part of a series of tests checking this behavior.
+
+Category D: remote head is "obs-affected" locally, but result is not part of the push.
+TestCase 1: remote branch has 2 changes, head is pruned, second is rewritten but result is not pushed
+
+.. old-state:
+..
+.. * 1 changeset branch
+..
+.. new-state:
+..
+.. * old head is pruned
+.. * 1 new branch succeeding to the other changeset in the old branch
+.. * 1 new unrelated branch
+..
+.. expected-result:
+..
+.. * push allowed
+.. * pushing only the unrelated branch: denied
+..
+.. graph-summary:
+..
+.. B ⊗
+.. |
+.. A ø⇠○ A'
+.. |/
+.. | ◔ C
+.. |/
+.. ○
+
+ $ . $TESTDIR/testlib/checkheads-util.sh
+
+Test setup
+----------
+
+ $ setuprepos
+ creating basic server and client repo
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd server
+ $ mkcommit B0
+ $ cd ../client
+ $ hg pull
+ pulling from $TESTTMP/server
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ (run 'hg update' to get a working copy)
+ $ hg up 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ mkcommit A1
+ created new head
+ $ hg debugobsolete `getid "desc(A0)" ` `getid "desc(A1)"`
+ $ hg debugobsolete --record-parents `getid "desc(B0)"`
+ $ hg up 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ mkcommit C0
+ created new head
+ $ hg log -G --hidden
+ @ 0f88766e02d6 (draft): C0
+ |
+ | o f6082bc4ffef (draft): A1
+ |/
+ | x d73caddc5533 (draft): B0
+ | |
+ | x 8aaa48160adc (draft): A0
+ |/
+ o 1e4be0697311 (public): root
+
+
+Actual testing
+--------------
+
+ $ hg push --rev 'desc(C0)'
+ pushing to $TESTTMP/server
+ searching for changes
+ abort: push creates new remote head 0f88766e02d6!
+ (merge or see 'hg help push' for details about pushing new heads)
+ [255]
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-checkheads-unpushed-D3.t Fri Mar 31 15:44:10 2017 +0200
@@ -0,0 +1,107 @@
+====================================
+Testing head checking code: Case D-3
+====================================
+
+Mercurial checks for the introduction of multiple heads on push. Evolution
+comes into play to detect if existing heads on the server are being replaced by
+some of the new heads we push.
+
+This test file is part of a series of tests checking this behavior.
+
+Category D: remote head is "obs-affected" locally, but result is not part of the push.
+TestCase 3: multi-changeset branch, split on multiple new others, only one of them is pushed
+
+.. old-state:
+..
+.. * 2 changesets branch
+..
+.. new-state:
+..
+.. * 2 new branches, each superseding one changeset in the old one.
+..
+.. expected-result:
+..
+.. * pushing only one of the resulting branch (either of them)
+.. * push denied
+..
+.. graph-summary:
+..
+.. B'◔⇢ø B
+.. | |
+.. A | ø⇠◔ A'
+.. | |/
+.. \|
+.. ●
+
+ $ . $TESTDIR/testlib/checkheads-util.sh
+
+Test setup
+----------
+
+ $ setuprepos
+ creating basic server and client repo
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd server
+ $ mkcommit B0
+ $ hg up 0
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ cd ../client
+ $ hg pull
+ pulling from $TESTTMP/server
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ (run 'hg update' to get a working copy)
+ $ hg up 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ mkcommit A1
+ created new head
+ $ hg up '0'
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ 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
+ @ 25c56d33e4c4 (draft): B1
+ |
+ | o f6082bc4ffef (draft): A1
+ |/
+ | x d73caddc5533 (draft): B0
+ | |
+ | x 8aaa48160adc (draft): A0
+ |/
+ o 1e4be0697311 (public): root
+
+
+
+Actual testing
+--------------
+
+ $ hg push --rev 'desc(A1)'
+ pushing to $TESTTMP/server
+ searching for changes
+ abort: push creates new remote head f6082bc4ffef!
+ (merge or see 'hg help push' for details about pushing new heads)
+ [255]
+ $ hg push --rev 'desc(B1)'
+ pushing to $TESTTMP/server
+ searching for changes
+ abort: push creates new remote head 25c56d33e4c4!
+ (merge or see 'hg help push' for details about pushing new heads)
+ [255]
+
+Extra testing
+-------------
+
+In this case, even a bare push is creating more heads
+
+ $ hg push
+ pushing to $TESTTMP/server
+ searching for changes
+ abort: push creates new remote head 25c56d33e4c4!
+ (merge or see 'hg help push' for details about pushing new heads)
+ [255]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-checkheads-unpushed-D4.t Fri Mar 31 15:44:10 2017 +0200
@@ -0,0 +1,102 @@
+====================================
+Testing head checking code: Case D-4
+====================================
+
+Mercurial checks for the introduction of multiple heads on push. Evolution
+comes into play to detect if existing heads on the server are being replaced by
+some of the new heads we push.
+
+This test file is part of a series of tests checking this behavior.
+
+Category D: remote head is "obs-affected" locally, but result is not part of the push.
+TestCase 4: multi-changeset branch, split on multiple other, (base on its own new branch)
+
+.. old-state:
+..
+.. * 2 branch (1 changeset, and 2 changesets)
+..
+.. new-state:
+..
+.. * 1 new branch superceeding the base of the old-2-changesets-branch,
+.. * 1 new changesets on the old-1-changeset-branch superceeding the head of the other
+..
+.. expected-result:
+..
+.. * push the new branch only -> push denied
+.. * push the existing branch only -> push allowed
+..
+.. graph-summary:
+..
+.. B'◔⇢ø B
+.. | |
+.. A | ø⇠◔ A'
+.. | |/
+.. C ● |
+.. \|
+.. ●
+
+ $ . $TESTDIR/testlib/checkheads-util.sh
+
+Test setup
+----------
+
+ $ setuprepos
+ creating basic server and client repo
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd server
+ $ mkcommit B0
+ $ hg up 0
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ mkcommit C0
+ created new head
+ $ cd ../client
+ $ hg pull
+ pulling from $TESTTMP/server
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 2 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ hg up 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ mkcommit A1
+ created new head
+ $ hg up 'desc(C0)'
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ mkcommit B1
+ $ hg debugobsolete `getid "desc(A0)" ` `getid "desc(A1)"`
+ $ hg debugobsolete `getid "desc(B0)" ` `getid "desc(B1)"`
+ $ hg log -G --hidden
+ @ d70a1f75a020 (draft): B1
+ |
+ | o f6082bc4ffef (draft): A1
+ | |
+ o | 0f88766e02d6 (draft): C0
+ |/
+ | x d73caddc5533 (draft): B0
+ | |
+ | x 8aaa48160adc (draft): A0
+ |/
+ o 1e4be0697311 (public): root
+
+
+
+Actual testing
+--------------
+
+ $ hg push --rev 'desc(A1)'
+ pushing to $TESTTMP/server
+ searching for changes
+ abort: push creates new remote head f6082bc4ffef!
+ (merge or see 'hg help push' for details about pushing new heads)
+ [255]
+ $ hg push --rev 'desc(B1)'
+ pushing to $TESTTMP/server
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ 1 new obsolescence markers
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-checkheads-unpushed-D5.t Fri Mar 31 15:44:10 2017 +0200
@@ -0,0 +1,104 @@
+====================================
+Testing head checking code: Case D-5
+====================================
+
+Mercurial checks for the introduction of multiple heads on push. Evolution
+comes into play to detect if existing heads on the server are being replaced by
+some of the new heads we push.
+
+This test file is part of a series of tests checking this behavior.
+
+Category D: remote head is "obs-affected" locally, but result is not part of the push.
+TestCase 5: multi-changeset branch, split on multiple other, (head on its own new branch)
+
+.. old-state:
+..
+.. * 2 branch (1 changeset, and 2 changesets)
+..
+.. new-state:
+..
+.. * 1 new branch superceeding the head of the old-2-changesets-branch,
+.. * 1 new changesets on the old-1-changeset-branch superceeding the base of the other
+..
+.. expected-result:
+..
+.. * push the new branch only -> push denied
+.. * push the existing branch only -> push allowed
+.. /!\ This push create unstability/orphaning on the other hand and we should
+.. probably detect/warn agains that.
+..
+.. graph-summary:
+..
+.. B ø⇠◔ B'
+.. | |
+.. A'◔⇢ø |
+.. | |/
+.. C ● |
+.. \|
+.. ●
+
+ $ . $TESTDIR/testlib/checkheads-util.sh
+
+Test setup
+----------
+
+ $ setuprepos
+ creating basic server and client repo
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd server
+ $ mkcommit B0
+ $ hg up 0
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ mkcommit C0
+ created new head
+ $ cd ../client
+ $ hg pull
+ pulling from $TESTTMP/server
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 2 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ hg up 'desc(C0)'
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ mkcommit A1
+ $ hg up 0
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ 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
+ @ 25c56d33e4c4 (draft): B1
+ |
+ | o a0802eb7fc1b (draft): A1
+ | |
+ | o 0f88766e02d6 (draft): C0
+ |/
+ | x d73caddc5533 (draft): B0
+ | |
+ | x 8aaa48160adc (draft): A0
+ |/
+ o 1e4be0697311 (public): root
+
+
+
+Actual testing
+--------------
+
+ $ hg push --rev 'desc(B1)'
+ pushing to $TESTTMP/server
+ searching for changes
+ abort: push creates new remote head 25c56d33e4c4!
+ (merge or see 'hg help push' for details about pushing new heads)
+ [255]
+ $ hg push --rev 'desc(A1)'
+ pushing to $TESTTMP/server
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ 1 new obsolescence markers
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-checkheads-unpushed-D6.t Fri Mar 31 15:44:10 2017 +0200
@@ -0,0 +1,78 @@
+====================================
+Testing head checking code: Case D-6
+====================================
+
+Mercurial checks for the introduction of multiple heads on push. Evolution
+comes into play to detect if existing heads on the server are being replaced by
+some of the new heads we push.
+
+This test file is part of a series of tests checking this behavior.
+
+Category D: remote head is "obs-affected" locally, but result is not part of the push.
+TestCase 6: single changesets, superseeded then pruned (on a new changeset unpushed) changeset
+
+This is a partial push variation of B6
+
+.. old-state:
+..
+.. * 1 changeset branch
+..
+.. new-state:
+..
+.. * old branch is rewritten onto another one,
+.. * the new version is then pruned.
+..
+.. expected-result:
+..
+.. * push denied
+..
+.. graph-summary:
+..
+.. A ø⇠⊗ A'
+.. | |
+.. C ◔ | ◔ B
+.. \|/
+.. ●
+
+ $ . $TESTDIR/testlib/checkheads-util.sh
+
+Test setup
+----------
+
+ $ setuprepos
+ creating basic server and client repo
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd client
+ $ hg up 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ mkcommit B0
+ created new head
+ $ mkcommit A1
+ $ hg up '0'
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ mkcommit C0
+ created new head
+ $ hg debugobsolete `getid "desc(A0)"` `getid "desc(A1)"`
+ $ hg debugobsolete --record-parents `getid "desc(A1)"`
+ $ hg log -G --hidden
+ @ 0f88766e02d6 (draft): C0
+ |
+ | x ba93660aff8d (draft): A1
+ | |
+ | o 74ff5441d343 (draft): B0
+ |/
+ | x 8aaa48160adc (draft): A0
+ |/
+ o 1e4be0697311 (public): root
+
+
+Actual testing
+--------------
+
+ $ hg push --rev 'desc(C0)'
+ pushing to $TESTTMP/server
+ searching for changes
+ abort: push creates new remote head 0f88766e02d6!
+ (merge or see 'hg help push' for details about pushing new heads)
+ [255]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-checkheads-unpushed-D7.t Fri Mar 31 15:44:10 2017 +0200
@@ -0,0 +1,92 @@
+====================================
+Testing head checking code: Case D-7
+====================================
+
+Mercurial checks for the introduction of multiple heads on push. Evolution
+comes into play to detect if existing heads on the server are being replaced by
+some of the new heads we push.
+
+This test file is part of a series of tests checking this behavior.
+
+Category D: remote head is "obs-affected" locally, but result is not part of the push.
+TestCase 7: single changesets, superseeded multiple time then pruned (on a new changeset unpushed) changeset
+
+This is a partial push variation of B6
+
+.. old-state:
+..
+.. * 1 changeset branch
+..
+.. new-state:
+..
+.. * old branch is rewritten onto another one,
+.. * The rewriting it again rewritten on the root
+.. * the new version is then pruned.
+..
+.. expected-result:
+..
+.. * push allowed
+..
+.. graph-summary:
+..
+.. A'
+.. A ø⇠ø⇠⊗ A''
+.. | | |
+.. C ◔ | ◔ | B
+.. \|/ /
+.. | /
+.. |/
+.. |
+.. ●
+
+ $ . $TESTDIR/testlib/checkheads-util.sh
+
+Test setup
+----------
+
+ $ setuprepos
+ creating basic server and client repo
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd client
+ $ hg up 0
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ mkcommit B0
+ created new head
+ $ mkcommit A1
+ $ hg up '0'
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ mkcommit A2
+ created new head
+ $ hg up '0'
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ mkcommit C0
+ created new head
+ $ hg debugobsolete `getid "desc(A0)"` `getid "desc(A1)"`
+ $ hg debugobsolete `getid "desc(A1)"` `getid "desc(A2)"`
+ $ hg debugobsolete --record-parents `getid "desc(A2)"`
+ $ hg log -G --hidden
+ @ 0f88766e02d6 (draft): C0
+ |
+ | x c1f8d089020f (draft): A2
+ |/
+ | x ba93660aff8d (draft): A1
+ | |
+ | o 74ff5441d343 (draft): B0
+ |/
+ | x 8aaa48160adc (draft): A0
+ |/
+ o 1e4be0697311 (public): root
+
+
+Actual testing
+--------------
+
+ $ hg push --rev 'desc(C0)'
+ pushing to $TESTTMP/server
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ 3 new obsolescence markers
--- a/tests/test-discovery-obshashrange.t Tue Mar 14 14:47:20 2017 -0700
+++ b/tests/test-discovery-obshashrange.t Fri Mar 31 15:44:10 2017 +0200
@@ -57,23 +57,23 @@
dddddddddddddddddddddddddddddddddddddddd c8d03c1b5e94af74b772900c58259d2e08917735 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee 4de32a90b66cd083ebf3c00b41277aa7abca51dd 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
- $ hg debugstablerange --rev tip
- rev node index size depth obshash
- 7 4de32a90b66c 0 8 8 38d1e7ad86ea
- 3 2dc09a01254d 0 4 4 000000000000
- 7 4de32a90b66c 4 4 8 38d1e7ad86ea
- 3 2dc09a01254d 2 2 4 000000000000
- 7 4de32a90b66c 6 2 8 033544c939f0
- 1 66f7d451a68b 0 2 2 17ff8dd63509
- 5 c8d03c1b5e94 4 2 6 57f6cf3757a2
- 2 01241442b3c2 2 1 3 1ed3c61fb39a
- 0 1ea73414a91b 0 1 1 000000000000
- 3 2dc09a01254d 3 1 4 000000000000
- 7 4de32a90b66c 7 1 8 033544c939f0
- 1 66f7d451a68b 1 1 2 17ff8dd63509
- 4 bebd167eb94d 4 1 5 bbe4d7fe27a8
- 5 c8d03c1b5e94 5 1 6 446c2dc3bce5
- 6 f69452c5b1af 6 1 7 000000000000
+ $ hg debugobshashrange --subranges --rev tip
+ rev node index size depth obshash
+ 7 4de32a90b66c 0 8 8 38d1e7ad86ea
+ 3 2dc09a01254d 0 4 4 000000000000
+ 7 4de32a90b66c 4 4 8 38d1e7ad86ea
+ 3 2dc09a01254d 2 2 4 000000000000
+ 7 4de32a90b66c 6 2 8 033544c939f0
+ 1 66f7d451a68b 0 2 2 17ff8dd63509
+ 5 c8d03c1b5e94 4 2 6 57f6cf3757a2
+ 2 01241442b3c2 2 1 3 1ed3c61fb39a
+ 0 1ea73414a91b 0 1 1 000000000000
+ 3 2dc09a01254d 3 1 4 000000000000
+ 7 4de32a90b66c 7 1 8 033544c939f0
+ 1 66f7d451a68b 1 1 2 17ff8dd63509
+ 4 bebd167eb94d 4 1 5 bbe4d7fe27a8
+ 5 c8d03c1b5e94 5 1 6 446c2dc3bce5
+ 6 f69452c5b1af 6 1 7 000000000000
$ cd ..
testing simple pull
--- a/tests/test-evolve.t Tue Mar 14 14:47:20 2017 -0700
+++ b/tests/test-evolve.t Fri Mar 31 15:44:10 2017 +0200
@@ -171,11 +171,11 @@
Smoketest stablerange.obshash:
- $ hg debugstablerange --rev 'head()'
- rev node index size depth obshash
- 1 7c3bad9141dc 0 2 2 * (glob)
- 0 1f0dee641bb7 0 1 1 000000000000
- 1 7c3bad9141dc 1 1 2 * (glob)
+ $ hg debugobshashrange --subranges --rev 'head()'
+ rev node index size depth obshash
+ 1 7c3bad9141dc 0 2 2 * (glob)
+ 0 1f0dee641bb7 0 1 1 000000000000
+ 1 7c3bad9141dc 1 1 2 * (glob)
$ cd ..
--- a/tests/test-exchange-A1.t Tue Mar 14 14:47:20 2017 -0700
+++ b/tests/test-exchange-A1.t Fri Mar 31 15:44:10 2017 +0200
@@ -1,7 +1,7 @@
Initial setup
- $ . $TESTDIR/_exc-util.sh
+ $ . $TESTDIR/testlib/exchange-util.sh
==== A.1.1 pushing a single head ====
..
@@ -48,11 +48,11 @@
$ hg debugobsrelsethashtree
a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04 0000000000000000000000000000000000000000
f5bc6836db60e308a17ba08bf050154ba9c4fad7 50656e04a95ecdfed94659dd61f663b2caa55e98
- $ hg debugstablerange --rev 'head()'
- rev node index size depth obshash
- 1 f5bc6836db60 0 2 2 50656e04a95e
- 0 a9bdc8b26820 0 1 1 000000000000
- 1 f5bc6836db60 1 1 2 50656e04a95e
+ $ hg debugobshashrange --subranges --rev 'head()'
+ rev node index size depth obshash
+ 1 f5bc6836db60 0 2 2 50656e04a95e
+ 0 a9bdc8b26820 0 1 1 000000000000
+ 1 f5bc6836db60 1 1 2 50656e04a95e
$ cd ..
$ cd ..
--- a/tests/test-exchange-A2.t Tue Mar 14 14:47:20 2017 -0700
+++ b/tests/test-exchange-A2.t Fri Mar 31 15:44:10 2017 +0200
@@ -2,7 +2,7 @@
Initial setup
- $ . $TESTDIR/_exc-util.sh
+ $ . $TESTDIR/testlib/exchange-util.sh
=== A.2 Two heads ===
@@ -61,13 +61,13 @@
a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04 0000000000000000000000000000000000000000
f5bc6836db60e308a17ba08bf050154ba9c4fad7 50656e04a95ecdfed94659dd61f663b2caa55e98
35b1839966785d5703a01607229eea932db42f87 b9c8f20eef8938ebab939fe6a592587feacf3245
- $ hg debugstablerange --rev 'head()'
- rev node index size depth obshash
- 2 35b183996678 0 2 2 b9c8f20eef89
- 1 f5bc6836db60 0 2 2 50656e04a95e
- 2 35b183996678 1 1 2 b9c8f20eef89
- 0 a9bdc8b26820 0 1 1 000000000000
- 1 f5bc6836db60 1 1 2 50656e04a95e
+ $ hg debugobshashrange --subranges --rev 'head()'
+ rev node index size depth obshash
+ 2 35b183996678 0 2 2 b9c8f20eef89
+ 1 f5bc6836db60 0 2 2 50656e04a95e
+ 2 35b183996678 1 1 2 b9c8f20eef89
+ 0 a9bdc8b26820 0 1 1 000000000000
+ 1 f5bc6836db60 1 1 2 50656e04a95e
$ cd ..
$ cd ..
--- a/tests/test-exchange-A3.t Tue Mar 14 14:47:20 2017 -0700
+++ b/tests/test-exchange-A3.t Fri Mar 31 15:44:10 2017 +0200
@@ -1,7 +1,7 @@
Initial setup
- $ . $TESTDIR/_exc-util.sh
+ $ . $TESTDIR/testlib/exchange-util.sh
=== A.3 new branch created ===
@@ -76,13 +76,13 @@
6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 0000000000000000000000000000000000000000
e5ea8f9c73143125d36658e90ef70c6d2027a5b7 3bc2ee626e11a7cf8fee7a66d069271e17d5a597
f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 91716bfd671b5a5854a47ac5d392edfdd25e431a
- $ hg debugstablerange --rev 'head()'
- rev node index size depth obshash
- 3 e5ea8f9c7314 0 2 2 3bc2ee626e11
- 4 f6298a8ac3a4 0 2 2 91716bfd671b
- 0 a9bdc8b26820 0 1 1 000000000000
- 3 e5ea8f9c7314 1 1 2 3bc2ee626e11
- 4 f6298a8ac3a4 1 1 2 91716bfd671b
+ $ hg debugobshashrange --subranges --rev 'head()'
+ rev node index size depth obshash
+ 3 e5ea8f9c7314 0 2 2 3bc2ee626e11
+ 4 f6298a8ac3a4 0 2 2 91716bfd671b
+ 0 a9bdc8b26820 0 1 1 000000000000
+ 3 e5ea8f9c7314 1 1 2 3bc2ee626e11
+ 4 f6298a8ac3a4 1 1 2 91716bfd671b
$ cd ..
$ cd ..
@@ -181,7 +181,7 @@
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)
+ (merge or see 'hg help push' for details about pushing new heads)
[255]
$ cd ..
--- a/tests/test-exchange-A4.t Tue Mar 14 14:47:20 2017 -0700
+++ b/tests/test-exchange-A4.t Fri Mar 31 15:44:10 2017 +0200
@@ -1,7 +1,7 @@
Initial setup
- $ . $TESTDIR/_exc-util.sh
+ $ . $TESTDIR/testlib/exchange-util.sh
=== A.4 Push in the middle of the obsolescence chain ===
@@ -68,15 +68,15 @@
28b51eb45704506b5c603decd6bf7ac5e0f6a52f 5d69322fad9eb1ba8f8f2c2312346ed347fdde76
06055a7959d4128e6e3bccfd01482e83a2db8a3a fd3e5712c9c2d216547d7a1b87ac815ee1fb7542
e5ea8f9c73143125d36658e90ef70c6d2027a5b7 cf518031fa753e9b049d727e6b0e19f645bab38f
- $ hg debugstablerange --rev 'head()'
- rev node index size depth obshash
- 2 06055a7959d4 0 3 3 000000000000
- 1 28b51eb45704 0 2 2 5d69322fad9e
- 3 e5ea8f9c7314 0 2 2 cf518031fa75
- 2 06055a7959d4 2 1 3 000000000000
- 1 28b51eb45704 1 1 2 5d69322fad9e
- 0 a9bdc8b26820 0 1 1 000000000000
- 3 e5ea8f9c7314 1 1 2 cf518031fa75
+ $ hg debugobshashrange --subranges --rev 'head()'
+ rev node index size depth obshash
+ 2 06055a7959d4 0 3 3 000000000000
+ 1 28b51eb45704 0 2 2 5d69322fad9e
+ 3 e5ea8f9c7314 0 2 2 cf518031fa75
+ 2 06055a7959d4 2 1 3 000000000000
+ 1 28b51eb45704 1 1 2 5d69322fad9e
+ 0 a9bdc8b26820 0 1 1 000000000000
+ 3 e5ea8f9c7314 1 1 2 cf518031fa75
$ cd ..
$ cd ..
--- a/tests/test-exchange-A5.t Tue Mar 14 14:47:20 2017 -0700
+++ b/tests/test-exchange-A5.t Fri Mar 31 15:44:10 2017 +0200
@@ -2,7 +2,7 @@
Initial setup
- $ . $TESTDIR/_exc-util.sh
+ $ . $TESTDIR/testlib/exchange-util.sh
=== A.5 partial reordering ===
@@ -75,13 +75,13 @@
6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 fd3e5712c9c2d216547d7a1b87ac815ee1fb7542
f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 91716bfd671b5a5854a47ac5d392edfdd25e431a
8c0a98c8372212c6efde4bfdcef006f27ff759d3 6e8c8c71c47a2bfc27c7cf2b1f4174977ede9f21
- $ hg debugstablerange --rev 'head()'
- rev node index size depth obshash
- 4 8c0a98c83722 0 3 3 70185b996296
- 3 f6298a8ac3a4 0 2 2 91716bfd671b
- 4 8c0a98c83722 2 1 3 4d835a45c1e9
- 0 a9bdc8b26820 0 1 1 000000000000
- 3 f6298a8ac3a4 1 1 2 91716bfd671b
+ $ hg debugobshashrange --subranges --rev 'head()'
+ rev node index size depth obshash
+ 4 8c0a98c83722 0 3 3 70185b996296
+ 3 f6298a8ac3a4 0 2 2 91716bfd671b
+ 4 8c0a98c83722 2 1 3 4d835a45c1e9
+ 0 a9bdc8b26820 0 1 1 000000000000
+ 3 f6298a8ac3a4 1 1 2 91716bfd671b
$ cd ..
$ cd ..
--- a/tests/test-exchange-A6.t Tue Mar 14 14:47:20 2017 -0700
+++ b/tests/test-exchange-A6.t Fri Mar 31 15:44:10 2017 +0200
@@ -3,7 +3,7 @@
Initial setup
- $ . $TESTDIR/_exc-util.sh
+ $ . $TESTDIR/testlib/exchange-util.sh
=== A.6 between existing changeset ===
@@ -63,11 +63,11 @@
a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04 0000000000000000000000000000000000000000
28b51eb45704506b5c603decd6bf7ac5e0f6a52f 0000000000000000000000000000000000000000
e5ea8f9c73143125d36658e90ef70c6d2027a5b7 3bc2ee626e11a7cf8fee7a66d069271e17d5a597
- $ hg debugstablerange --rev 'head()'
- rev node index size depth obshash
- 2 e5ea8f9c7314 0 2 2 3bc2ee626e11
- 0 a9bdc8b26820 0 1 1 000000000000
- 2 e5ea8f9c7314 1 1 2 3bc2ee626e11
+ $ hg debugobshashrange --subranges --rev 'head()'
+ rev node index size depth obshash
+ 2 e5ea8f9c7314 0 2 2 3bc2ee626e11
+ 0 a9bdc8b26820 0 1 1 000000000000
+ 2 e5ea8f9c7314 1 1 2 3bc2ee626e11
$ cd ..
$ cd ..
--- a/tests/test-exchange-A7.t Tue Mar 14 14:47:20 2017 -0700
+++ b/tests/test-exchange-A7.t Fri Mar 31 15:44:10 2017 +0200
@@ -1,7 +1,7 @@
Initial setup
- $ . $TESTDIR/_exc-util.sh
+ $ . $TESTDIR/testlib/exchange-util.sh
=== A.7 Non targeted common changeset ===
@@ -45,11 +45,11 @@
$ hg debugobsrelsethashtree
a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04 0000000000000000000000000000000000000000
f5bc6836db60e308a17ba08bf050154ba9c4fad7 50656e04a95ecdfed94659dd61f663b2caa55e98
- $ hg debugstablerange --rev 'head()'
- rev node index size depth obshash
- 1 f5bc6836db60 0 2 2 50656e04a95e
- 0 a9bdc8b26820 0 1 1 000000000000
- 1 f5bc6836db60 1 1 2 50656e04a95e
+ $ hg debugobshashrange --subranges --rev 'head()'
+ rev node index size depth obshash
+ 1 f5bc6836db60 0 2 2 50656e04a95e
+ 0 a9bdc8b26820 0 1 1 000000000000
+ 1 f5bc6836db60 1 1 2 50656e04a95e
$ cd ..
$ cd ..
--- a/tests/test-exchange-B1.t Tue Mar 14 14:47:20 2017 -0700
+++ b/tests/test-exchange-B1.t Fri Mar 31 15:44:10 2017 +0200
@@ -1,7 +1,7 @@
Initial setup
- $ . $TESTDIR/_exc-util.sh
+ $ . $TESTDIR/testlib/exchange-util.sh
=== B.1 Prune on non-targeted common changeset ===
@@ -50,11 +50,11 @@
a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04 0000000000000000000000000000000000000000
f5bc6836db60e308a17ba08bf050154ba9c4fad7 926d9d84b97b3483891ae983990ad87c1f7827e9
f6fbb35d8ac958bbe70035e4c789c18471cdc0af e041f7ff1c7bd5501c7ab602baa35f0873128021
- $ hg debugstablerange --rev 'head()'
- rev node index size depth obshash
- 1 f5bc6836db60 0 2 2 926d9d84b97b
- 0 a9bdc8b26820 0 1 1 000000000000
- 1 f5bc6836db60 1 1 2 926d9d84b97b
+ $ hg debugobshashrange --subranges --rev 'head()'
+ rev node index size depth obshash
+ 1 f5bc6836db60 0 2 2 926d9d84b97b
+ 0 a9bdc8b26820 0 1 1 000000000000
+ 1 f5bc6836db60 1 1 2 926d9d84b97b
$ cd ..
$ cd ..
--- a/tests/test-exchange-B2.t Tue Mar 14 14:47:20 2017 -0700
+++ b/tests/test-exchange-B2.t Fri Mar 31 15:44:10 2017 +0200
@@ -1,7 +1,7 @@
Initial setup
- $ . $TESTDIR/_exc-util.sh
+ $ . $TESTDIR/testlib/exchange-util.sh
=== B.2 Pruned changeset on head: nothing pushed ===
@@ -44,9 +44,9 @@
$ hg debugobsrelsethashtree
a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04 52a5380bc04783a9ad43bb2ab2f47a02ef02adcc
f5bc6836db60e308a17ba08bf050154ba9c4fad7 c5a567339e205e8cc4c494e4fb82944daaec449c
- $ hg debugstablerange --rev 'head()'
- rev node index size depth obshash
- 0 a9bdc8b26820 0 1 1 52a5380bc047
+ $ hg debugobshashrange --subranges --rev 'head()'
+ rev node index size depth obshash
+ 0 a9bdc8b26820 0 1 1 52a5380bc047
$ cd ..
$ cd ..
--- a/tests/test-exchange-B3.t Tue Mar 14 14:47:20 2017 -0700
+++ b/tests/test-exchange-B3.t Fri Mar 31 15:44:10 2017 +0200
@@ -2,7 +2,7 @@
Initial setup
- $ . $TESTDIR/_exc-util.sh
+ $ . $TESTDIR/testlib/exchange-util.sh
=== B.3 Pruned changeset on non-pushed part of the history ===
@@ -62,13 +62,13 @@
f5bc6836db60e308a17ba08bf050154ba9c4fad7 0000000000000000000000000000000000000000
35b1839966785d5703a01607229eea932db42f87 631ab4cd02ffa1d144dc8f32a18be574076031e3
e56289ab6378dc752fd7965f8bf66b58bda740bd 47c9d2d8db5d4b1eddd0266329ad260ccc84772c
- $ hg debugstablerange --rev 'head()'
- rev node index size depth obshash
- 2 35b183996678 0 2 2 631ab4cd02ff
- 1 f5bc6836db60 0 2 2 000000000000
- 2 35b183996678 1 1 2 631ab4cd02ff
- 0 a9bdc8b26820 0 1 1 000000000000
- 1 f5bc6836db60 1 1 2 000000000000
+ $ hg debugobshashrange --subranges --rev 'head()'
+ rev node index size depth obshash
+ 2 35b183996678 0 2 2 631ab4cd02ff
+ 1 f5bc6836db60 0 2 2 000000000000
+ 2 35b183996678 1 1 2 631ab4cd02ff
+ 0 a9bdc8b26820 0 1 1 000000000000
+ 1 f5bc6836db60 1 1 2 000000000000
$ cd ..
$ cd ..
--- a/tests/test-exchange-B4.t Tue Mar 14 14:47:20 2017 -0700
+++ b/tests/test-exchange-B4.t Fri Mar 31 15:44:10 2017 +0200
@@ -1,7 +1,7 @@
Initial setup
- $ . $TESTDIR/_exc-util.sh
+ $ . $TESTDIR/testlib/exchange-util.sh
=== B.4 Pruned changeset on common part of history ===
@@ -72,13 +72,13 @@
f5bc6836db60e308a17ba08bf050154ba9c4fad7 c27e764c783f451ef3aa40daf2a3795e6674cd06
f6fbb35d8ac958bbe70035e4c789c18471cdc0af 907beff79fdff2b82b5d3bed7989107a6d744508
7f7f229b13a629a5b20581c6cb723f4e2ca54bed c27e764c783f451ef3aa40daf2a3795e6674cd06
- $ hg debugstablerange --rev 'head()'
- rev node index size depth obshash
- 2 f6fbb35d8ac9 0 3 3 000000000000
- 1 f5bc6836db60 0 2 2 000000000000
- 0 a9bdc8b26820 0 1 1 1900882e85db
- 1 f5bc6836db60 1 1 2 000000000000
- 2 f6fbb35d8ac9 2 1 3 000000000000
+ $ hg debugobshashrange --subranges --rev 'head()'
+ rev node index size depth obshash
+ 2 f6fbb35d8ac9 0 3 3 000000000000
+ 1 f5bc6836db60 0 2 2 000000000000
+ 0 a9bdc8b26820 0 1 1 1900882e85db
+ 1 f5bc6836db60 1 1 2 000000000000
+ 2 f6fbb35d8ac9 2 1 3 000000000000
$ cd ..
$ cd ..
--- a/tests/test-exchange-B5.t Tue Mar 14 14:47:20 2017 -0700
+++ b/tests/test-exchange-B5.t Fri Mar 31 15:44:10 2017 +0200
@@ -3,7 +3,7 @@
Initial setup
- $ . $TESTDIR/_exc-util.sh
+ $ . $TESTDIR/testlib/exchange-util.sh
=== B.5 Push of a children of changeset which successors is pruned ===
@@ -71,13 +71,13 @@
28b51eb45704506b5c603decd6bf7ac5e0f6a52f 5c81c58ce0a8ad61dd9cf4c6949846b5990af30d
06055a7959d4128e6e3bccfd01482e83a2db8a3a 201e20697f2a6b0752335af7cd813f140e9e653e
e5ea8f9c73143125d36658e90ef70c6d2027a5b7 ae1ac676a5e6d6f4216595c53da763d588929970
- $ hg debugstablerange --rev 'head()'
- rev node index size depth obshash
- 2 06055a7959d4 0 3 3 000000000000
- 1 28b51eb45704 0 2 2 000000000000
- 2 06055a7959d4 2 1 3 000000000000
- 1 28b51eb45704 1 1 2 000000000000
- 0 a9bdc8b26820 0 1 1 554c0b12f7d9
+ $ hg debugobshashrange --subranges --rev 'head()'
+ rev node index size depth obshash
+ 2 06055a7959d4 0 3 3 000000000000
+ 1 28b51eb45704 0 2 2 000000000000
+ 2 06055a7959d4 2 1 3 000000000000
+ 1 28b51eb45704 1 1 2 000000000000
+ 0 a9bdc8b26820 0 1 1 554c0b12f7d9
$ cd ..
$ cd ..
--- a/tests/test-exchange-B6.t Tue Mar 14 14:47:20 2017 -0700
+++ b/tests/test-exchange-B6.t Fri Mar 31 15:44:10 2017 +0200
@@ -4,7 +4,7 @@
Initial setup
- $ . $TESTDIR/_exc-util.sh
+ $ . $TESTDIR/testlib/exchange-util.sh
== B.6 Pruned changeset with ancestors not in pushed set ===
@@ -61,11 +61,11 @@
f5bc6836db60e308a17ba08bf050154ba9c4fad7 f2e05412d3f1d5bc1ae647cf9efc43e0399c26ca
962ecf6b1afc94e15c7e48fdfb76ef8abd11372b 974507d1c466d0aa86d288836194339ed3b98736
f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 04e03a8959d8a39984e6a8f4a16fba975b364747
- $ hg debugstablerange --rev 'head()'
- rev node index size depth obshash
- 1 f5bc6836db60 0 2 2 000000000000
- 0 a9bdc8b26820 0 1 1 86e41541149f
- 1 f5bc6836db60 1 1 2 000000000000
+ $ hg debugobshashrange --subranges --rev 'head()'
+ rev node index size depth obshash
+ 1 f5bc6836db60 0 2 2 000000000000
+ 0 a9bdc8b26820 0 1 1 86e41541149f
+ 1 f5bc6836db60 1 1 2 000000000000
$ cd ..
$ cd ..
--- a/tests/test-exchange-B7.t Tue Mar 14 14:47:20 2017 -0700
+++ b/tests/test-exchange-B7.t Fri Mar 31 15:44:10 2017 +0200
@@ -1,7 +1,7 @@
Initial setup
- $ . $TESTDIR/_exc-util.sh
+ $ . $TESTDIR/testlib/exchange-util.sh
=== B.7 Prune on non-targeted common changeset ===
@@ -53,11 +53,11 @@
a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04 0000000000000000000000000000000000000000
f5bc6836db60e308a17ba08bf050154ba9c4fad7 926d9d84b97b3483891ae983990ad87c1f7827e9
f6fbb35d8ac958bbe70035e4c789c18471cdc0af e041f7ff1c7bd5501c7ab602baa35f0873128021
- $ hg debugstablerange --rev 'head()'
- rev node index size depth obshash
- 1 f5bc6836db60 0 2 2 926d9d84b97b
- 0 a9bdc8b26820 0 1 1 000000000000
- 1 f5bc6836db60 1 1 2 926d9d84b97b
+ $ hg debugobshashrange --subranges --rev 'head()'
+ rev node index size depth obshash
+ 1 f5bc6836db60 0 2 2 926d9d84b97b
+ 0 a9bdc8b26820 0 1 1 000000000000
+ 1 f5bc6836db60 1 1 2 926d9d84b97b
$ cd ..
$ cd ..
--- a/tests/test-exchange-C1.t Tue Mar 14 14:47:20 2017 -0700
+++ b/tests/test-exchange-C1.t Fri Mar 31 15:44:10 2017 +0200
@@ -1,7 +1,7 @@
Initial setup
- $ . $TESTDIR/_exc-util.sh
+ $ . $TESTDIR/testlib/exchange-util.sh
=== C.1 Multiple pruned changeset atop each other ===
..
@@ -52,9 +52,9 @@
a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04 1ce18e5a71f78d443a80c819f2f7197c4706af70
f5bc6836db60e308a17ba08bf050154ba9c4fad7 92af733686ce7e0469d8b2b87b4612a4c2d33468
f6fbb35d8ac958bbe70035e4c789c18471cdc0af 3800aeba3728457abb9c508c94f6abc59e698c55
- $ hg debugstablerange --rev 'head()'
- rev node index size depth obshash
- 0 a9bdc8b26820 0 1 1 1ce18e5a71f7
+ $ hg debugobshashrange --subranges --rev 'head()'
+ rev node index size depth obshash
+ 0 a9bdc8b26820 0 1 1 1ce18e5a71f7
$ cd ..
$ cd ..
--- a/tests/test-exchange-C2.t Tue Mar 14 14:47:20 2017 -0700
+++ b/tests/test-exchange-C2.t Fri Mar 31 15:44:10 2017 +0200
@@ -2,7 +2,7 @@
Initial setup
- $ . $TESTDIR/_exc-util.sh
+ $ . $TESTDIR/testlib/exchange-util.sh
=== C.2 Pruned changeset on precursors ===
@@ -60,11 +60,11 @@
28b51eb45704506b5c603decd6bf7ac5e0f6a52f 72f95b7b9fa12243aeb90433d211f2c38263da31
06055a7959d4128e6e3bccfd01482e83a2db8a3a 58ecf9a107b10986d88da605eb0d03b7f24ae486
e5ea8f9c73143125d36658e90ef70c6d2027a5b7 289cb0d058c81c763eca8bb438657dba9a7ba646
- $ hg debugstablerange --rev 'head()'
- rev node index size depth obshash
- 3 e5ea8f9c7314 0 2 2 289cb0d058c8
- 0 a9bdc8b26820 0 1 1 000000000000
- 3 e5ea8f9c7314 1 1 2 289cb0d058c8
+ $ hg debugobshashrange --subranges --rev 'head()'
+ rev node index size depth obshash
+ 3 e5ea8f9c7314 0 2 2 289cb0d058c8
+ 0 a9bdc8b26820 0 1 1 000000000000
+ 3 e5ea8f9c7314 1 1 2 289cb0d058c8
$ cd ..
$ cd ..
--- a/tests/test-exchange-C3.t Tue Mar 14 14:47:20 2017 -0700
+++ b/tests/test-exchange-C3.t Fri Mar 31 15:44:10 2017 +0200
@@ -2,7 +2,7 @@
Initial setup
- $ . $TESTDIR/_exc-util.sh
+ $ . $TESTDIR/testlib/exchange-util.sh
=== C.3 Pruned changeset on precursors of another pruned one ===
@@ -65,9 +65,9 @@
28b51eb45704506b5c603decd6bf7ac5e0f6a52f beac7228bbe708bc7c9181c3c27f8a17f21dbd9f
06055a7959d4128e6e3bccfd01482e83a2db8a3a 8b648bd67281e9e525919285ac7b3bb2836c2f02
e5ea8f9c73143125d36658e90ef70c6d2027a5b7 dcd2b566ad0983333be704afdc205066e1a6b742
- $ hg debugstablerange --rev 'head()'
- rev node index size depth obshash
- 0 a9bdc8b26820 0 1 1 40be80b35671
+ $ hg debugobshashrange --subranges --rev 'head()'
+ rev node index size depth obshash
+ 0 a9bdc8b26820 0 1 1 40be80b35671
$ cd ..
$ cd ..
--- a/tests/test-exchange-C4.t Tue Mar 14 14:47:20 2017 -0700
+++ b/tests/test-exchange-C4.t Fri Mar 31 15:44:10 2017 +0200
@@ -2,7 +2,7 @@
Initial setup
- $ . $TESTDIR/_exc-util.sh
+ $ . $TESTDIR/testlib/exchange-util.sh
=== C.4 multiple successors, one is pruned ===
@@ -75,11 +75,11 @@
f5bc6836db60e308a17ba08bf050154ba9c4fad7 619b4d13bd9878f04d7208dcfcf1e89da826f6be
35b1839966785d5703a01607229eea932db42f87 ddeb7b7a87378f59cecb36d5146df0092b6b3327
7f7f229b13a629a5b20581c6cb723f4e2ca54bed 58ef2e726c5bd89bceffb6243294b38eadbf3d60
- $ hg debugstablerange --rev 'head()'
- rev node index size depth obshash
- 2 35b183996678 0 2 2 2a098b4a877f
- 2 35b183996678 1 1 2 916e804c50de
- 0 a9bdc8b26820 0 1 1 a9c02d134f5b
+ $ hg debugobshashrange --subranges --rev 'head()'
+ rev node index size depth obshash
+ 2 35b183996678 0 2 2 2a098b4a877f
+ 2 35b183996678 1 1 2 916e804c50de
+ 0 a9bdc8b26820 0 1 1 a9c02d134f5b
$ cd ..
$ cd ..
--- a/tests/test-exchange-D1.t Tue Mar 14 14:47:20 2017 -0700
+++ b/tests/test-exchange-D1.t Fri Mar 31 15:44:10 2017 +0200
@@ -1,7 +1,7 @@
Initial setup
- $ . $TESTDIR/_exc-util.sh
+ $ . $TESTDIR/testlib/exchange-util.sh
=== D.1 Pruned changeset based on missing precursor of something not present ===
@@ -55,11 +55,11 @@
$ hg debugobsrelsethashtree
a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04 0000000000000000000000000000000000000000
e5ea8f9c73143125d36658e90ef70c6d2027a5b7 289cb0d058c81c763eca8bb438657dba9a7ba646
- $ hg debugstablerange --rev 'head()'
- rev node index size depth obshash
- 1 e5ea8f9c7314 0 2 2 289cb0d058c8
- 0 a9bdc8b26820 0 1 1 000000000000
- 1 e5ea8f9c7314 1 1 2 289cb0d058c8
+ $ hg debugobshashrange --subranges --rev 'head()'
+ rev node index size depth obshash
+ 1 e5ea8f9c7314 0 2 2 289cb0d058c8
+ 0 a9bdc8b26820 0 1 1 000000000000
+ 1 e5ea8f9c7314 1 1 2 289cb0d058c8
$ cd ..
$ cd ..
--- a/tests/test-exchange-D2.t Tue Mar 14 14:47:20 2017 -0700
+++ b/tests/test-exchange-D2.t Fri Mar 31 15:44:10 2017 +0200
@@ -2,7 +2,7 @@
Initial setup
- $ . $TESTDIR/_exc-util.sh
+ $ . $TESTDIR/testlib/exchange-util.sh
=== D.2 missing prune target (prune in "pushed set") ===
@@ -52,9 +52,9 @@
$ hg debugobsrelsethashtree
a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04 554c0b12f7d9fff20cb904c26e12eee337e3309c
28b51eb45704506b5c603decd6bf7ac5e0f6a52f 5c81c58ce0a8ad61dd9cf4c6949846b5990af30d
- $ hg debugstablerange --rev 'head()'
- rev node index size depth obshash
- 0 a9bdc8b26820 0 1 1 554c0b12f7d9
+ $ hg debugobshashrange --subranges --rev 'head()'
+ rev node index size depth obshash
+ 0 a9bdc8b26820 0 1 1 554c0b12f7d9
$ cd ..
$ cd ..
--- a/tests/test-exchange-D3.t Tue Mar 14 14:47:20 2017 -0700
+++ b/tests/test-exchange-D3.t Fri Mar 31 15:44:10 2017 +0200
@@ -3,7 +3,7 @@
Initial setup
- $ . $TESTDIR/_exc-util.sh
+ $ . $TESTDIR/testlib/exchange-util.sh
=== D.2 missing prune target (prune in "pushed set") ===
@@ -57,11 +57,11 @@
a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04 0000000000000000000000000000000000000000
28b51eb45704506b5c603decd6bf7ac5e0f6a52f 0000000000000000000000000000000000000000
35b1839966785d5703a01607229eea932db42f87 65a9f21dff0702355e973a8f31d3b3b7e59376fb
- $ hg debugstablerange --rev 'head()'
- rev node index size depth obshash
- 2 35b183996678 0 2 2 65a9f21dff07
- 2 35b183996678 1 1 2 65a9f21dff07
- 0 a9bdc8b26820 0 1 1 000000000000
+ $ hg debugobshashrange --subranges --rev 'head()'
+ rev node index size depth obshash
+ 2 35b183996678 0 2 2 65a9f21dff07
+ 2 35b183996678 1 1 2 65a9f21dff07
+ 0 a9bdc8b26820 0 1 1 000000000000
$ cd ..
$ cd ..
--- a/tests/test-exchange-D4.t Tue Mar 14 14:47:20 2017 -0700
+++ b/tests/test-exchange-D4.t Fri Mar 31 15:44:10 2017 +0200
@@ -2,7 +2,7 @@
Initial setup
- $ . $TESTDIR/_exc-util.sh
+ $ . $TESTDIR/testlib/exchange-util.sh
=== D.4 Unknown changeset in between known one ===
@@ -71,13 +71,13 @@
6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 0000000000000000000000000000000000000000
e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0aacc2f86e8fca29f2d5fd8d0790644620acd58a
069b05c3876d56f62895e853a501ea58ea85f68d 40b98bc2b5b1152416ea8e9665ae1c6a3ce32ba0
- $ hg debugstablerange --rev 'head()'
- rev node index size depth obshash
- 4 069b05c3876d 0 3 3 a2b2331da650
- 3 e5ea8f9c7314 0 2 2 0aacc2f86e8f
- 4 069b05c3876d 2 1 3 901f118d4333
- 0 a9bdc8b26820 0 1 1 000000000000
- 3 e5ea8f9c7314 1 1 2 0aacc2f86e8f
+ $ hg debugobshashrange --subranges --rev 'head()'
+ rev node index size depth obshash
+ 4 069b05c3876d 0 3 3 a2b2331da650
+ 3 e5ea8f9c7314 0 2 2 0aacc2f86e8f
+ 4 069b05c3876d 2 1 3 901f118d4333
+ 0 a9bdc8b26820 0 1 1 000000000000
+ 3 e5ea8f9c7314 1 1 2 0aacc2f86e8f
$ cd ..
$ cd ..
--- a/tests/test-inhibit.t Tue Mar 14 14:47:20 2017 -0700
+++ b/tests/test-inhibit.t Fri Mar 31 15:44:10 2017 +0200
@@ -807,7 +807,7 @@
[255]
Visible commits can still be pushed
- $ hg push -r 71eb4f100663 $pwd/inhibit2
+ $ hg push -fr 71eb4f100663 $pwd/inhibit2
pushing to $TESTTMP/inhibit2
searching for changes
adding changesets
@@ -911,7 +911,7 @@
$ cd not-inhibit
$ hg book -d foo
$ hg pull
- pulling from $TESTTMP/inhibit
+ pulling from $TESTTMP/inhibit (glob)
searching for changes
no changes found
adding remote bookmark foo
--- a/tests/test-sharing.t Tue Mar 14 14:47:20 2017 -0700
+++ b/tests/test-sharing.t Fri Mar 31 15:44:10 2017 +0200
@@ -342,7 +342,7 @@
searching for changes
remote has heads on branch 'default' that are not known locally: 540ba8f317e6
abort: push creates new remote head cbdfbd5a5db2 with bookmark 'bug15'!
- (pull and merge or see "hg help push" for details about pushing new heads)
+ (pull and merge or see 'hg help push' for details about pushing new heads)
[255]
$ hg pull ../public
pulling from ../public
--- a/tests/test-stablerange.t Tue Mar 14 14:47:20 2017 -0700
+++ b/tests/test-stablerange.t Fri Mar 31 15:44:10 2017 +0200
@@ -16,114 +16,107 @@
$ hg init repo_linear
$ cd repo_linear
$ hg debugbuilddag '.+6'
- $ hg debugstablerange --rev 1
- rev node index size depth obshash
- 1 66f7d451a68b 0 2 2 000000000000
- 0 1ea73414a91b 0 1 1 000000000000
- 1 66f7d451a68b 1 1 2 000000000000
- $ hg debugstablerange --rev 1 > 1.range
+ $ hg debugstablerange --verify --verbose --subranges --rev 1
+ 66f7d451a68b-0 (1, 2, 2) [complete] - 1ea73414a91b-0 (0, 1, 1), 66f7d451a68b-1 (1, 2, 1)
+ 1ea73414a91b-0 (0, 1, 1) [leaf] -
+ 66f7d451a68b-1 (1, 2, 1) [leaf] -
+ $ hg debugstablerange --verify --verbose --subranges --rev 1 > 1.range
bigger subset reuse most of the previous one
- $ hg debugstablerange --rev 4
- rev node index size depth obshash
- 4 bebd167eb94d 0 5 5 000000000000
- 3 2dc09a01254d 0 4 4 000000000000
- 3 2dc09a01254d 2 2 4 000000000000
- 1 66f7d451a68b 0 2 2 000000000000
- 2 01241442b3c2 2 1 3 000000000000
- 0 1ea73414a91b 0 1 1 000000000000
- 3 2dc09a01254d 3 1 4 000000000000
- 1 66f7d451a68b 1 1 2 000000000000
- 4 bebd167eb94d 4 1 5 000000000000
- $ hg debugstablerange --rev 4 > 4.range
+ $ hg debugstablerange --verify --verbose --subranges --rev 4
+ bebd167eb94d-0 (4, 5, 5) [complete] - 2dc09a01254d-0 (3, 4, 4), bebd167eb94d-4 (4, 5, 1)
+ 2dc09a01254d-0 (3, 4, 4) [complete] - 66f7d451a68b-0 (1, 2, 2), 2dc09a01254d-2 (3, 4, 2)
+ 2dc09a01254d-2 (3, 4, 2) [complete] - 01241442b3c2-2 (2, 3, 1), 2dc09a01254d-3 (3, 4, 1)
+ 66f7d451a68b-0 (1, 2, 2) [complete] - 1ea73414a91b-0 (0, 1, 1), 66f7d451a68b-1 (1, 2, 1)
+ 01241442b3c2-2 (2, 3, 1) [leaf] -
+ 1ea73414a91b-0 (0, 1, 1) [leaf] -
+ 2dc09a01254d-3 (3, 4, 1) [leaf] -
+ 66f7d451a68b-1 (1, 2, 1) [leaf] -
+ bebd167eb94d-4 (4, 5, 1) [leaf] -
+ $ hg debugstablerange --verify --verbose --subranges --rev 4 > 4.range
$ diff -u 1.range 4.range
--- 1.range * (glob)
+++ 4.range * (glob)
- @@ -1,4 +1,10 @@
- rev node index size depth obshash
- + 4 bebd167eb94d 0 5 5 000000000000
- + 3 2dc09a01254d 0 4 4 000000000000
- + 3 2dc09a01254d 2 2 4 000000000000
- 1 66f7d451a68b 0 2 2 000000000000
- + 2 01241442b3c2 2 1 3 000000000000
- 0 1ea73414a91b 0 1 1 000000000000
- + 3 2dc09a01254d 3 1 4 000000000000
- 1 66f7d451a68b 1 1 2 000000000000
- + 4 bebd167eb94d 4 1 5 000000000000
+ @@ -1,3 +1,9 @@
+ +bebd167eb94d-0 (4, 5, 5) [complete] - 2dc09a01254d-0 (3, 4, 4), bebd167eb94d-4 (4, 5, 1)
+ +2dc09a01254d-0 (3, 4, 4) [complete] - 66f7d451a68b-0 (1, 2, 2), 2dc09a01254d-2 (3, 4, 2)
+ +2dc09a01254d-2 (3, 4, 2) [complete] - 01241442b3c2-2 (2, 3, 1), 2dc09a01254d-3 (3, 4, 1)
+ 66f7d451a68b-0 (1, 2, 2) [complete] - 1ea73414a91b-0 (0, 1, 1), 66f7d451a68b-1 (1, 2, 1)
+ +01241442b3c2-2 (2, 3, 1) [leaf] -
+ 1ea73414a91b-0 (0, 1, 1) [leaf] -
+ +2dc09a01254d-3 (3, 4, 1) [leaf] -
+ 66f7d451a68b-1 (1, 2, 1) [leaf] -
+ +bebd167eb94d-4 (4, 5, 1) [leaf] -
[1]
Using a range not ending on 2**N boundary
we fall back on 2**N as much as possible
- $ hg debugstablerange --rev 5
- rev node index size depth obshash
- 5 c8d03c1b5e94 0 6 6 000000000000
- 3 2dc09a01254d 0 4 4 000000000000
- 3 2dc09a01254d 2 2 4 000000000000
- 1 66f7d451a68b 0 2 2 000000000000
- 5 c8d03c1b5e94 4 2 6 000000000000
- 2 01241442b3c2 2 1 3 000000000000
- 0 1ea73414a91b 0 1 1 000000000000
- 3 2dc09a01254d 3 1 4 000000000000
- 1 66f7d451a68b 1 1 2 000000000000
- 4 bebd167eb94d 4 1 5 000000000000
- 5 c8d03c1b5e94 5 1 6 000000000000
- $ hg debugstablerange --rev 5 > 5.range
+ $ hg debugstablerange --verify --verbose --subranges --rev 5
+ c8d03c1b5e94-0 (5, 6, 6) [complete] - 2dc09a01254d-0 (3, 4, 4), c8d03c1b5e94-4 (5, 6, 2)
+ 2dc09a01254d-0 (3, 4, 4) [complete] - 66f7d451a68b-0 (1, 2, 2), 2dc09a01254d-2 (3, 4, 2)
+ 2dc09a01254d-2 (3, 4, 2) [complete] - 01241442b3c2-2 (2, 3, 1), 2dc09a01254d-3 (3, 4, 1)
+ 66f7d451a68b-0 (1, 2, 2) [complete] - 1ea73414a91b-0 (0, 1, 1), 66f7d451a68b-1 (1, 2, 1)
+ c8d03c1b5e94-4 (5, 6, 2) [complete] - bebd167eb94d-4 (4, 5, 1), c8d03c1b5e94-5 (5, 6, 1)
+ 01241442b3c2-2 (2, 3, 1) [leaf] -
+ 1ea73414a91b-0 (0, 1, 1) [leaf] -
+ 2dc09a01254d-3 (3, 4, 1) [leaf] -
+ 66f7d451a68b-1 (1, 2, 1) [leaf] -
+ bebd167eb94d-4 (4, 5, 1) [leaf] -
+ c8d03c1b5e94-5 (5, 6, 1) [leaf] -
+ $ hg debugstablerange --verify --verbose --subranges --rev 5 > 5.range
$ diff -u 4.range 5.range
--- 4.range * (glob)
+++ 5.range * (glob)
- @@ -1,10 +1,12 @@
- rev node index size depth obshash
- - 4 bebd167eb94d 0 5 5 000000000000
- + 5 c8d03c1b5e94 0 6 6 000000000000
- 3 2dc09a01254d 0 4 4 000000000000
- 3 2dc09a01254d 2 2 4 000000000000
- 1 66f7d451a68b 0 2 2 000000000000
- + 5 c8d03c1b5e94 4 2 6 000000000000
- 2 01241442b3c2 2 1 3 000000000000
- 0 1ea73414a91b 0 1 1 000000000000
- 3 2dc09a01254d 3 1 4 000000000000
- 1 66f7d451a68b 1 1 2 000000000000
- 4 bebd167eb94d 4 1 5 000000000000
- + 5 c8d03c1b5e94 5 1 6 000000000000
+ @@ -1,9 +1,11 @@
+ -bebd167eb94d-0 (4, 5, 5) [complete] - 2dc09a01254d-0 (3, 4, 4), bebd167eb94d-4 (4, 5, 1)
+ +c8d03c1b5e94-0 (5, 6, 6) [complete] - 2dc09a01254d-0 (3, 4, 4), c8d03c1b5e94-4 (5, 6, 2)
+ 2dc09a01254d-0 (3, 4, 4) [complete] - 66f7d451a68b-0 (1, 2, 2), 2dc09a01254d-2 (3, 4, 2)
+ 2dc09a01254d-2 (3, 4, 2) [complete] - 01241442b3c2-2 (2, 3, 1), 2dc09a01254d-3 (3, 4, 1)
+ 66f7d451a68b-0 (1, 2, 2) [complete] - 1ea73414a91b-0 (0, 1, 1), 66f7d451a68b-1 (1, 2, 1)
+ +c8d03c1b5e94-4 (5, 6, 2) [complete] - bebd167eb94d-4 (4, 5, 1), c8d03c1b5e94-5 (5, 6, 1)
+ 01241442b3c2-2 (2, 3, 1) [leaf] -
+ 1ea73414a91b-0 (0, 1, 1) [leaf] -
+ 2dc09a01254d-3 (3, 4, 1) [leaf] -
+ 66f7d451a68b-1 (1, 2, 1) [leaf] -
+ bebd167eb94d-4 (4, 5, 1) [leaf] -
+ +c8d03c1b5e94-5 (5, 6, 1) [leaf] -
[1]
Even two unperfect range overlap a lot
- $ hg debugstablerange --rev tip
- rev node index size depth obshash
- 6 f69452c5b1af 0 7 7 000000000000
- 3 2dc09a01254d 0 4 4 000000000000
- 6 f69452c5b1af 4 3 7 000000000000
- 3 2dc09a01254d 2 2 4 000000000000
- 1 66f7d451a68b 0 2 2 000000000000
- 5 c8d03c1b5e94 4 2 6 000000000000
- 2 01241442b3c2 2 1 3 000000000000
- 0 1ea73414a91b 0 1 1 000000000000
- 3 2dc09a01254d 3 1 4 000000000000
- 1 66f7d451a68b 1 1 2 000000000000
- 4 bebd167eb94d 4 1 5 000000000000
- 5 c8d03c1b5e94 5 1 6 000000000000
- 6 f69452c5b1af 6 1 7 000000000000
- $ hg debugstablerange --rev tip > tip.range
+ $ hg debugstablerange --verify --verbose --subranges --rev tip
+ f69452c5b1af-0 (6, 7, 7) [complete] - 2dc09a01254d-0 (3, 4, 4), f69452c5b1af-4 (6, 7, 3)
+ 2dc09a01254d-0 (3, 4, 4) [complete] - 66f7d451a68b-0 (1, 2, 2), 2dc09a01254d-2 (3, 4, 2)
+ f69452c5b1af-4 (6, 7, 3) [complete] - c8d03c1b5e94-4 (5, 6, 2), f69452c5b1af-6 (6, 7, 1)
+ 2dc09a01254d-2 (3, 4, 2) [complete] - 01241442b3c2-2 (2, 3, 1), 2dc09a01254d-3 (3, 4, 1)
+ 66f7d451a68b-0 (1, 2, 2) [complete] - 1ea73414a91b-0 (0, 1, 1), 66f7d451a68b-1 (1, 2, 1)
+ c8d03c1b5e94-4 (5, 6, 2) [complete] - bebd167eb94d-4 (4, 5, 1), c8d03c1b5e94-5 (5, 6, 1)
+ 01241442b3c2-2 (2, 3, 1) [leaf] -
+ 1ea73414a91b-0 (0, 1, 1) [leaf] -
+ 2dc09a01254d-3 (3, 4, 1) [leaf] -
+ 66f7d451a68b-1 (1, 2, 1) [leaf] -
+ bebd167eb94d-4 (4, 5, 1) [leaf] -
+ c8d03c1b5e94-5 (5, 6, 1) [leaf] -
+ f69452c5b1af-6 (6, 7, 1) [leaf] -
+ $ hg debugstablerange --verify --verbose --subranges --rev tip > tip.range
$ diff -u 5.range tip.range
--- 5.range * (glob)
+++ tip.range * (glob)
- @@ -1,6 +1,7 @@
- rev node index size depth obshash
- - 5 c8d03c1b5e94 0 6 6 000000000000
- + 6 f69452c5b1af 0 7 7 000000000000
- 3 2dc09a01254d 0 4 4 000000000000
- + 6 f69452c5b1af 4 3 7 000000000000
- 3 2dc09a01254d 2 2 4 000000000000
- 1 66f7d451a68b 0 2 2 000000000000
- 5 c8d03c1b5e94 4 2 6 000000000000
- @@ -10,3 +11,4 @@
- 1 66f7d451a68b 1 1 2 000000000000
- 4 bebd167eb94d 4 1 5 000000000000
- 5 c8d03c1b5e94 5 1 6 000000000000
- + 6 f69452c5b1af 6 1 7 000000000000
+ @@ -1,5 +1,6 @@
+ -c8d03c1b5e94-0 (5, 6, 6) [complete] - 2dc09a01254d-0 (3, 4, 4), c8d03c1b5e94-4 (5, 6, 2)
+ +f69452c5b1af-0 (6, 7, 7) [complete] - 2dc09a01254d-0 (3, 4, 4), f69452c5b1af-4 (6, 7, 3)
+ 2dc09a01254d-0 (3, 4, 4) [complete] - 66f7d451a68b-0 (1, 2, 2), 2dc09a01254d-2 (3, 4, 2)
+ +f69452c5b1af-4 (6, 7, 3) [complete] - c8d03c1b5e94-4 (5, 6, 2), f69452c5b1af-6 (6, 7, 1)
+ 2dc09a01254d-2 (3, 4, 2) [complete] - 01241442b3c2-2 (2, 3, 1), 2dc09a01254d-3 (3, 4, 1)
+ 66f7d451a68b-0 (1, 2, 2) [complete] - 1ea73414a91b-0 (0, 1, 1), 66f7d451a68b-1 (1, 2, 1)
+ c8d03c1b5e94-4 (5, 6, 2) [complete] - bebd167eb94d-4 (4, 5, 1), c8d03c1b5e94-5 (5, 6, 1)
+ @@ -9,3 +10,4 @@
+ 66f7d451a68b-1 (1, 2, 1) [leaf] -
+ bebd167eb94d-4 (4, 5, 1) [leaf] -
+ c8d03c1b5e94-5 (5, 6, 1) [leaf] -
+ +f69452c5b1af-6 (6, 7, 1) [leaf] -
[1]
$ cd ..
@@ -168,132 +161,123 @@
(left branch)
- $ hg debugstablerange --rev 'left~2'
- rev node index size depth obshash
- 1 66f7d451a68b 0 2 2 000000000000
- 0 1ea73414a91b 0 1 1 000000000000
- 1 66f7d451a68b 1 1 2 000000000000
- $ hg debugstablerange --rev 'left~2' > left-2.range
- $ hg debugstablerange --rev left
- rev node index size depth obshash
- 3 2dc09a01254d 0 4 4 000000000000
- 3 2dc09a01254d 2 2 4 000000000000
- 1 66f7d451a68b 0 2 2 000000000000
- 2 01241442b3c2 2 1 3 000000000000
- 0 1ea73414a91b 0 1 1 000000000000
- 3 2dc09a01254d 3 1 4 000000000000
- 1 66f7d451a68b 1 1 2 000000000000
- $ hg debugstablerange --rev 'left' > left.range
+ $ hg debugstablerange --verify --verbose --subranges --rev 'left~2'
+ 66f7d451a68b-0 (1, 2, 2) [complete] - 1ea73414a91b-0 (0, 1, 1), 66f7d451a68b-1 (1, 2, 1)
+ 1ea73414a91b-0 (0, 1, 1) [leaf] -
+ 66f7d451a68b-1 (1, 2, 1) [leaf] -
+ $ hg debugstablerange --verify --verbose --subranges --rev 'left~2' > left-2.range
+ $ hg debugstablerange --verify --verbose --subranges --rev left
+ 2dc09a01254d-0 (3, 4, 4) [complete] - 66f7d451a68b-0 (1, 2, 2), 2dc09a01254d-2 (3, 4, 2)
+ 2dc09a01254d-2 (3, 4, 2) [complete] - 01241442b3c2-2 (2, 3, 1), 2dc09a01254d-3 (3, 4, 1)
+ 66f7d451a68b-0 (1, 2, 2) [complete] - 1ea73414a91b-0 (0, 1, 1), 66f7d451a68b-1 (1, 2, 1)
+ 01241442b3c2-2 (2, 3, 1) [leaf] -
+ 1ea73414a91b-0 (0, 1, 1) [leaf] -
+ 2dc09a01254d-3 (3, 4, 1) [leaf] -
+ 66f7d451a68b-1 (1, 2, 1) [leaf] -
+ $ hg debugstablerange --verify --verbose --subranges --rev 'left' > left.range
$ diff -u left-2.range left.range
--- left-2.range * (glob)
+++ left.range * (glob)
- @@ -1,4 +1,8 @@
- rev node index size depth obshash
- + 3 2dc09a01254d 0 4 4 000000000000
- + 3 2dc09a01254d 2 2 4 000000000000
- 1 66f7d451a68b 0 2 2 000000000000
- + 2 01241442b3c2 2 1 3 000000000000
- 0 1ea73414a91b 0 1 1 000000000000
- + 3 2dc09a01254d 3 1 4 000000000000
- 1 66f7d451a68b 1 1 2 000000000000
+ @@ -1,3 +1,7 @@
+ +2dc09a01254d-0 (3, 4, 4) [complete] - 66f7d451a68b-0 (1, 2, 2), 2dc09a01254d-2 (3, 4, 2)
+ +2dc09a01254d-2 (3, 4, 2) [complete] - 01241442b3c2-2 (2, 3, 1), 2dc09a01254d-3 (3, 4, 1)
+ 66f7d451a68b-0 (1, 2, 2) [complete] - 1ea73414a91b-0 (0, 1, 1), 66f7d451a68b-1 (1, 2, 1)
+ +01241442b3c2-2 (2, 3, 1) [leaf] -
+ 1ea73414a91b-0 (0, 1, 1) [leaf] -
+ +2dc09a01254d-3 (3, 4, 1) [leaf] -
+ 66f7d451a68b-1 (1, 2, 1) [leaf] -
[1]
(right branch)
- $ hg debugstablerange --rev right~2
- rev node index size depth obshash
- 4 e7bd5218ca15 0 2 2 000000000000
- 0 1ea73414a91b 0 1 1 000000000000
- 4 e7bd5218ca15 1 1 2 000000000000
- $ hg debugstablerange --rev 'right~2' > right-2.range
- $ hg debugstablerange --rev right
- rev node index size depth obshash
- 6 a2f58e9c1e56 0 4 4 000000000000
- 6 a2f58e9c1e56 2 2 4 000000000000
- 4 e7bd5218ca15 0 2 2 000000000000
- 0 1ea73414a91b 0 1 1 000000000000
- 5 3a367db1fabc 2 1 3 000000000000
- 6 a2f58e9c1e56 3 1 4 000000000000
- 4 e7bd5218ca15 1 1 2 000000000000
- $ hg debugstablerange --rev 'right' > right.range
+ $ hg debugstablerange --verify --verbose --subranges --rev right~2
+ e7bd5218ca15-0 (4, 2, 2) [complete] - 1ea73414a91b-0 (0, 1, 1), e7bd5218ca15-1 (4, 2, 1)
+ 1ea73414a91b-0 (0, 1, 1) [leaf] -
+ e7bd5218ca15-1 (4, 2, 1) [leaf] -
+ $ hg debugstablerange --verify --verbose --subranges --rev 'right~2' > right-2.range
+ $ hg debugstablerange --verify --verbose --subranges --rev right
+ a2f58e9c1e56-0 (6, 4, 4) [complete] - e7bd5218ca15-0 (4, 2, 2), a2f58e9c1e56-2 (6, 4, 2)
+ a2f58e9c1e56-2 (6, 4, 2) [complete] - 3a367db1fabc-2 (5, 3, 1), a2f58e9c1e56-3 (6, 4, 1)
+ e7bd5218ca15-0 (4, 2, 2) [complete] - 1ea73414a91b-0 (0, 1, 1), e7bd5218ca15-1 (4, 2, 1)
+ 1ea73414a91b-0 (0, 1, 1) [leaf] -
+ 3a367db1fabc-2 (5, 3, 1) [leaf] -
+ a2f58e9c1e56-3 (6, 4, 1) [leaf] -
+ e7bd5218ca15-1 (4, 2, 1) [leaf] -
+ $ hg debugstablerange --verify --verbose --subranges --rev 'right' > right.range
$ diff -u right-2.range right.range
--- right-2.range * (glob)
+++ right.range * (glob)
- @@ -1,4 +1,8 @@
- rev node index size depth obshash
- + 6 a2f58e9c1e56 0 4 4 000000000000
- + 6 a2f58e9c1e56 2 2 4 000000000000
- 4 e7bd5218ca15 0 2 2 000000000000
- 0 1ea73414a91b 0 1 1 000000000000
- + 5 3a367db1fabc 2 1 3 000000000000
- + 6 a2f58e9c1e56 3 1 4 000000000000
- 4 e7bd5218ca15 1 1 2 000000000000
+ @@ -1,3 +1,7 @@
+ +a2f58e9c1e56-0 (6, 4, 4) [complete] - e7bd5218ca15-0 (4, 2, 2), a2f58e9c1e56-2 (6, 4, 2)
+ +a2f58e9c1e56-2 (6, 4, 2) [complete] - 3a367db1fabc-2 (5, 3, 1), a2f58e9c1e56-3 (6, 4, 1)
+ e7bd5218ca15-0 (4, 2, 2) [complete] - 1ea73414a91b-0 (0, 1, 1), e7bd5218ca15-1 (4, 2, 1)
+ 1ea73414a91b-0 (0, 1, 1) [leaf] -
+ +3a367db1fabc-2 (5, 3, 1) [leaf] -
+ +a2f58e9c1e56-3 (6, 4, 1) [leaf] -
+ e7bd5218ca15-1 (4, 2, 1) [leaf] -
[1]
The merge reuse as much of the slicing created for one of the branch
- $ hg debugstablerange --rev merge
- rev node index size depth obshash
- 7 5f18015f9110 0 8 8 000000000000
- 3 2dc09a01254d 0 4 4 000000000000
- 7 5f18015f9110 4 4 8 000000000000
- 3 2dc09a01254d 2 2 4 000000000000
- 5 3a367db1fabc 1 2 3 000000000000
- 7 5f18015f9110 6 2 8 000000000000
- 1 66f7d451a68b 0 2 2 000000000000
- 2 01241442b3c2 2 1 3 000000000000
- 0 1ea73414a91b 0 1 1 000000000000
- 3 2dc09a01254d 3 1 4 000000000000
- 5 3a367db1fabc 2 1 3 000000000000
- 7 5f18015f9110 7 1 8 000000000000
- 1 66f7d451a68b 1 1 2 000000000000
- 6 a2f58e9c1e56 3 1 4 000000000000
- 4 e7bd5218ca15 1 1 2 000000000000
- $ hg debugstablerange --rev 'merge' > merge.range
+ $ hg debugstablerange --verify --verbose --subranges --rev merge
+ 5f18015f9110-0 (7, 8, 8) [complete] - 2dc09a01254d-0 (3, 4, 4), 5f18015f9110-4 (7, 8, 4)
+ 2dc09a01254d-0 (3, 4, 4) [complete] - 66f7d451a68b-0 (1, 2, 2), 2dc09a01254d-2 (3, 4, 2)
+ 5f18015f9110-4 (7, 8, 4) [complete] - 3a367db1fabc-1 (5, 3, 2), 5f18015f9110-6 (7, 8, 2)
+ 2dc09a01254d-2 (3, 4, 2) [complete] - 01241442b3c2-2 (2, 3, 1), 2dc09a01254d-3 (3, 4, 1)
+ 3a367db1fabc-1 (5, 3, 2) [complete] - e7bd5218ca15-1 (4, 2, 1), 3a367db1fabc-2 (5, 3, 1)
+ 5f18015f9110-6 (7, 8, 2) [complete] - a2f58e9c1e56-3 (6, 4, 1), 5f18015f9110-7 (7, 8, 1)
+ 66f7d451a68b-0 (1, 2, 2) [complete] - 1ea73414a91b-0 (0, 1, 1), 66f7d451a68b-1 (1, 2, 1)
+ 01241442b3c2-2 (2, 3, 1) [leaf] -
+ 1ea73414a91b-0 (0, 1, 1) [leaf] -
+ 2dc09a01254d-3 (3, 4, 1) [leaf] -
+ 3a367db1fabc-2 (5, 3, 1) [leaf] -
+ 5f18015f9110-7 (7, 8, 1) [leaf] -
+ 66f7d451a68b-1 (1, 2, 1) [leaf] -
+ a2f58e9c1e56-3 (6, 4, 1) [leaf] -
+ e7bd5218ca15-1 (4, 2, 1) [leaf] -
+ $ hg debugstablerange --verify --verbose --subranges --rev 'merge' > merge.range
$ diff -u left.range merge.range
--- left.range * (glob)
+++ merge.range * (glob)
- @@ -1,8 +1,16 @@
- rev node index size depth obshash
- + 7 5f18015f9110 0 8 8 000000000000
- 3 2dc09a01254d 0 4 4 000000000000
- + 7 5f18015f9110 4 4 8 000000000000
- 3 2dc09a01254d 2 2 4 000000000000
- + 5 3a367db1fabc 1 2 3 000000000000
- + 7 5f18015f9110 6 2 8 000000000000
- 1 66f7d451a68b 0 2 2 000000000000
- 2 01241442b3c2 2 1 3 000000000000
- 0 1ea73414a91b 0 1 1 000000000000
- 3 2dc09a01254d 3 1 4 000000000000
- + 5 3a367db1fabc 2 1 3 000000000000
- + 7 5f18015f9110 7 1 8 000000000000
- 1 66f7d451a68b 1 1 2 000000000000
- + 6 a2f58e9c1e56 3 1 4 000000000000
- + 4 e7bd5218ca15 1 1 2 000000000000
+ @@ -1,7 +1,15 @@
+ +5f18015f9110-0 (7, 8, 8) [complete] - 2dc09a01254d-0 (3, 4, 4), 5f18015f9110-4 (7, 8, 4)
+ 2dc09a01254d-0 (3, 4, 4) [complete] - 66f7d451a68b-0 (1, 2, 2), 2dc09a01254d-2 (3, 4, 2)
+ +5f18015f9110-4 (7, 8, 4) [complete] - 3a367db1fabc-1 (5, 3, 2), 5f18015f9110-6 (7, 8, 2)
+ 2dc09a01254d-2 (3, 4, 2) [complete] - 01241442b3c2-2 (2, 3, 1), 2dc09a01254d-3 (3, 4, 1)
+ +3a367db1fabc-1 (5, 3, 2) [complete] - e7bd5218ca15-1 (4, 2, 1), 3a367db1fabc-2 (5, 3, 1)
+ +5f18015f9110-6 (7, 8, 2) [complete] - a2f58e9c1e56-3 (6, 4, 1), 5f18015f9110-7 (7, 8, 1)
+ 66f7d451a68b-0 (1, 2, 2) [complete] - 1ea73414a91b-0 (0, 1, 1), 66f7d451a68b-1 (1, 2, 1)
+ 01241442b3c2-2 (2, 3, 1) [leaf] -
+ 1ea73414a91b-0 (0, 1, 1) [leaf] -
+ 2dc09a01254d-3 (3, 4, 1) [leaf] -
+ +3a367db1fabc-2 (5, 3, 1) [leaf] -
+ +5f18015f9110-7 (7, 8, 1) [leaf] -
+ 66f7d451a68b-1 (1, 2, 1) [leaf] -
+ +a2f58e9c1e56-3 (6, 4, 1) [leaf] -
+ +e7bd5218ca15-1 (4, 2, 1) [leaf] -
[1]
$ diff -u right.range merge.range
--- right.range * (glob)
+++ merge.range * (glob)
- @@ -1,8 +1,16 @@
- rev node index size depth obshash
- - 6 a2f58e9c1e56 0 4 4 000000000000
- - 6 a2f58e9c1e56 2 2 4 000000000000
- - 4 e7bd5218ca15 0 2 2 000000000000
- + 7 5f18015f9110 0 8 8 000000000000
- + 3 2dc09a01254d 0 4 4 000000000000
- + 7 5f18015f9110 4 4 8 000000000000
- + 3 2dc09a01254d 2 2 4 000000000000
- + 5 3a367db1fabc 1 2 3 000000000000
- + 7 5f18015f9110 6 2 8 000000000000
- + 1 66f7d451a68b 0 2 2 000000000000
- + 2 01241442b3c2 2 1 3 000000000000
- 0 1ea73414a91b 0 1 1 000000000000
- + 3 2dc09a01254d 3 1 4 000000000000
- 5 3a367db1fabc 2 1 3 000000000000
- + 7 5f18015f9110 7 1 8 000000000000
- + 1 66f7d451a68b 1 1 2 000000000000
- 6 a2f58e9c1e56 3 1 4 000000000000
- 4 e7bd5218ca15 1 1 2 000000000000
+ @@ -1,7 +1,15 @@
+ -a2f58e9c1e56-0 (6, 4, 4) [complete] - e7bd5218ca15-0 (4, 2, 2), a2f58e9c1e56-2 (6, 4, 2)
+ -a2f58e9c1e56-2 (6, 4, 2) [complete] - 3a367db1fabc-2 (5, 3, 1), a2f58e9c1e56-3 (6, 4, 1)
+ -e7bd5218ca15-0 (4, 2, 2) [complete] - 1ea73414a91b-0 (0, 1, 1), e7bd5218ca15-1 (4, 2, 1)
+ +5f18015f9110-0 (7, 8, 8) [complete] - 2dc09a01254d-0 (3, 4, 4), 5f18015f9110-4 (7, 8, 4)
+ +2dc09a01254d-0 (3, 4, 4) [complete] - 66f7d451a68b-0 (1, 2, 2), 2dc09a01254d-2 (3, 4, 2)
+ +5f18015f9110-4 (7, 8, 4) [complete] - 3a367db1fabc-1 (5, 3, 2), 5f18015f9110-6 (7, 8, 2)
+ +2dc09a01254d-2 (3, 4, 2) [complete] - 01241442b3c2-2 (2, 3, 1), 2dc09a01254d-3 (3, 4, 1)
+ +3a367db1fabc-1 (5, 3, 2) [complete] - e7bd5218ca15-1 (4, 2, 1), 3a367db1fabc-2 (5, 3, 1)
+ +5f18015f9110-6 (7, 8, 2) [complete] - a2f58e9c1e56-3 (6, 4, 1), 5f18015f9110-7 (7, 8, 1)
+ +66f7d451a68b-0 (1, 2, 2) [complete] - 1ea73414a91b-0 (0, 1, 1), 66f7d451a68b-1 (1, 2, 1)
+ +01241442b3c2-2 (2, 3, 1) [leaf] -
+ 1ea73414a91b-0 (0, 1, 1) [leaf] -
+ +2dc09a01254d-3 (3, 4, 1) [leaf] -
+ 3a367db1fabc-2 (5, 3, 1) [leaf] -
+ +5f18015f9110-7 (7, 8, 1) [leaf] -
+ +66f7d451a68b-1 (1, 2, 1) [leaf] -
+ a2f58e9c1e56-3 (6, 4, 1) [leaf] -
+ e7bd5218ca15-1 (4, 2, 1) [leaf] -
[1]
$ cd ..
@@ -348,85 +332,79 @@
(left branch)
- $ hg debugstablerange --rev 'left~2'
- rev node index size depth obshash
- 2 01241442b3c2 0 3 3 000000000000
- 1 66f7d451a68b 0 2 2 000000000000
- 2 01241442b3c2 2 1 3 000000000000
- 0 1ea73414a91b 0 1 1 000000000000
- 1 66f7d451a68b 1 1 2 000000000000
- $ hg debugstablerange --rev 'left~2' > left-2.range
- $ hg debugstablerange --rev left
- rev node index size depth obshash
- 4 bebd167eb94d 0 5 5 000000000000
- 3 2dc09a01254d 0 4 4 000000000000
- 3 2dc09a01254d 2 2 4 000000000000
- 1 66f7d451a68b 0 2 2 000000000000
- 2 01241442b3c2 2 1 3 000000000000
- 0 1ea73414a91b 0 1 1 000000000000
- 3 2dc09a01254d 3 1 4 000000000000
- 1 66f7d451a68b 1 1 2 000000000000
- 4 bebd167eb94d 4 1 5 000000000000
- $ hg debugstablerange --rev 'left' > left.range
+ $ hg debugstablerange --verify --verbose --subranges --rev 'left~2'
+ 01241442b3c2-0 (2, 3, 3) [complete] - 66f7d451a68b-0 (1, 2, 2), 01241442b3c2-2 (2, 3, 1)
+ 66f7d451a68b-0 (1, 2, 2) [complete] - 1ea73414a91b-0 (0, 1, 1), 66f7d451a68b-1 (1, 2, 1)
+ 01241442b3c2-2 (2, 3, 1) [leaf] -
+ 1ea73414a91b-0 (0, 1, 1) [leaf] -
+ 66f7d451a68b-1 (1, 2, 1) [leaf] -
+ $ hg debugstablerange --verify --verbose --subranges --rev 'left~2' > left-2.range
+ $ hg debugstablerange --verify --verbose --subranges --rev left
+ bebd167eb94d-0 (4, 5, 5) [complete] - 2dc09a01254d-0 (3, 4, 4), bebd167eb94d-4 (4, 5, 1)
+ 2dc09a01254d-0 (3, 4, 4) [complete] - 66f7d451a68b-0 (1, 2, 2), 2dc09a01254d-2 (3, 4, 2)
+ 2dc09a01254d-2 (3, 4, 2) [complete] - 01241442b3c2-2 (2, 3, 1), 2dc09a01254d-3 (3, 4, 1)
+ 66f7d451a68b-0 (1, 2, 2) [complete] - 1ea73414a91b-0 (0, 1, 1), 66f7d451a68b-1 (1, 2, 1)
+ 01241442b3c2-2 (2, 3, 1) [leaf] -
+ 1ea73414a91b-0 (0, 1, 1) [leaf] -
+ 2dc09a01254d-3 (3, 4, 1) [leaf] -
+ 66f7d451a68b-1 (1, 2, 1) [leaf] -
+ bebd167eb94d-4 (4, 5, 1) [leaf] -
+ $ hg debugstablerange --verify --verbose --subranges --rev 'left' > left.range
$ diff -u left-2.range left.range
--- left-2.range * (glob)
+++ left.range * (glob)
- @@ -1,6 +1,10 @@
- rev node index size depth obshash
- - 2 01241442b3c2 0 3 3 000000000000
- + 4 bebd167eb94d 0 5 5 000000000000
- + 3 2dc09a01254d 0 4 4 000000000000
- + 3 2dc09a01254d 2 2 4 000000000000
- 1 66f7d451a68b 0 2 2 000000000000
- 2 01241442b3c2 2 1 3 000000000000
- 0 1ea73414a91b 0 1 1 000000000000
- + 3 2dc09a01254d 3 1 4 000000000000
- 1 66f7d451a68b 1 1 2 000000000000
- + 4 bebd167eb94d 4 1 5 000000000000
+ @@ -1,5 +1,9 @@
+ -01241442b3c2-0 (2, 3, 3) [complete] - 66f7d451a68b-0 (1, 2, 2), 01241442b3c2-2 (2, 3, 1)
+ +bebd167eb94d-0 (4, 5, 5) [complete] - 2dc09a01254d-0 (3, 4, 4), bebd167eb94d-4 (4, 5, 1)
+ +2dc09a01254d-0 (3, 4, 4) [complete] - 66f7d451a68b-0 (1, 2, 2), 2dc09a01254d-2 (3, 4, 2)
+ +2dc09a01254d-2 (3, 4, 2) [complete] - 01241442b3c2-2 (2, 3, 1), 2dc09a01254d-3 (3, 4, 1)
+ 66f7d451a68b-0 (1, 2, 2) [complete] - 1ea73414a91b-0 (0, 1, 1), 66f7d451a68b-1 (1, 2, 1)
+ 01241442b3c2-2 (2, 3, 1) [leaf] -
+ 1ea73414a91b-0 (0, 1, 1) [leaf] -
+ +2dc09a01254d-3 (3, 4, 1) [leaf] -
+ 66f7d451a68b-1 (1, 2, 1) [leaf] -
+ +bebd167eb94d-4 (4, 5, 1) [leaf] -
[1]
(right branch)
- $ hg debugstablerange --rev right~2
- rev node index size depth obshash
- 7 42b07e8da27d 0 4 4 000000000000
- 7 42b07e8da27d 2 2 4 000000000000
- 5 de561312eff4 0 2 2 000000000000
- 0 1ea73414a91b 0 1 1 000000000000
- 7 42b07e8da27d 3 1 4 000000000000
- 6 b9bc20507e0b 2 1 3 000000000000
- 5 de561312eff4 1 1 2 000000000000
- $ hg debugstablerange --rev 'right~2' > right-2.range
- $ hg debugstablerange --rev right
- rev node index size depth obshash
- 9 f4b7da68b467 0 6 6 000000000000
- 7 42b07e8da27d 0 4 4 000000000000
- 7 42b07e8da27d 2 2 4 000000000000
- 5 de561312eff4 0 2 2 000000000000
- 9 f4b7da68b467 4 2 6 000000000000
- 0 1ea73414a91b 0 1 1 000000000000
- 7 42b07e8da27d 3 1 4 000000000000
- 8 857477a9aebb 4 1 5 000000000000
- 6 b9bc20507e0b 2 1 3 000000000000
- 5 de561312eff4 1 1 2 000000000000
- 9 f4b7da68b467 5 1 6 000000000000
- $ hg debugstablerange --rev 'right' > right.range
+ $ hg debugstablerange --verify --verbose --subranges --rev right~2
+ 42b07e8da27d-0 (7, 4, 4) [complete] - de561312eff4-0 (5, 2, 2), 42b07e8da27d-2 (7, 4, 2)
+ 42b07e8da27d-2 (7, 4, 2) [complete] - b9bc20507e0b-2 (6, 3, 1), 42b07e8da27d-3 (7, 4, 1)
+ de561312eff4-0 (5, 2, 2) [complete] - 1ea73414a91b-0 (0, 1, 1), de561312eff4-1 (5, 2, 1)
+ 1ea73414a91b-0 (0, 1, 1) [leaf] -
+ 42b07e8da27d-3 (7, 4, 1) [leaf] -
+ b9bc20507e0b-2 (6, 3, 1) [leaf] -
+ de561312eff4-1 (5, 2, 1) [leaf] -
+ $ hg debugstablerange --verify --verbose --subranges --rev 'right~2' > right-2.range
+ $ hg debugstablerange --verify --verbose --subranges --rev right
+ f4b7da68b467-0 (9, 6, 6) [complete] - 42b07e8da27d-0 (7, 4, 4), f4b7da68b467-4 (9, 6, 2)
+ 42b07e8da27d-0 (7, 4, 4) [complete] - de561312eff4-0 (5, 2, 2), 42b07e8da27d-2 (7, 4, 2)
+ 42b07e8da27d-2 (7, 4, 2) [complete] - b9bc20507e0b-2 (6, 3, 1), 42b07e8da27d-3 (7, 4, 1)
+ de561312eff4-0 (5, 2, 2) [complete] - 1ea73414a91b-0 (0, 1, 1), de561312eff4-1 (5, 2, 1)
+ f4b7da68b467-4 (9, 6, 2) [complete] - 857477a9aebb-4 (8, 5, 1), f4b7da68b467-5 (9, 6, 1)
+ 1ea73414a91b-0 (0, 1, 1) [leaf] -
+ 42b07e8da27d-3 (7, 4, 1) [leaf] -
+ 857477a9aebb-4 (8, 5, 1) [leaf] -
+ b9bc20507e0b-2 (6, 3, 1) [leaf] -
+ de561312eff4-1 (5, 2, 1) [leaf] -
+ f4b7da68b467-5 (9, 6, 1) [leaf] -
+ $ hg debugstablerange --verify --verbose --subranges --rev 'right' > right.range
$ diff -u right-2.range right.range
--- right-2.range * (glob)
+++ right.range * (glob)
- @@ -1,8 +1,12 @@
- rev node index size depth obshash
- + 9 f4b7da68b467 0 6 6 000000000000
- 7 42b07e8da27d 0 4 4 000000000000
- 7 42b07e8da27d 2 2 4 000000000000
- 5 de561312eff4 0 2 2 000000000000
- + 9 f4b7da68b467 4 2 6 000000000000
- 0 1ea73414a91b 0 1 1 000000000000
- 7 42b07e8da27d 3 1 4 000000000000
- + 8 857477a9aebb 4 1 5 000000000000
- 6 b9bc20507e0b 2 1 3 000000000000
- 5 de561312eff4 1 1 2 000000000000
- + 9 f4b7da68b467 5 1 6 000000000000
+ @@ -1,7 +1,11 @@
+ +f4b7da68b467-0 (9, 6, 6) [complete] - 42b07e8da27d-0 (7, 4, 4), f4b7da68b467-4 (9, 6, 2)
+ 42b07e8da27d-0 (7, 4, 4) [complete] - de561312eff4-0 (5, 2, 2), 42b07e8da27d-2 (7, 4, 2)
+ 42b07e8da27d-2 (7, 4, 2) [complete] - b9bc20507e0b-2 (6, 3, 1), 42b07e8da27d-3 (7, 4, 1)
+ de561312eff4-0 (5, 2, 2) [complete] - 1ea73414a91b-0 (0, 1, 1), de561312eff4-1 (5, 2, 1)
+ +f4b7da68b467-4 (9, 6, 2) [complete] - 857477a9aebb-4 (8, 5, 1), f4b7da68b467-5 (9, 6, 1)
+ 1ea73414a91b-0 (0, 1, 1) [leaf] -
+ 42b07e8da27d-3 (7, 4, 1) [leaf] -
+ +857477a9aebb-4 (8, 5, 1) [leaf] -
+ b9bc20507e0b-2 (6, 3, 1) [leaf] -
+ de561312eff4-1 (5, 2, 1) [leaf] -
+ +f4b7da68b467-5 (9, 6, 1) [leaf] -
[1]
In this case, the bottom of the split will have multiple heads,
@@ -435,148 +413,143 @@
We are still able to reuse one of the branch however
- $ hg debugstablerange --rev merge
- rev node index size depth obshash
- 10 8aca7f8c9bd2 0 11 11 000000000000
- 4 bebd167eb94d 0 5 5 000000000000
- 3 2dc09a01254d 0 4 4 000000000000
- 7 42b07e8da27d 0 4 4 000000000000
- 10 8aca7f8c9bd2 8 3 11 000000000000
- 3 2dc09a01254d 2 2 4 000000000000
- 7 42b07e8da27d 2 2 4 000000000000
- 1 66f7d451a68b 0 2 2 000000000000
- 5 de561312eff4 0 2 2 000000000000
- 9 f4b7da68b467 4 2 6 000000000000
- 2 01241442b3c2 2 1 3 000000000000
- 0 1ea73414a91b 0 1 1 000000000000
- 3 2dc09a01254d 3 1 4 000000000000
- 7 42b07e8da27d 3 1 4 000000000000
- 1 66f7d451a68b 1 1 2 000000000000
- 8 857477a9aebb 4 1 5 000000000000
- 10 8aca7f8c9bd2 10 1 11 000000000000
- 6 b9bc20507e0b 2 1 3 000000000000
- 4 bebd167eb94d 4 1 5 000000000000
- 5 de561312eff4 1 1 2 000000000000
- 9 f4b7da68b467 5 1 6 000000000000
- $ hg debugstablerange --rev 'merge' > merge.range
+ $ hg debugstablerange --verify --verbose --subranges --rev merge
+ 8aca7f8c9bd2-0 (10, 11, 11) [complete] - bebd167eb94d-0 (4, 5, 5), 42b07e8da27d-0 (7, 4, 4), 8aca7f8c9bd2-8 (10, 11, 3)
+ bebd167eb94d-0 (4, 5, 5) [complete] - 2dc09a01254d-0 (3, 4, 4), bebd167eb94d-4 (4, 5, 1)
+ 2dc09a01254d-0 (3, 4, 4) [complete] - 66f7d451a68b-0 (1, 2, 2), 2dc09a01254d-2 (3, 4, 2)
+ 42b07e8da27d-0 (7, 4, 4) [complete] - de561312eff4-0 (5, 2, 2), 42b07e8da27d-2 (7, 4, 2)
+ 8aca7f8c9bd2-8 (10, 11, 3) [complete] - f4b7da68b467-4 (9, 6, 2), 8aca7f8c9bd2-10 (10, 11, 1)
+ 2dc09a01254d-2 (3, 4, 2) [complete] - 01241442b3c2-2 (2, 3, 1), 2dc09a01254d-3 (3, 4, 1)
+ 42b07e8da27d-2 (7, 4, 2) [complete] - b9bc20507e0b-2 (6, 3, 1), 42b07e8da27d-3 (7, 4, 1)
+ 66f7d451a68b-0 (1, 2, 2) [complete] - 1ea73414a91b-0 (0, 1, 1), 66f7d451a68b-1 (1, 2, 1)
+ de561312eff4-0 (5, 2, 2) [complete] - 1ea73414a91b-0 (0, 1, 1), de561312eff4-1 (5, 2, 1)
+ f4b7da68b467-4 (9, 6, 2) [complete] - 857477a9aebb-4 (8, 5, 1), f4b7da68b467-5 (9, 6, 1)
+ 01241442b3c2-2 (2, 3, 1) [leaf] -
+ 1ea73414a91b-0 (0, 1, 1) [leaf] -
+ 2dc09a01254d-3 (3, 4, 1) [leaf] -
+ 42b07e8da27d-3 (7, 4, 1) [leaf] -
+ 66f7d451a68b-1 (1, 2, 1) [leaf] -
+ 857477a9aebb-4 (8, 5, 1) [leaf] -
+ 8aca7f8c9bd2-10 (10, 11, 1) [leaf] -
+ b9bc20507e0b-2 (6, 3, 1) [leaf] -
+ bebd167eb94d-4 (4, 5, 1) [leaf] -
+ de561312eff4-1 (5, 2, 1) [leaf] -
+ f4b7da68b467-5 (9, 6, 1) [leaf] -
+ $ hg debugstablerange --verify --verbose --subranges --rev 'merge' > merge.range
$ diff -u left.range merge.range
--- left.range * (glob)
+++ merge.range * (glob)
- @@ -1,10 +1,22 @@
- rev node index size depth obshash
- + 10 8aca7f8c9bd2 0 11 11 000000000000
- 4 bebd167eb94d 0 5 5 000000000000
- 3 2dc09a01254d 0 4 4 000000000000
- + 7 42b07e8da27d 0 4 4 000000000000
- + 10 8aca7f8c9bd2 8 3 11 000000000000
- 3 2dc09a01254d 2 2 4 000000000000
- + 7 42b07e8da27d 2 2 4 000000000000
- 1 66f7d451a68b 0 2 2 000000000000
- + 5 de561312eff4 0 2 2 000000000000
- + 9 f4b7da68b467 4 2 6 000000000000
- 2 01241442b3c2 2 1 3 000000000000
- 0 1ea73414a91b 0 1 1 000000000000
- 3 2dc09a01254d 3 1 4 000000000000
- + 7 42b07e8da27d 3 1 4 000000000000
- 1 66f7d451a68b 1 1 2 000000000000
- + 8 857477a9aebb 4 1 5 000000000000
- + 10 8aca7f8c9bd2 10 1 11 000000000000
- + 6 b9bc20507e0b 2 1 3 000000000000
- 4 bebd167eb94d 4 1 5 000000000000
- + 5 de561312eff4 1 1 2 000000000000
- + 9 f4b7da68b467 5 1 6 000000000000
+ @@ -1,9 +1,21 @@
+ +8aca7f8c9bd2-0 (10, 11, 11) [complete] - bebd167eb94d-0 (4, 5, 5), 42b07e8da27d-0 (7, 4, 4), 8aca7f8c9bd2-8 (10, 11, 3)
+ bebd167eb94d-0 (4, 5, 5) [complete] - 2dc09a01254d-0 (3, 4, 4), bebd167eb94d-4 (4, 5, 1)
+ 2dc09a01254d-0 (3, 4, 4) [complete] - 66f7d451a68b-0 (1, 2, 2), 2dc09a01254d-2 (3, 4, 2)
+ +42b07e8da27d-0 (7, 4, 4) [complete] - de561312eff4-0 (5, 2, 2), 42b07e8da27d-2 (7, 4, 2)
+ +8aca7f8c9bd2-8 (10, 11, 3) [complete] - f4b7da68b467-4 (9, 6, 2), 8aca7f8c9bd2-10 (10, 11, 1)
+ 2dc09a01254d-2 (3, 4, 2) [complete] - 01241442b3c2-2 (2, 3, 1), 2dc09a01254d-3 (3, 4, 1)
+ +42b07e8da27d-2 (7, 4, 2) [complete] - b9bc20507e0b-2 (6, 3, 1), 42b07e8da27d-3 (7, 4, 1)
+ 66f7d451a68b-0 (1, 2, 2) [complete] - 1ea73414a91b-0 (0, 1, 1), 66f7d451a68b-1 (1, 2, 1)
+ +de561312eff4-0 (5, 2, 2) [complete] - 1ea73414a91b-0 (0, 1, 1), de561312eff4-1 (5, 2, 1)
+ +f4b7da68b467-4 (9, 6, 2) [complete] - 857477a9aebb-4 (8, 5, 1), f4b7da68b467-5 (9, 6, 1)
+ 01241442b3c2-2 (2, 3, 1) [leaf] -
+ 1ea73414a91b-0 (0, 1, 1) [leaf] -
+ 2dc09a01254d-3 (3, 4, 1) [leaf] -
+ +42b07e8da27d-3 (7, 4, 1) [leaf] -
+ 66f7d451a68b-1 (1, 2, 1) [leaf] -
+ +857477a9aebb-4 (8, 5, 1) [leaf] -
+ +8aca7f8c9bd2-10 (10, 11, 1) [leaf] -
+ +b9bc20507e0b-2 (6, 3, 1) [leaf] -
+ bebd167eb94d-4 (4, 5, 1) [leaf] -
+ +de561312eff4-1 (5, 2, 1) [leaf] -
+ +f4b7da68b467-5 (9, 6, 1) [leaf] -
[1]
$ diff -u right.range merge.range
--- right.range * (glob)
+++ merge.range * (glob)
- @@ -1,12 +1,22 @@
- rev node index size depth obshash
- - 9 f4b7da68b467 0 6 6 000000000000
- + 10 8aca7f8c9bd2 0 11 11 000000000000
- + 4 bebd167eb94d 0 5 5 000000000000
- + 3 2dc09a01254d 0 4 4 000000000000
- 7 42b07e8da27d 0 4 4 000000000000
- + 10 8aca7f8c9bd2 8 3 11 000000000000
- + 3 2dc09a01254d 2 2 4 000000000000
- 7 42b07e8da27d 2 2 4 000000000000
- + 1 66f7d451a68b 0 2 2 000000000000
- 5 de561312eff4 0 2 2 000000000000
- 9 f4b7da68b467 4 2 6 000000000000
- + 2 01241442b3c2 2 1 3 000000000000
- 0 1ea73414a91b 0 1 1 000000000000
- + 3 2dc09a01254d 3 1 4 000000000000
- 7 42b07e8da27d 3 1 4 000000000000
- + 1 66f7d451a68b 1 1 2 000000000000
- 8 857477a9aebb 4 1 5 000000000000
- + 10 8aca7f8c9bd2 10 1 11 000000000000
- 6 b9bc20507e0b 2 1 3 000000000000
- + 4 bebd167eb94d 4 1 5 000000000000
- 5 de561312eff4 1 1 2 000000000000
- 9 f4b7da68b467 5 1 6 000000000000
+ @@ -1,11 +1,21 @@
+ -f4b7da68b467-0 (9, 6, 6) [complete] - 42b07e8da27d-0 (7, 4, 4), f4b7da68b467-4 (9, 6, 2)
+ +8aca7f8c9bd2-0 (10, 11, 11) [complete] - bebd167eb94d-0 (4, 5, 5), 42b07e8da27d-0 (7, 4, 4), 8aca7f8c9bd2-8 (10, 11, 3)
+ +bebd167eb94d-0 (4, 5, 5) [complete] - 2dc09a01254d-0 (3, 4, 4), bebd167eb94d-4 (4, 5, 1)
+ +2dc09a01254d-0 (3, 4, 4) [complete] - 66f7d451a68b-0 (1, 2, 2), 2dc09a01254d-2 (3, 4, 2)
+ 42b07e8da27d-0 (7, 4, 4) [complete] - de561312eff4-0 (5, 2, 2), 42b07e8da27d-2 (7, 4, 2)
+ +8aca7f8c9bd2-8 (10, 11, 3) [complete] - f4b7da68b467-4 (9, 6, 2), 8aca7f8c9bd2-10 (10, 11, 1)
+ +2dc09a01254d-2 (3, 4, 2) [complete] - 01241442b3c2-2 (2, 3, 1), 2dc09a01254d-3 (3, 4, 1)
+ 42b07e8da27d-2 (7, 4, 2) [complete] - b9bc20507e0b-2 (6, 3, 1), 42b07e8da27d-3 (7, 4, 1)
+ +66f7d451a68b-0 (1, 2, 2) [complete] - 1ea73414a91b-0 (0, 1, 1), 66f7d451a68b-1 (1, 2, 1)
+ de561312eff4-0 (5, 2, 2) [complete] - 1ea73414a91b-0 (0, 1, 1), de561312eff4-1 (5, 2, 1)
+ f4b7da68b467-4 (9, 6, 2) [complete] - 857477a9aebb-4 (8, 5, 1), f4b7da68b467-5 (9, 6, 1)
+ +01241442b3c2-2 (2, 3, 1) [leaf] -
+ 1ea73414a91b-0 (0, 1, 1) [leaf] -
+ +2dc09a01254d-3 (3, 4, 1) [leaf] -
+ 42b07e8da27d-3 (7, 4, 1) [leaf] -
+ +66f7d451a68b-1 (1, 2, 1) [leaf] -
+ 857477a9aebb-4 (8, 5, 1) [leaf] -
+ +8aca7f8c9bd2-10 (10, 11, 1) [leaf] -
+ b9bc20507e0b-2 (6, 3, 1) [leaf] -
+ +bebd167eb94d-4 (4, 5, 1) [leaf] -
+ de561312eff4-1 (5, 2, 1) [leaf] -
+ f4b7da68b467-5 (9, 6, 1) [leaf] -
[1]
Range above the merge, reuse subrange from the merge
- $ hg debugstablerange --rev tip
- rev node index size depth obshash
- 12 e6b8d5b46647 0 13 13 000000000000
- 4 bebd167eb94d 0 5 5 000000000000
- 12 e6b8d5b46647 8 5 13 000000000000
- 3 2dc09a01254d 0 4 4 000000000000
- 7 42b07e8da27d 0 4 4 000000000000
- 11 485383494a89 8 4 12 000000000000
- 3 2dc09a01254d 2 2 4 000000000000
- 7 42b07e8da27d 2 2 4 000000000000
- 11 485383494a89 10 2 12 000000000000
- 1 66f7d451a68b 0 2 2 000000000000
- 5 de561312eff4 0 2 2 000000000000
- 9 f4b7da68b467 4 2 6 000000000000
- 2 01241442b3c2 2 1 3 000000000000
- 0 1ea73414a91b 0 1 1 000000000000
- 3 2dc09a01254d 3 1 4 000000000000
- 7 42b07e8da27d 3 1 4 000000000000
- 11 485383494a89 11 1 12 000000000000
- 1 66f7d451a68b 1 1 2 000000000000
- 8 857477a9aebb 4 1 5 000000000000
- 10 8aca7f8c9bd2 10 1 11 000000000000
- 6 b9bc20507e0b 2 1 3 000000000000
- 4 bebd167eb94d 4 1 5 000000000000
- 5 de561312eff4 1 1 2 000000000000
- 12 e6b8d5b46647 12 1 13 000000000000
- 9 f4b7da68b467 5 1 6 000000000000
- $ hg debugstablerange --rev 'tip' > tip.range
+ $ hg debugstablerange --verify --verbose --subranges --rev tip
+ e6b8d5b46647-0 (12, 13, 13) [complete] - bebd167eb94d-0 (4, 5, 5), 42b07e8da27d-0 (7, 4, 4), e6b8d5b46647-8 (12, 13, 5)
+ bebd167eb94d-0 (4, 5, 5) [complete] - 2dc09a01254d-0 (3, 4, 4), bebd167eb94d-4 (4, 5, 1)
+ e6b8d5b46647-8 (12, 13, 5) [complete] - 485383494a89-8 (11, 12, 4), e6b8d5b46647-12 (12, 13, 1)
+ 2dc09a01254d-0 (3, 4, 4) [complete] - 66f7d451a68b-0 (1, 2, 2), 2dc09a01254d-2 (3, 4, 2)
+ 42b07e8da27d-0 (7, 4, 4) [complete] - de561312eff4-0 (5, 2, 2), 42b07e8da27d-2 (7, 4, 2)
+ 485383494a89-8 (11, 12, 4) [complete] - f4b7da68b467-4 (9, 6, 2), 485383494a89-10 (11, 12, 2)
+ 2dc09a01254d-2 (3, 4, 2) [complete] - 01241442b3c2-2 (2, 3, 1), 2dc09a01254d-3 (3, 4, 1)
+ 42b07e8da27d-2 (7, 4, 2) [complete] - b9bc20507e0b-2 (6, 3, 1), 42b07e8da27d-3 (7, 4, 1)
+ 485383494a89-10 (11, 12, 2) [complete] - 8aca7f8c9bd2-10 (10, 11, 1), 485383494a89-11 (11, 12, 1)
+ 66f7d451a68b-0 (1, 2, 2) [complete] - 1ea73414a91b-0 (0, 1, 1), 66f7d451a68b-1 (1, 2, 1)
+ de561312eff4-0 (5, 2, 2) [complete] - 1ea73414a91b-0 (0, 1, 1), de561312eff4-1 (5, 2, 1)
+ f4b7da68b467-4 (9, 6, 2) [complete] - 857477a9aebb-4 (8, 5, 1), f4b7da68b467-5 (9, 6, 1)
+ 01241442b3c2-2 (2, 3, 1) [leaf] -
+ 1ea73414a91b-0 (0, 1, 1) [leaf] -
+ 2dc09a01254d-3 (3, 4, 1) [leaf] -
+ 42b07e8da27d-3 (7, 4, 1) [leaf] -
+ 485383494a89-11 (11, 12, 1) [leaf] -
+ 66f7d451a68b-1 (1, 2, 1) [leaf] -
+ 857477a9aebb-4 (8, 5, 1) [leaf] -
+ 8aca7f8c9bd2-10 (10, 11, 1) [leaf] -
+ b9bc20507e0b-2 (6, 3, 1) [leaf] -
+ bebd167eb94d-4 (4, 5, 1) [leaf] -
+ de561312eff4-1 (5, 2, 1) [leaf] -
+ e6b8d5b46647-12 (12, 13, 1) [leaf] -
+ f4b7da68b467-5 (9, 6, 1) [leaf] -
+ $ hg debugstablerange --verify --verbose --subranges --rev 'tip' > tip.range
$ diff -u merge.range tip.range
--- merge.range * (glob)
+++ tip.range * (glob)
- @@ -1,11 +1,13 @@
- rev node index size depth obshash
- - 10 8aca7f8c9bd2 0 11 11 000000000000
- + 12 e6b8d5b46647 0 13 13 000000000000
- 4 bebd167eb94d 0 5 5 000000000000
- + 12 e6b8d5b46647 8 5 13 000000000000
- 3 2dc09a01254d 0 4 4 000000000000
- 7 42b07e8da27d 0 4 4 000000000000
- - 10 8aca7f8c9bd2 8 3 11 000000000000
- + 11 485383494a89 8 4 12 000000000000
- 3 2dc09a01254d 2 2 4 000000000000
- 7 42b07e8da27d 2 2 4 000000000000
- + 11 485383494a89 10 2 12 000000000000
- 1 66f7d451a68b 0 2 2 000000000000
- 5 de561312eff4 0 2 2 000000000000
- 9 f4b7da68b467 4 2 6 000000000000
- @@ -13,10 +15,12 @@
- 0 1ea73414a91b 0 1 1 000000000000
- 3 2dc09a01254d 3 1 4 000000000000
- 7 42b07e8da27d 3 1 4 000000000000
- + 11 485383494a89 11 1 12 000000000000
- 1 66f7d451a68b 1 1 2 000000000000
- 8 857477a9aebb 4 1 5 000000000000
- 10 8aca7f8c9bd2 10 1 11 000000000000
- 6 b9bc20507e0b 2 1 3 000000000000
- 4 bebd167eb94d 4 1 5 000000000000
- 5 de561312eff4 1 1 2 000000000000
- + 12 e6b8d5b46647 12 1 13 000000000000
- 9 f4b7da68b467 5 1 6 000000000000
+ @@ -1,10 +1,12 @@
+ -8aca7f8c9bd2-0 (10, 11, 11) [complete] - bebd167eb94d-0 (4, 5, 5), 42b07e8da27d-0 (7, 4, 4), 8aca7f8c9bd2-8 (10, 11, 3)
+ +e6b8d5b46647-0 (12, 13, 13) [complete] - bebd167eb94d-0 (4, 5, 5), 42b07e8da27d-0 (7, 4, 4), e6b8d5b46647-8 (12, 13, 5)
+ bebd167eb94d-0 (4, 5, 5) [complete] - 2dc09a01254d-0 (3, 4, 4), bebd167eb94d-4 (4, 5, 1)
+ +e6b8d5b46647-8 (12, 13, 5) [complete] - 485383494a89-8 (11, 12, 4), e6b8d5b46647-12 (12, 13, 1)
+ 2dc09a01254d-0 (3, 4, 4) [complete] - 66f7d451a68b-0 (1, 2, 2), 2dc09a01254d-2 (3, 4, 2)
+ 42b07e8da27d-0 (7, 4, 4) [complete] - de561312eff4-0 (5, 2, 2), 42b07e8da27d-2 (7, 4, 2)
+ -8aca7f8c9bd2-8 (10, 11, 3) [complete] - f4b7da68b467-4 (9, 6, 2), 8aca7f8c9bd2-10 (10, 11, 1)
+ +485383494a89-8 (11, 12, 4) [complete] - f4b7da68b467-4 (9, 6, 2), 485383494a89-10 (11, 12, 2)
+ 2dc09a01254d-2 (3, 4, 2) [complete] - 01241442b3c2-2 (2, 3, 1), 2dc09a01254d-3 (3, 4, 1)
+ 42b07e8da27d-2 (7, 4, 2) [complete] - b9bc20507e0b-2 (6, 3, 1), 42b07e8da27d-3 (7, 4, 1)
+ +485383494a89-10 (11, 12, 2) [complete] - 8aca7f8c9bd2-10 (10, 11, 1), 485383494a89-11 (11, 12, 1)
+ 66f7d451a68b-0 (1, 2, 2) [complete] - 1ea73414a91b-0 (0, 1, 1), 66f7d451a68b-1 (1, 2, 1)
+ de561312eff4-0 (5, 2, 2) [complete] - 1ea73414a91b-0 (0, 1, 1), de561312eff4-1 (5, 2, 1)
+ f4b7da68b467-4 (9, 6, 2) [complete] - 857477a9aebb-4 (8, 5, 1), f4b7da68b467-5 (9, 6, 1)
+ @@ -12,10 +14,12 @@
+ 1ea73414a91b-0 (0, 1, 1) [leaf] -
+ 2dc09a01254d-3 (3, 4, 1) [leaf] -
+ 42b07e8da27d-3 (7, 4, 1) [leaf] -
+ +485383494a89-11 (11, 12, 1) [leaf] -
+ 66f7d451a68b-1 (1, 2, 1) [leaf] -
+ 857477a9aebb-4 (8, 5, 1) [leaf] -
+ 8aca7f8c9bd2-10 (10, 11, 1) [leaf] -
+ b9bc20507e0b-2 (6, 3, 1) [leaf] -
+ bebd167eb94d-4 (4, 5, 1) [leaf] -
+ de561312eff4-1 (5, 2, 1) [leaf] -
+ +e6b8d5b46647-12 (12, 13, 1) [leaf] -
+ f4b7da68b467-5 (9, 6, 1) [leaf] -
[1]
$ cd ..
@@ -632,41 +605,73 @@
|/
o 0 1ea73414a91b r0
- $ hg debugstablerange --rev 'head()'
- rev node index size depth obshash
- 15 1d8d22637c2d 0 8 8 000000000000
- 9 dcbb326fdec2 0 7 7 000000000000
- 10 ff43616e5d0f 0 7 7 000000000000
- 13 b4594d867745 0 6 6 000000000000
- 12 e46a4836065c 0 6 6 000000000000
- 6 2702dd0c91e7 0 5 5 000000000000
- 15 1d8d22637c2d 4 4 8 000000000000
- 3 2b6d669947cd 0 4 4 000000000000
- 5 f0f3ef9a6cd5 0 4 4 000000000000
- 9 dcbb326fdec2 4 3 7 000000000000
- 10 ff43616e5d0f 4 3 7 000000000000
- 15 1d8d22637c2d 6 2 8 000000000000
- 3 2b6d669947cd 2 2 4 000000000000
- 1 66f7d451a68b 0 2 2 000000000000
- 13 b4594d867745 4 2 6 000000000000
- 8 d62d843c9a01 4 2 6 000000000000
- 12 e46a4836065c 4 2 6 000000000000
- 5 f0f3ef9a6cd5 2 2 4 000000000000
- 2 fa942426a6fd 0 2 2 000000000000
- 15 1d8d22637c2d 7 1 8 000000000000
- 0 1ea73414a91b 0 1 1 000000000000
- 6 2702dd0c91e7 4 1 5 000000000000
- 3 2b6d669947cd 3 1 4 000000000000
- 14 43227190fef8 4 1 5 000000000000
- 4 4c748ffd1a46 2 1 3 000000000000
- 1 66f7d451a68b 1 1 2 000000000000
- 13 b4594d867745 5 1 6 000000000000
- 11 bab5d5bf48bd 4 1 5 000000000000
- 8 d62d843c9a01 5 1 6 000000000000
- 9 dcbb326fdec2 6 1 7 000000000000
- 12 e46a4836065c 5 1 6 000000000000
- 7 e7d9710d9fc6 4 1 5 000000000000
- 5 f0f3ef9a6cd5 3 1 4 000000000000
- 2 fa942426a6fd 1 1 2 000000000000
- 10 ff43616e5d0f 6 1 7 000000000000
+ $ hg debugstablerange --verify --verbose --subranges --rev 'head()'
+ 1d8d22637c2d-0 (15, 8, 8) [complete] - 2b6d669947cd-0 (3, 4, 4), 1d8d22637c2d-4 (15, 8, 4)
+ dcbb326fdec2-0 (9, 7, 7) [complete] - 2b6d669947cd-0 (3, 4, 4), dcbb326fdec2-4 (9, 7, 3)
+ ff43616e5d0f-0 (10, 7, 7) [complete] - 2b6d669947cd-0 (3, 4, 4), ff43616e5d0f-4 (10, 7, 3)
+ b4594d867745-0 (13, 6, 6) [complete] - 2b6d669947cd-0 (3, 4, 4), b4594d867745-4 (13, 6, 2)
+ e46a4836065c-0 (12, 6, 6) [complete] - 2b6d669947cd-0 (3, 4, 4), e46a4836065c-4 (12, 6, 2)
+ 2702dd0c91e7-0 (6, 5, 5) [complete] - f0f3ef9a6cd5-0 (5, 4, 4), 2702dd0c91e7-4 (6, 5, 1)
+ 1d8d22637c2d-4 (15, 8, 4) [complete] - 4c748ffd1a46-2 (4, 3, 1), 43227190fef8-4 (14, 5, 1), 1d8d22637c2d-6 (15, 8, 2)
+ 2b6d669947cd-0 (3, 4, 4) [complete] - 66f7d451a68b-0 (1, 2, 2), 2b6d669947cd-2 (3, 4, 2)
+ f0f3ef9a6cd5-0 (5, 4, 4) [complete] - fa942426a6fd-0 (2, 2, 2), f0f3ef9a6cd5-2 (5, 4, 2)
+ dcbb326fdec2-4 (9, 7, 3) [complete] - d62d843c9a01-4 (8, 6, 2), dcbb326fdec2-6 (9, 7, 1)
+ ff43616e5d0f-4 (10, 7, 3) [complete] - d62d843c9a01-4 (8, 6, 2), ff43616e5d0f-6 (10, 7, 1)
+ 1d8d22637c2d-6 (15, 8, 2) [complete] - f0f3ef9a6cd5-3 (5, 4, 1), 1d8d22637c2d-7 (15, 8, 1)
+ 2b6d669947cd-2 (3, 4, 2) [complete] - fa942426a6fd-1 (2, 2, 1), 2b6d669947cd-3 (3, 4, 1)
+ 66f7d451a68b-0 (1, 2, 2) [complete] - 1ea73414a91b-0 (0, 1, 1), 66f7d451a68b-1 (1, 2, 1)
+ b4594d867745-4 (13, 6, 2) [complete] - bab5d5bf48bd-4 (11, 5, 1), b4594d867745-5 (13, 6, 1)
+ d62d843c9a01-4 (8, 6, 2) [complete] - e7d9710d9fc6-4 (7, 5, 1), d62d843c9a01-5 (8, 6, 1)
+ e46a4836065c-4 (12, 6, 2) [complete] - bab5d5bf48bd-4 (11, 5, 1), e46a4836065c-5 (12, 6, 1)
+ f0f3ef9a6cd5-2 (5, 4, 2) [complete] - 4c748ffd1a46-2 (4, 3, 1), f0f3ef9a6cd5-3 (5, 4, 1)
+ fa942426a6fd-0 (2, 2, 2) [complete] - 1ea73414a91b-0 (0, 1, 1), fa942426a6fd-1 (2, 2, 1)
+ 1d8d22637c2d-7 (15, 8, 1) [leaf] -
+ 1ea73414a91b-0 (0, 1, 1) [leaf] -
+ 2702dd0c91e7-4 (6, 5, 1) [leaf] -
+ 2b6d669947cd-3 (3, 4, 1) [leaf] -
+ 43227190fef8-4 (14, 5, 1) [leaf] -
+ 4c748ffd1a46-2 (4, 3, 1) [leaf] -
+ 66f7d451a68b-1 (1, 2, 1) [leaf] -
+ b4594d867745-5 (13, 6, 1) [leaf] -
+ bab5d5bf48bd-4 (11, 5, 1) [leaf] -
+ d62d843c9a01-5 (8, 6, 1) [leaf] -
+ dcbb326fdec2-6 (9, 7, 1) [leaf] -
+ e46a4836065c-5 (12, 6, 1) [leaf] -
+ e7d9710d9fc6-4 (7, 5, 1) [leaf] -
+ f0f3ef9a6cd5-3 (5, 4, 1) [leaf] -
+ fa942426a6fd-1 (2, 2, 1) [leaf] -
+ ff43616e5d0f-6 (10, 7, 1) [leaf] -
$ cd ..
+
+Tests range where a toprange is rooted on a merge
+=================================================
+
+ $ hg init slice_on_merge
+ $ cd slice_on_merge
+ $ hg debugbuilddag '
+ > ..:a # 2 nodes, tagged "a"
+ > <2..:b # another branch with two node based on 0, tagged b
+ > *a/b:m # merge -1 and -2 (1, 2), tagged "m"
+ > '
+ $ hg log -G
+ o 4 f37e476fba9a r4 m tip
+ |\
+ | o 3 36315563e2fa r3 b
+ | |
+ | o 2 fa942426a6fd r2
+ | |
+ o | 1 66f7d451a68b r1 a
+ |/
+ o 0 1ea73414a91b r0
+
+ $ hg debugstablerange --verify --verbose --subranges --rev 'head()'
+ f37e476fba9a-0 (4, 5, 5) [complete] - 66f7d451a68b-0 (1, 2, 2), 36315563e2fa-0 (3, 3, 3), f37e476fba9a-4 (4, 5, 1)
+ 36315563e2fa-0 (3, 3, 3) [complete] - fa942426a6fd-0 (2, 2, 2), 36315563e2fa-2 (3, 3, 1)
+ 66f7d451a68b-0 (1, 2, 2) [complete] - 1ea73414a91b-0 (0, 1, 1), 66f7d451a68b-1 (1, 2, 1)
+ fa942426a6fd-0 (2, 2, 2) [complete] - 1ea73414a91b-0 (0, 1, 1), fa942426a6fd-1 (2, 2, 1)
+ 1ea73414a91b-0 (0, 1, 1) [leaf] -
+ 36315563e2fa-2 (3, 3, 1) [leaf] -
+ 66f7d451a68b-1 (1, 2, 1) [leaf] -
+ f37e476fba9a-4 (4, 5, 1) [leaf] -
+ fa942426a6fd-1 (2, 2, 1) [leaf] -
+
--- a/tests/test-stablesort.t Tue Mar 14 14:47:20 2017 -0700
+++ b/tests/test-stablesort.t Fri Mar 31 15:44:10 2017 +0200
@@ -138,7 +138,7 @@
updating to branch default
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg -R repo_B pull --rev 13
- pulling from $TESTTMP/repo_A
+ pulling from $TESTTMP/repo_A (glob)
searching for changes
adding changesets
adding manifests
@@ -146,7 +146,7 @@
added 4 changesets with 0 changes to 0 files (+1 heads)
(run 'hg heads' to see heads, 'hg merge' to merge)
$ hg -R repo_B pull --rev 14
- pulling from $TESTTMP/repo_A
+ pulling from $TESTTMP/repo_A (glob)
searching for changes
adding changesets
adding manifests
@@ -154,7 +154,7 @@
added 1 changesets with 0 changes to 0 files (+1 heads)
(run 'hg heads .' to see heads, 'hg merge' to merge)
$ hg -R repo_B pull
- pulling from $TESTTMP/repo_A
+ pulling from $TESTTMP/repo_A (glob)
searching for changes
adding changesets
adding manifests
@@ -204,7 +204,7 @@
updating to branch default
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg -R repo_C pull --rev 12
- pulling from $TESTTMP/repo_A
+ pulling from $TESTTMP/repo_A (glob)
searching for changes
adding changesets
adding manifests
@@ -212,7 +212,7 @@
added 2 changesets with 0 changes to 0 files (+1 heads)
(run 'hg heads' to see heads, 'hg merge' to merge)
$ hg -R repo_C pull --rev 15
- pulling from $TESTTMP/repo_A
+ pulling from $TESTTMP/repo_A (glob)
searching for changes
adding changesets
adding manifests
@@ -220,7 +220,7 @@
added 4 changesets with 0 changes to 0 files (+1 heads)
(run 'hg heads .' to see heads, 'hg merge' to merge)
$ hg -R repo_C pull
- pulling from $TESTTMP/repo_A
+ pulling from $TESTTMP/repo_A (glob)
searching for changes
adding changesets
adding manifests
@@ -270,7 +270,7 @@
updating to branch default
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg -R repo_D pull --rev 10
- pulling from $TESTTMP/repo_A
+ pulling from $TESTTMP/repo_A (glob)
searching for changes
adding changesets
adding manifests
@@ -278,7 +278,7 @@
added 5 changesets with 0 changes to 0 files
(run 'hg update' to get a working copy)
$ hg -R repo_D pull --rev 15
- pulling from $TESTTMP/repo_A
+ pulling from $TESTTMP/repo_A (glob)
searching for changes
adding changesets
adding manifests
@@ -286,7 +286,7 @@
added 4 changesets with 0 changes to 0 files (+1 heads)
(run 'hg heads' to see heads, 'hg merge' to merge)
$ hg -R repo_D pull
- pulling from $TESTTMP/repo_A
+ pulling from $TESTTMP/repo_A (glob)
searching for changes
adding changesets
adding manifests
@@ -404,7 +404,7 @@
updating to branch default
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg -R repo_E pull --rev e7d9710d9fc6
- pulling from $TESTTMP/repo_A
+ pulling from $TESTTMP/repo_A (glob)
searching for changes
adding changesets
adding manifests
@@ -420,7 +420,7 @@
updating to branch default
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg -R repo_F pull --rev d62d843c9a01
- pulling from $TESTTMP/repo_A
+ pulling from $TESTTMP/repo_A (glob)
searching for changes
adding changesets
adding manifests
@@ -436,7 +436,7 @@
updating to branch default
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg -R repo_G pull --rev 43227190fef8
- pulling from $TESTTMP/repo_A
+ pulling from $TESTTMP/repo_A (glob)
searching for changes
adding changesets
adding manifests
@@ -444,7 +444,7 @@
added 1 changesets with 0 changes to 0 files (+1 heads)
(run 'hg heads' to see heads, 'hg merge' to merge)
$ hg -R repo_G pull --rev 2702dd0c91e7
- pulling from $TESTTMP/repo_A
+ pulling from $TESTTMP/repo_A (glob)
searching for changes
adding changesets
adding manifests
--- a/tests/test-topic-dest.t Tue Mar 14 14:47:20 2017 -0700
+++ b/tests/test-topic-dest.t Fri Mar 31 15:44:10 2017 +0200
@@ -276,7 +276,7 @@
$ hg add other
$ hg ci -m 'c_other'
$ hg pull -r default --rebase
- pulling from $TESTTMP/jungle
+ pulling from $TESTTMP/jungle (glob)
searching for changes
adding changesets
adding manifests
--- a/tests/test-topic-push.t Tue Mar 14 14:47:20 2017 -0700
+++ b/tests/test-topic-push.t Fri Mar 31 15:44:10 2017 +0200
@@ -32,12 +32,12 @@
$ hg add aaa
$ hg commit -m 'CA'
$ hg outgoing -G
- comparing with $TESTTMP/main
+ comparing with $TESTTMP/main (glob)
searching for changes
@ 0 default draft CA
$ hg push
- pushing to $TESTTMP/main
+ pushing to $TESTTMP/main (glob)
searching for changes
adding changesets
adding manifests
@@ -56,25 +56,25 @@
$ hg commit -m 'CC'
created new head
$ hg outgoing -G
- comparing with $TESTTMP/main
+ comparing with $TESTTMP/main (glob)
searching for changes
@ 2 default draft CC
o 1 default draft CB
$ hg push
- pushing to $TESTTMP/main
+ pushing to $TESTTMP/main (glob)
searching for changes
abort: push creates new remote head 9fe81b7f425d!
(merge or see "hg help push" for details about pushing new heads)
[255]
$ hg outgoing -r 'desc(CB)' -G
- comparing with $TESTTMP/main
+ comparing with $TESTTMP/main (glob)
searching for changes
o 1 default draft CB
$ hg push -r 'desc(CB)'
- pushing to $TESTTMP/main
+ pushing to $TESTTMP/main (glob)
searching for changes
adding changesets
adding manifests
@@ -88,18 +88,18 @@
(branches are permanent and global, did you want a bookmark?)
$ hg commit --amend
$ hg outgoing -G
- comparing with $TESTTMP/main
+ comparing with $TESTTMP/main (glob)
searching for changes
@ 4 mountain draft CC
$ hg push
- pushing to $TESTTMP/main
+ pushing to $TESTTMP/main (glob)
searching for changes
abort: push creates new remote branches: mountain!
(use 'hg push --new-branch' to create new remote branches)
[255]
$ hg push --new-branch
- pushing to $TESTTMP/main
+ pushing to $TESTTMP/main (glob)
searching for changes
adding changesets
adding manifests
@@ -110,7 +110,7 @@
Including on non-publishing
$ hg push --new-branch draft
- pushing to $TESTTMP/draft
+ pushing to $TESTTMP/draft (glob)
searching for changes
adding changesets
adding manifests
@@ -143,7 +143,7 @@
Pushing a new topic to a non publishing server should not be seen as a new head
$ hg push draft
- pushing to $TESTTMP/draft
+ pushing to $TESTTMP/draft (glob)
searching for changes
adding changesets
adding manifests
@@ -162,7 +162,7 @@
Pushing a new topic to a publishing server should be seen as a new head
$ hg push
- pushing to $TESTTMP/main
+ pushing to $TESTTMP/main (glob)
searching for changes
abort: push creates new remote head 67f579af159d!
(merge or see "hg help push" for details about pushing new heads)
@@ -289,7 +289,7 @@
$ hg push draft
- pushing to $TESTTMP/draft
+ pushing to $TESTTMP/draft (glob)
searching for changes
abort: push creates new remote head f0bc62a661be on branch 'default:babar'!
(merge or see "hg help push" for details about pushing new heads)
@@ -333,7 +333,7 @@
Reject when pushing to draft
$ hg push draft -r .
- pushing to $TESTTMP/draft
+ pushing to $TESTTMP/draft (glob)
searching for changes
abort: push creates new remote head 4937c4cad39e!
(merge or see "hg help push" for details about pushing new heads)
@@ -343,7 +343,7 @@
Reject when pushing to publishing
$ hg push -r .
- pushing to $TESTTMP/main
+ pushing to $TESTTMP/main (glob)
searching for changes
adding changesets
adding manifests
--- a/tests/test-topic-tutorial.t Tue Mar 14 14:47:20 2017 -0700
+++ b/tests/test-topic-tutorial.t Fri Mar 31 15:44:10 2017 +0200
@@ -193,7 +193,7 @@
Topic will also affect rebase and merge destination. Let's pull the latest update from the main server::
$ hg pull
- pulling from $TESTTMP/server
+ pulling from $TESTTMP/server (glob)
searching for changes
adding changesets
adding manifests
@@ -276,7 +276,7 @@
$ hg topic
food
$ hg push
- pushing to $TESTTMP/server
+ pushing to $TESTTMP/server (glob)
searching for changes
adding changesets
adding manifests
@@ -392,7 +392,7 @@
Lets see what other people did in the mean time::
$ hg pull
- pulling from $TESTTMP/server
+ pulling from $TESTTMP/server (glob)
searching for changes
adding changesets
adding manifests
@@ -421,7 +421,7 @@
Pushing that topic would create a new heads will be prevented::
$ hg push --rev drinks
- pushing to $TESTTMP/server
+ pushing to $TESTTMP/server (glob)
searching for changes
abort: push creates new remote head 70dfa201ed73!
(merge or see "hg help push" for details about pushing new heads)
@@ -437,7 +437,7 @@
merging shopping
switching to topic tools
$ hg push
- pushing to $TESTTMP/server
+ pushing to $TESTTMP/server (glob)
searching for changes
abort: push creates new remote head 4cd7c1591a67!
(merge or see "hg help push" for details about pushing new heads)
@@ -446,7 +446,7 @@
Publishing only one of them is allowed (as long as it does not create a new branch head has we just saw in the previous case)::
$ hg push -r drinks
- pushing to $TESTTMP/server
+ pushing to $TESTTMP/server (glob)
searching for changes
adding changesets
adding manifests
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/testlib/checkheads-util.sh Fri Mar 31 15:44:10 2017 +0200
@@ -0,0 +1,26 @@
+# common setup for head checking code
+
+. $TESTDIR/testlib/common.sh
+
+cat >> $HGRCPATH <<EOF
+[ui]
+logtemplate ="{node|short} ({phase}): {desc}\n"
+
+[phases]
+publish=False
+
+[extensions]
+strip=
+evolve=
+EOF
+
+setuprepos() {
+ echo creating basic server and client repo
+ hg init server
+ cd server
+ mkcommit root
+ hg phase --public .
+ mkcommit A0
+ cd ..
+ hg clone server client
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/testlib/common.sh Fri Mar 31 15:44:10 2017 +0200
@@ -0,0 +1,16 @@
+. $TESTDIR/testlib/pythonpath.sh
+
+mkcommit() {
+ echo "$1" > "$1"
+ hg add "$1"
+ hg ci -m "$1"
+}
+
+getid() {
+ hg log --hidden --template '{node}\n' --rev "$1"
+}
+
+cat >> $HGRCPATH <<EOF
+[alias]
+debugobsolete=debugobsolete -d '0 0'
+EOF
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/testlib/exchange-util.sh Fri Mar 31 15:44:10 2017 +0200
@@ -0,0 +1,110 @@
+#!/bin/sh
+
+cat >> $HGRCPATH <<EOF
+[web]
+push_ssl = false
+allow_push = *
+
+[ui]
+logtemplate ="{node|short} ({phase}): {desc}\n"
+
+[phases]
+publish=False
+
+[experimental]
+verbose-obsolescence-exchange=false
+bundle2-exp=true
+bundle2-output-capture=True
+
+[alias]
+debugobsolete=debugobsolete -d '0 0'
+
+[extensions]
+hgext.strip=
+EOF
+echo "evolve=$(echo $(dirname $TESTDIR))/hgext3rd/evolve/" >> $HGRCPATH
+
+mkcommit() {
+ echo "$1" > "$1"
+ hg add "$1"
+ hg ci -m "$1"
+}
+getid() {
+ hg log --hidden --template '{node}\n' --rev "$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 | sort
+ echo "# obstore: pushdest"
+ hg -R pushdest debugobsolete | sort
+ echo "# obstore: pulldest"
+ hg -R pulldest debugobsolete | sort
+
+ 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 | sort
+ echo "# obstore: pushdest"
+ hg -R pushdest debugobsolete | sort
+ echo "# obstore: pulldest"
+ hg -R pulldest debugobsolete | sort
+ 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 | sort
+ echo "# obstore: pushdest"
+ hg -R pushdest debugobsolete | sort
+ echo "# obstore: pulldest"
+ hg -R pulldest debugobsolete | sort
+
+ cd ..
+
+}