diff --git a/mercurial/changegroup.py b/mercurial/changegroup.py
--- a/mercurial/changegroup.py
+++ b/mercurial/changegroup.py
@@ -929,29 +929,20 @@ def changegroupsubset(repo, roots, heads
It is fairly complex as determining which filenodes and which
manifest nodes need to be included for the changeset to be complete
is non-trivial.
Another wrinkle is doing the reverse, figuring out which changeset in
the changegroup a particular filenode or manifestnode belongs to.
"""
- cl = repo.changelog
- if not roots:
- roots = [nullid]
- discbases = []
- for n in roots:
- discbases.extend([p for p in cl.parents(n) if p != nullid])
- # TODO: remove call to nodesbetween.
- csets, roots, heads = cl.nodesbetween(roots, heads)
- included = set(csets)
- discbases = [n for n in discbases if n not in included]
- outgoing = discovery.outgoing(cl, discbases, heads)
- bundler = getbundler(version, repo)
- return getsubset(repo, outgoing, bundler, source)
+ emitter = changegroupemitter.fromrootsandheads(repo, roots, heads)
+ data = emitter.emitchangegroupdata(version, source)
+ return getunbundler(version, util.chunkbuffer(data), None,
+ {'clcount': emitter.changesetcount})
def getlocalchangegroup(repo, source, outgoing, bundlecaps=None,
version='01'):
"""Like getbundle, but taking a discovery.outgoing as an argument.
This is only implemented for local repos and reuses potentially
precomputed sets in outgoing."""
if not outgoing.missing:
@@ -1072,16 +1063,39 @@ class changegroupemitter(object):
destination. ``common`` is a list of binary nodes that are
common between this repo and the destination. The missing
nodes between ``common`` and ``heads`` will be included in the
changegroup.
"""
outgoing = computeoutgoing(repo, heads, common)
return changegroupemitter.fromoutgoing(repo, outgoing)
+ @classmethod
+ def fromrootsandheads(cls, repo, roots, heads):
+ """Create an instance with changesets between roots and heads.
+
+ The returned ``changegroupemitter`` will be configured to write
+ data for revisions that are descendants of any of the roots
+ in ``roots`` and ancestors of any of the heads in ``heads``. Both
+ are specified as a list of binary nodes.
+ """
+ cl = repo.changelog
+ if not roots:
+ roots = [nullid]
+ bases = []
+ for n in roots:
+ bases.extend([p for p in cl.parents(n) if p != nullid])
+ # TODO remove call to nodesbetween
+ nodes, roots, heads = cl.nodesbetween(roots, heads)
+ included = set(nodes)
+ bases = [n for n in bases if n not in included]
+ outgoing = discovery.outgoing(cl, bases, heads)
+
+ return changegroupemitter.fromoutgoing(repo, outgoing)
+
@property
def changesetcount(self):
"""The number of changesets in this changegroup."""
return len(self._nodes)
def emitchangegroupdata(self, version, source, bundlecaps=None,
fastpathlinkrev=False):
"""Emit raw changegroup data.