diff --git a/mercurial/exchange.py b/mercurial/exchange.py
--- a/mercurial/exchange.py
+++ b/mercurial/exchange.py
@@ -1532,20 +1532,14 @@ def bundle2requested(bundlecaps):
         return any(cap.startswith('HG2') for cap in bundlecaps)
     return False
 
-def getbundle(repo, source, heads=None, common=None, bundlecaps=None,
-              **kwargs):
-    """return a full bundle (with potentially multiple kind of parts)
+def getbundlechunks(repo, source, heads=None, common=None, bundlecaps=None,
+                    **kwargs):
+    """Return chunks constituting a bundle's raw data.
 
     Could be a bundle HG10 or a bundle HG20 depending on bundlecaps
-    passed. For now, the bundle can contain only changegroup, but this will
-    changes when more part type will be available for bundle2.
+    passed.
 
-    This is different from changegroup.getchangegroup that only returns an HG10
-    changegroup bundle. They may eventually get reunited in the future when we
-    have a clearer idea of the API we what to query different data.
-
-    The implementation is at a very early stage and will get massive rework
-    when the API of bundle is refined.
+    Returns an iterator over raw chunks (of varying sizes).
     """
     usebundle2 = bundle2requested(bundlecaps)
     # bundle10 case
@@ -1557,8 +1551,8 @@ def getbundle(repo, source, heads=None, 
             raise ValueError(_('unsupported getbundle arguments: %s')
                              % ', '.join(sorted(kwargs.keys())))
         outgoing = _computeoutgoing(repo, heads, common)
-        return changegroup.getchangegroup(repo, source, outgoing,
-                                          bundlecaps=bundlecaps)
+        bundler = changegroup.getbundler('01', repo, bundlecaps)
+        return changegroup.getsubsetraw(repo, outgoing, bundler, source)
 
     # bundle20 case
     b2caps = {}
@@ -1576,7 +1570,7 @@ def getbundle(repo, source, heads=None, 
         func(bundler, repo, source, bundlecaps=bundlecaps, b2caps=b2caps,
              **kwargs)
 
-    return util.chunkbuffer(bundler.getchunks())
+    return bundler.getchunks()
 
 @getbundle2partsgenerator('changegroup')
 def _getbundlechangegrouppart(bundler, repo, source, bundlecaps=None,
diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -149,14 +149,18 @@ class localpeer(peer.peerrepository):
 
     def getbundle(self, source, heads=None, common=None, bundlecaps=None,
                   **kwargs):
-        cg = exchange.getbundle(self._repo, source, heads=heads,
-                                common=common, bundlecaps=bundlecaps, **kwargs)
+        chunks = exchange.getbundlechunks(self._repo, source, heads=heads,
+                                          common=common, bundlecaps=bundlecaps,
+                                          **kwargs)
+        cb = util.chunkbuffer(chunks)
+
         if bundlecaps is not None and 'HG20' in bundlecaps:
             # When requesting a bundle2, getbundle returns a stream to make the
             # wire level function happier. We need to build a proper object
             # from it in local peer.
-            cg = bundle2.getunbundler(self.ui, cg)
-        return cg
+            return bundle2.getunbundler(self.ui, cb)
+        else:
+            return changegroup.getunbundler('01', cb, None)
 
     # TODO We might want to move the next two calls into legacypeer and add
     # unbundle instead.
diff --git a/mercurial/wireproto.py b/mercurial/wireproto.py
--- a/mercurial/wireproto.py
+++ b/mercurial/wireproto.py
@@ -772,8 +772,10 @@ def getbundle(repo, proto, others):
         if not exchange.bundle2requested(opts.get('bundlecaps')):
             return ooberror(bundle2required)
 
-    cg = exchange.getbundle(repo, 'serve', **opts)
-    return streamres(proto.groupchunks(cg))
+    chunks = exchange.getbundlechunks(repo, 'serve', **opts)
+    # TODO avoid util.chunkbuffer() here since it is adding overhead to
+    # what is fundamentally a generator proxying operation.
+    return streamres(proto.groupchunks(util.chunkbuffer(chunks)))
 
 @wireprotocommand('heads')
 def heads(repo, proto):
diff --git a/tests/test-getbundle.t b/tests/test-getbundle.t
--- a/tests/test-getbundle.t
+++ b/tests/test-getbundle.t
@@ -170,7 +170,7 @@ Get branch and merge:
   $ hg debuggetbundle repo bundle -t bundle2
   $ hg debugbundle bundle
   Stream params: {}
-  changegroup -- "sortdict([('version', '01'), ('nbchanges', '18')])"
+  changegroup -- "sortdict([('version', '01')])"
       7704483d56b2a7b5db54dcee7c62378ac629b348
       29a4d1f17bd3f0779ca0525bebb1cfb51067c738
       713346a995c363120712aed1aee7e04afd867638