diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -1270,6 +1270,29 @@ def debugbundle(ui, bundlepath, all=None
     finally:
         f.close()
 
+def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
+    """retrieves a bundle from a repo
+
+    Every ID must be a full-length hex node id string. Saves the bundle to the
+    given file.
+    """
+    repo = hg.repository(ui, repopath)
+    if not repo.capable('getbundle'):
+        raise util.Abort("getbundle() not supported by target repository")
+    args = {}
+    if common:
+        args['common'] = [bin(s) for s in common]
+    if head:
+        args['heads'] = [bin(s) for s in head]
+    bundle = repo.getbundle('debug', **args)
+
+    bundletype = opts.get('type', 'bzip2').lower()
+    btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
+    bundletype = btypes.get(bundletype)
+    if bundletype not in changegroup.bundletypes:
+        raise util.Abort(_('unknown bundle type specified with --type'))
+    changegroup.writebundle(bundle, bundlepath, bundletype)
+
 def debugpushkey(ui, repopath, namespace, *keyinfo):
     '''access the pushkey key/value protocol
 
@@ -4497,6 +4520,13 @@ table = {
          _('[-e] DATE [RANGE]')),
     "debugdata": (debugdata, [], _('FILE REV')),
     "debugfsinfo": (debugfsinfo, [], _('[PATH]')),
+    "debuggetbundle":
+        (debuggetbundle,
+         [('H', 'head', [], _('id of head node'), _('ID')),
+          ('C', 'common', [], _('id of common node'), _('ID')),
+          ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
+         ],
+         _('REPO FILE [-H|-C ID]...')),
     "debugignore": (debugignore, [], ''),
     "debugindex": (debugindex,
                    [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
@@ -4869,6 +4899,6 @@ table = {
 
 norepo = ("clone init version help debugcommands debugcomplete"
           " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
-          " debugknown debugbundle")
+          " debugknown debuggetbundle debugbundle")
 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
                 " debugdata debugindex debugindexdot")
diff --git a/mercurial/hgweb/hgweb_mod.py b/mercurial/hgweb/hgweb_mod.py
--- a/mercurial/hgweb/hgweb_mod.py
+++ b/mercurial/hgweb/hgweb_mod.py
@@ -17,6 +17,7 @@ import webcommands, protocol, webutil
 perms = {
     'changegroup': 'pull',
     'changegroupsubset': 'pull',
+    'getbundle': 'pull',
     'stream_out': 'pull',
     'listkeys': 'pull',
     'unbundle': 'push',
diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -21,7 +21,7 @@ propertycache = util.propertycache
 
 class localrepository(repo.repository):
     capabilities = set(('lookup', 'changegroupsubset', 'branchmap', 'pushkey',
-                        'known'))
+                        'known', 'getbundle'))
     supportedformats = set(('revlogv1', 'parentdelta'))
     supported = supportedformats | set(('store', 'fncache', 'shared',
                                         'dotencode'))
@@ -1443,16 +1443,41 @@ class localrepository(repo.repository):
         Another wrinkle is doing the reverse, figuring out which changeset in
         the changegroup a particular filenode or manifestnode belongs to.
         """
+        cl = self.changelog
+        if not bases:
+            bases = [nullid]
+        csets, bases, heads = cl.nodesbetween(bases, heads)
+        # We assume that all ancestors of bases are known
+        common = set(cl.ancestors(*[cl.rev(n) for n in bases]))
+        return self._changegroupsubset(common, csets, heads, source)
+
+    def getbundle(self, source, heads=None, common=None):
+        """Like changegroupsubset, but returns the set difference between the
+        ancestors of heads and the ancestors common.
+
+        If heads is None, use the local heads. If common is None, use [nullid].
+
+        The nodes in common might not all be known locally due to the way the
+        current discovery protocol works.
+        """
+        cl = self.changelog
+        if common:
+            nm = cl.nodemap
+            common = [n for n in common if n in nm]
+        else:
+            common = [nullid]
+        if not heads:
+            heads = cl.heads()
+        common, missing = cl.findcommonmissing(common, heads)
+        return self._changegroupsubset(common, missing, heads, source)
+
+    def _changegroupsubset(self, commonrevs, csets, heads, source):
 
         cl = self.changelog
         mf = self.manifest
         mfs = {} # needed manifests
         fnodes = {} # needed file nodes
 
-        if not bases:
-            bases = [nullid]
-        csets, bases, heads = cl.nodesbetween(bases, heads)
-
         # can we go through the fast path ?
         heads.sort()
         if heads == sorted(self.heads()):
@@ -1462,9 +1487,6 @@ class localrepository(repo.repository):
         self.hook('preoutgoing', throw=True, source=source)
         self.changegroupinfo(csets, source)
 
-        # We assume that all ancestors of bases are known
-        commonrevs = set(cl.ancestors(*[cl.rev(n) for n in bases]))
-
         # A function generating function that sets up the initial environment
         # the inner function.
         def filenode_collector(changedfiles):
diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -399,11 +399,12 @@ class revlog(object):
                     yield i
                     break
 
-    def findmissing(self, common=None, heads=None):
-        """Return the ancestors of heads that are not ancestors of common.
+    def findcommonmissing(self, common=None, heads=None):
+        """Return a tuple of the ancestors of common and the ancestors of heads
+        that are not ancestors of common.
 
-        More specifically, return a list of nodes N such that every N
-        satisfies the following constraints:
+        More specifically, the second element is a list of nodes N such that
+        every N satisfies the following constraints:
 
           1. N is an ancestor of some node in 'heads'
           2. N is not an ancestor of any node in 'common'
@@ -441,7 +442,25 @@ class revlog(object):
                         visit.append(p)
         missing = list(missing)
         missing.sort()
-        return [self.node(r) for r in missing]
+        return has, [self.node(r) for r in missing]
+
+    def findmissing(self, common=None, heads=None):
+        """Return the ancestors of heads that are not ancestors of common.
+
+        More specifically, return a list of nodes N such that every N
+        satisfies the following constraints:
+
+          1. N is an ancestor of some node in 'heads'
+          2. N is not an ancestor of any node in 'common'
+
+        The list is sorted by revision number, meaning it is
+        topologically sorted.
+
+        'heads' and 'common' are both lists of node IDs.  If heads is
+        not supplied, uses all of the revlog's heads.  If common is not
+        supplied, uses nullid."""
+        _common, missing = self.findcommonmissing(common, heads)
+        return missing
 
     def nodesbetween(self, roots=None, heads=None):
         """Return a topological path from 'roots' to 'heads'.
diff --git a/mercurial/wireproto.py b/mercurial/wireproto.py
--- a/mercurial/wireproto.py
+++ b/mercurial/wireproto.py
@@ -123,6 +123,16 @@ class wirerepository(repo.repository):
                              bases=bases, heads=heads)
         return changegroupmod.unbundle10(self._decompress(f), 'UN')
 
+    def getbundle(self, source, heads=None, common=None):
+        self.requirecap('getbundle', _('look up remote changes'))
+        opts = {}
+        if heads is not None:
+            opts['heads'] = encodelist(heads)
+        if common is not None:
+            opts['common'] = encodelist(common)
+        f = self._callstream("getbundle", **opts)
+        return changegroupmod.unbundle10(self._decompress(f), 'UN')
+
     def unbundle(self, cg, heads, source):
         '''Send cg (a readable file-like object representing the
         changegroup to push, typically a chunkbuffer object) to the
@@ -206,7 +216,7 @@ def branches(repo, proto, nodes):
     return "".join(r)
 
 def capabilities(repo, proto):
-    caps = 'lookup changegroupsubset branchmap pushkey known'.split()
+    caps = 'lookup changegroupsubset branchmap pushkey known getbundle'.split()
     if _allowstream(repo.ui):
         requiredformats = repo.requirements & repo.supportedformats
         # if our local revlogs are just revlogv1, add 'stream' cap
@@ -234,6 +244,13 @@ def debugwireargs(repo, proto, one, two,
     opts = options('debugwireargs', ['three', 'four'], others)
     return repo.debugwireargs(one, two, **opts)
 
+def getbundle(repo, proto, others):
+    opts = options('getbundle', ['heads', 'common'], others)
+    for k, v in opts.iteritems():
+        opts[k] = decodelist(v)
+    cg = repo.getbundle('serve', **opts)
+    return streamres(proto.groupchunks(cg))
+
 def heads(repo, proto):
     h = repo.heads()
     return encodelist(h) + "\n"
@@ -382,6 +399,7 @@ commands = {
     'changegroup': (changegroup, 'roots'),
     'changegroupsubset': (changegroupsubset, 'bases heads'),
     'debugwireargs': (debugwireargs, 'one two *'),
+    'getbundle': (getbundle, '*'),
     'heads': (heads, ''),
     'hello': (hello, ''),
     'known': (known, 'nodes'),
diff --git a/tests/test-debugcomplete.t b/tests/test-debugcomplete.t
--- a/tests/test-debugcomplete.t
+++ b/tests/test-debugcomplete.t
@@ -76,6 +76,7 @@ Show debug commands if there are no othe
   debugdata
   debugdate
   debugfsinfo
+  debuggetbundle
   debugignore
   debugindex
   debugindexdot
@@ -219,6 +220,7 @@ Show all commands + options
   debugdata: 
   debugdate: extended
   debugfsinfo: 
+  debuggetbundle: head, common, type
   debugignore: 
   debugindex: format
   debugindexdot: 
diff --git a/tests/test-getbundle.t b/tests/test-getbundle.t
new file mode 100644
--- /dev/null
+++ b/tests/test-getbundle.t
@@ -0,0 +1,253 @@
+
+= Test the getbundle() protocol function =
+
+Enable graphlog extension:
+
+  $ echo "[extensions]" >> $HGRCPATH
+  $ echo "graphlog=" >> $HGRCPATH
+
+Create a test repository:
+
+  $ hg init repo
+  $ cd repo
+  $ hg debugbuilddag -n -m '+2 :fork +5 :p1 *fork +6 :p2 /p1 :m1 +3' > /dev/null
+  $ hg glog --template '{node}\n'
+  @  2bba2f40f321484159b395a43f20101d4bb7ead0
+  |
+  o  d9e5488323c782fe684573f3043369d199038b6f
+  |
+  o  6e9a5adf5437e49c746288cf95c5ac34fa8f2f72
+  |
+  o    733bf0910832b26b768a09172f325f995b5476e1
+  |\
+  | o  b5af5d6ea56d73ce24c40bc3cd19a862f74888ac
+  | |
+  | o  6b57ee934bb2996050540f84cdfc8dcad1e7267d
+  | |
+  | o  2c0ec49482e8abe888b7bd090b5827acfc22b3d7
+  | |
+  | o  c1818a9f5977dd4139a48f93f5425c67d44a9368
+  | |
+  | o  6c725a58ad10aea441540bfd06c507f63e8b9cdd
+  | |
+  | o  18063366a155bd56b5618229ae2ac3e91849aa5e
+  | |
+  | o  a21d913c992197a2eb60b298521ec0f045a04799
+  | |
+  o |  b6b2b682253df2ffedc10e9415e4114202b303c5
+  | |
+  o |  2114148793524fd045998f71a45b0aaf139f752b
+  | |
+  o |  74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc
+  | |
+  o |  ea919464b16e003894c48b6cb68df3cd9411b544
+  | |
+  o |  0f82d97ec2778746743fbc996740d409558fda22
+  |/
+  o  6e23b016bc0f0e79c7bd9dd372ccee07055d7fd4
+  |
+  o  10e64d654571f11577745b4d8372e859d9e4df63
+  
+  $ cd ..
+
+
+= Test locally =
+
+Get everything:
+
+  $ hg debuggetbundle repo bundle
+  $ hg debugbundle bundle
+  10e64d654571f11577745b4d8372e859d9e4df63
+  6e23b016bc0f0e79c7bd9dd372ccee07055d7fd4
+  0f82d97ec2778746743fbc996740d409558fda22
+  ea919464b16e003894c48b6cb68df3cd9411b544
+  74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc
+  2114148793524fd045998f71a45b0aaf139f752b
+  b6b2b682253df2ffedc10e9415e4114202b303c5
+  a21d913c992197a2eb60b298521ec0f045a04799
+  18063366a155bd56b5618229ae2ac3e91849aa5e
+  6c725a58ad10aea441540bfd06c507f63e8b9cdd
+  c1818a9f5977dd4139a48f93f5425c67d44a9368
+  2c0ec49482e8abe888b7bd090b5827acfc22b3d7
+  6b57ee934bb2996050540f84cdfc8dcad1e7267d
+  b5af5d6ea56d73ce24c40bc3cd19a862f74888ac
+  733bf0910832b26b768a09172f325f995b5476e1
+  6e9a5adf5437e49c746288cf95c5ac34fa8f2f72
+  d9e5488323c782fe684573f3043369d199038b6f
+  2bba2f40f321484159b395a43f20101d4bb7ead0
+
+Get part of linear run:
+
+  $ hg debuggetbundle repo bundle -H d9e5488323c782fe684573f3043369d199038b6f -C 733bf0910832b26b768a09172f325f995b5476e1
+  $ hg debugbundle bundle
+  6e9a5adf5437e49c746288cf95c5ac34fa8f2f72
+  d9e5488323c782fe684573f3043369d199038b6f
+
+Get missing branch and merge:
+
+  $ hg debuggetbundle repo bundle -H d9e5488323c782fe684573f3043369d199038b6f -C 6b57ee934bb2996050540f84cdfc8dcad1e7267d
+  $ hg debugbundle bundle
+  0f82d97ec2778746743fbc996740d409558fda22
+  ea919464b16e003894c48b6cb68df3cd9411b544
+  74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc
+  2114148793524fd045998f71a45b0aaf139f752b
+  b6b2b682253df2ffedc10e9415e4114202b303c5
+  b5af5d6ea56d73ce24c40bc3cd19a862f74888ac
+  733bf0910832b26b768a09172f325f995b5476e1
+  6e9a5adf5437e49c746288cf95c5ac34fa8f2f72
+  d9e5488323c782fe684573f3043369d199038b6f
+
+Get from only one head:
+
+  $ hg debuggetbundle repo bundle -H 6c725a58ad10aea441540bfd06c507f63e8b9cdd -C 6e23b016bc0f0e79c7bd9dd372ccee07055d7fd4
+  $ hg debugbundle bundle
+  a21d913c992197a2eb60b298521ec0f045a04799
+  18063366a155bd56b5618229ae2ac3e91849aa5e
+  6c725a58ad10aea441540bfd06c507f63e8b9cdd
+
+Get parts of two branches:
+
+  $ hg debuggetbundle repo bundle -H 6b57ee934bb2996050540f84cdfc8dcad1e7267d -C c1818a9f5977dd4139a48f93f5425c67d44a9368 -H 2114148793524fd045998f71a45b0aaf139f752b -C ea919464b16e003894c48b6cb68df3cd9411b544
+  $ hg debugbundle bundle
+  74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc
+  2114148793524fd045998f71a45b0aaf139f752b
+  2c0ec49482e8abe888b7bd090b5827acfc22b3d7
+  6b57ee934bb2996050540f84cdfc8dcad1e7267d
+
+Check that we get all needed file changes:
+
+  $ hg debugbundle bundle --all
+  format: id, p1, p2, cset, len(delta)
+  
+  changelog
+  74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc ea919464b16e003894c48b6cb68df3cd9411b544 0000000000000000000000000000000000000000 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc 99
+  2114148793524fd045998f71a45b0aaf139f752b 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc 0000000000000000000000000000000000000000 2114148793524fd045998f71a45b0aaf139f752b 99
+  2c0ec49482e8abe888b7bd090b5827acfc22b3d7 c1818a9f5977dd4139a48f93f5425c67d44a9368 0000000000000000000000000000000000000000 2c0ec49482e8abe888b7bd090b5827acfc22b3d7 102
+  6b57ee934bb2996050540f84cdfc8dcad1e7267d 2c0ec49482e8abe888b7bd090b5827acfc22b3d7 0000000000000000000000000000000000000000 6b57ee934bb2996050540f84cdfc8dcad1e7267d 102
+  
+  manifest
+  dac7984588fc4eea7acbf39693a9c1b06f5b175d 591f732a3faf1fb903815273f3c199a514a61ccb 0000000000000000000000000000000000000000 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc 113
+  0772616e6b48a76afb6c1458e193cbb3dae2e4ff dac7984588fc4eea7acbf39693a9c1b06f5b175d 0000000000000000000000000000000000000000 2114148793524fd045998f71a45b0aaf139f752b 113
+  eb498cd9af6c44108e43041e951ce829e29f6c80 bff2f4817ced57b386caf7c4e3e36a4bc9af7e93 0000000000000000000000000000000000000000 2c0ec49482e8abe888b7bd090b5827acfc22b3d7 295
+  b15709c071ddd2d93188508ba156196ab4f19620 eb498cd9af6c44108e43041e951ce829e29f6c80 0000000000000000000000000000000000000000 6b57ee934bb2996050540f84cdfc8dcad1e7267d 114
+  
+  mf
+  4f73f97080266ab8e0c0561ca8d0da3eaf65b695 301ca08d026bb72cb4258a9d211bdf7ca0bcd810 0000000000000000000000000000000000000000 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc 17
+  c7b583de053293870e145f45bd2d61643563fd06 4f73f97080266ab8e0c0561ca8d0da3eaf65b695 0000000000000000000000000000000000000000 2114148793524fd045998f71a45b0aaf139f752b 18
+  266ee3c0302a5a18f1cf96817ac79a51836179e9 edc0f6b8db80d68ae6aff2b19f7e5347ab68fa63 0000000000000000000000000000000000000000 2c0ec49482e8abe888b7bd090b5827acfc22b3d7 149
+  698c6a36220548cd3903ca7dada27c59aa500c52 266ee3c0302a5a18f1cf96817ac79a51836179e9 0000000000000000000000000000000000000000 6b57ee934bb2996050540f84cdfc8dcad1e7267d 19
+  
+  nf11
+  33fbc651630ffa7ccbebfe4eb91320a873e7291c 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 2c0ec49482e8abe888b7bd090b5827acfc22b3d7 16
+  
+  nf12
+  ddce0544363f037e9fb889faca058f52dc01c0a5 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 6b57ee934bb2996050540f84cdfc8dcad1e7267d 16
+  
+  nf4
+  3c1407305701051cbed9f9cb9a68bdfb5997c235 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc 15
+  
+  nf5
+  0dbd89c185f53a1727c54cd1ce256482fa23968e 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 2114148793524fd045998f71a45b0aaf139f752b 15
+
+Get branch and merge:
+
+  $ hg debuggetbundle repo bundle -C 10e64d654571f11577745b4d8372e859d9e4df63 -H 6e9a5adf5437e49c746288cf95c5ac34fa8f2f72
+  $ hg debugbundle bundle
+  6e23b016bc0f0e79c7bd9dd372ccee07055d7fd4
+  0f82d97ec2778746743fbc996740d409558fda22
+  ea919464b16e003894c48b6cb68df3cd9411b544
+  74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc
+  2114148793524fd045998f71a45b0aaf139f752b
+  b6b2b682253df2ffedc10e9415e4114202b303c5
+  a21d913c992197a2eb60b298521ec0f045a04799
+  18063366a155bd56b5618229ae2ac3e91849aa5e
+  6c725a58ad10aea441540bfd06c507f63e8b9cdd
+  c1818a9f5977dd4139a48f93f5425c67d44a9368
+  2c0ec49482e8abe888b7bd090b5827acfc22b3d7
+  6b57ee934bb2996050540f84cdfc8dcad1e7267d
+  b5af5d6ea56d73ce24c40bc3cd19a862f74888ac
+  733bf0910832b26b768a09172f325f995b5476e1
+  6e9a5adf5437e49c746288cf95c5ac34fa8f2f72
+
+
+= Test via HTTP =
+
+Get everything:
+
+  $ hg serve -R repo -p $HGPORT -d --pid-file=hg.pid -E error.log -A access.log
+  $ cat hg.pid >> $DAEMON_PIDS
+  $ hg debuggetbundle http://localhost:$HGPORT/ bundle
+  $ hg debugbundle bundle
+  10e64d654571f11577745b4d8372e859d9e4df63
+  6e23b016bc0f0e79c7bd9dd372ccee07055d7fd4
+  0f82d97ec2778746743fbc996740d409558fda22
+  ea919464b16e003894c48b6cb68df3cd9411b544
+  74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc
+  2114148793524fd045998f71a45b0aaf139f752b
+  b6b2b682253df2ffedc10e9415e4114202b303c5
+  a21d913c992197a2eb60b298521ec0f045a04799
+  18063366a155bd56b5618229ae2ac3e91849aa5e
+  6c725a58ad10aea441540bfd06c507f63e8b9cdd
+  c1818a9f5977dd4139a48f93f5425c67d44a9368
+  2c0ec49482e8abe888b7bd090b5827acfc22b3d7
+  6b57ee934bb2996050540f84cdfc8dcad1e7267d
+  b5af5d6ea56d73ce24c40bc3cd19a862f74888ac
+  733bf0910832b26b768a09172f325f995b5476e1
+  6e9a5adf5437e49c746288cf95c5ac34fa8f2f72
+  d9e5488323c782fe684573f3043369d199038b6f
+  2bba2f40f321484159b395a43f20101d4bb7ead0
+
+Get parts of two branches:
+
+  $ hg debuggetbundle http://localhost:$HGPORT/ bundle -H 6b57ee934bb2996050540f84cdfc8dcad1e7267d -C c1818a9f5977dd4139a48f93f5425c67d44a9368 -H 2114148793524fd045998f71a45b0aaf139f752b -C ea919464b16e003894c48b6cb68df3cd9411b544
+  $ hg debugbundle bundle
+  74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc
+  2114148793524fd045998f71a45b0aaf139f752b
+  2c0ec49482e8abe888b7bd090b5827acfc22b3d7
+  6b57ee934bb2996050540f84cdfc8dcad1e7267d
+
+Check that we get all needed file changes:
+
+  $ hg debugbundle bundle --all
+  format: id, p1, p2, cset, len(delta)
+  
+  changelog
+  74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc ea919464b16e003894c48b6cb68df3cd9411b544 0000000000000000000000000000000000000000 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc 99
+  2114148793524fd045998f71a45b0aaf139f752b 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc 0000000000000000000000000000000000000000 2114148793524fd045998f71a45b0aaf139f752b 99
+  2c0ec49482e8abe888b7bd090b5827acfc22b3d7 c1818a9f5977dd4139a48f93f5425c67d44a9368 0000000000000000000000000000000000000000 2c0ec49482e8abe888b7bd090b5827acfc22b3d7 102
+  6b57ee934bb2996050540f84cdfc8dcad1e7267d 2c0ec49482e8abe888b7bd090b5827acfc22b3d7 0000000000000000000000000000000000000000 6b57ee934bb2996050540f84cdfc8dcad1e7267d 102
+  
+  manifest
+  dac7984588fc4eea7acbf39693a9c1b06f5b175d 591f732a3faf1fb903815273f3c199a514a61ccb 0000000000000000000000000000000000000000 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc 113
+  0772616e6b48a76afb6c1458e193cbb3dae2e4ff dac7984588fc4eea7acbf39693a9c1b06f5b175d 0000000000000000000000000000000000000000 2114148793524fd045998f71a45b0aaf139f752b 113
+  eb498cd9af6c44108e43041e951ce829e29f6c80 bff2f4817ced57b386caf7c4e3e36a4bc9af7e93 0000000000000000000000000000000000000000 2c0ec49482e8abe888b7bd090b5827acfc22b3d7 295
+  b15709c071ddd2d93188508ba156196ab4f19620 eb498cd9af6c44108e43041e951ce829e29f6c80 0000000000000000000000000000000000000000 6b57ee934bb2996050540f84cdfc8dcad1e7267d 114
+  
+  mf
+  4f73f97080266ab8e0c0561ca8d0da3eaf65b695 301ca08d026bb72cb4258a9d211bdf7ca0bcd810 0000000000000000000000000000000000000000 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc 17
+  c7b583de053293870e145f45bd2d61643563fd06 4f73f97080266ab8e0c0561ca8d0da3eaf65b695 0000000000000000000000000000000000000000 2114148793524fd045998f71a45b0aaf139f752b 18
+  266ee3c0302a5a18f1cf96817ac79a51836179e9 edc0f6b8db80d68ae6aff2b19f7e5347ab68fa63 0000000000000000000000000000000000000000 2c0ec49482e8abe888b7bd090b5827acfc22b3d7 149
+  698c6a36220548cd3903ca7dada27c59aa500c52 266ee3c0302a5a18f1cf96817ac79a51836179e9 0000000000000000000000000000000000000000 6b57ee934bb2996050540f84cdfc8dcad1e7267d 19
+  
+  nf11
+  33fbc651630ffa7ccbebfe4eb91320a873e7291c 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 2c0ec49482e8abe888b7bd090b5827acfc22b3d7 16
+  
+  nf12
+  ddce0544363f037e9fb889faca058f52dc01c0a5 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 6b57ee934bb2996050540f84cdfc8dcad1e7267d 16
+  
+  nf4
+  3c1407305701051cbed9f9cb9a68bdfb5997c235 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc 15
+  
+  nf5
+  0dbd89c185f53a1727c54cd1ce256482fa23968e 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 2114148793524fd045998f71a45b0aaf139f752b 15
+
+Verify we hit the HTTP server:
+
+  $ cat access.log
+  * - - [*] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob)
+  * - - [*] "GET /?cmd=getbundle HTTP/1.1" 200 - (glob)
+  * - - [*] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob)
+  * - - [*] "GET /?cmd=getbundle&common=c1818a9f5977dd4139a48f93f5425c67d44a9368+ea919464b16e003894c48b6cb68df3cd9411b544&heads=6b57ee934bb2996050540f84cdfc8dcad1e7267d+2114148793524fd045998f71a45b0aaf139f752b HTTP/1.1" 200 - (glob)
+
+  $ cat error.log
+
diff --git a/tests/test-hgweb-commands.t b/tests/test-hgweb-commands.t
--- a/tests/test-hgweb-commands.t
+++ b/tests/test-hgweb-commands.t
@@ -905,7 +905,7 @@ capabilities
   $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '?cmd=capabilities'; echo
   200 Script output follows
   
-  lookup changegroupsubset branchmap pushkey known unbundle=HG10GZ,HG10BZ,HG10UN
+  lookup changegroupsubset branchmap pushkey known getbundle unbundle=HG10GZ,HG10BZ,HG10UN
 
 heads