diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py
index c29c7e083c342ccc2aed77e513c77a5d67e8cb86_bWVyY3VyaWFsL2J1bmRsZTIucHk=..cb2b2242428df5be87693b8acaac71deafcff2c5_bWVyY3VyaWFsL2J1bmRsZTIucHk= 100644
--- a/mercurial/bundle2.py
+++ b/mercurial/bundle2.py
@@ -939,7 +939,16 @@
             yield _pack(_fstreamparamsize, paramssize)
         # From there, payload might need to be decompressed
         self._fp = self._compengine.decompressorreader(self._fp)
-        emptycount = 0
+
+        # We usually wait for empty terminators: a bundle part terminator
+        # followed by a bundle terminator.
+        #
+        # Since the empty bundle has no parts,
+        # bundle part terminator never comes.
+        #
+        # So we boostrap this detection with am empty part, which the first
+        # piece of part will reset.
+        emptycount = 1
         while emptycount < 2:
             # so we can brainlessly loop
             assert _fpartheadersize == _fpayloadsize
diff --git a/relnotes/7.0 b/relnotes/7.0
index c29c7e083c342ccc2aed77e513c77a5d67e8cb86_cmVsbm90ZXMvNy4w..cb2b2242428df5be87693b8acaac71deafcff2c5_cmVsbm90ZXMvNy4w 100644
--- a/relnotes/7.0
+++ b/relnotes/7.0
@@ -53,6 +53,9 @@
 - rhg: set the expected dirstate permissions (0o666 minus umask) (a48c688d3e80)
 - rhg: fix matcher issue (136e74c2bf8f)
 - rhg files correctly implements `--rev` (it instead provided `--revision`)
+- clone-bundles: fix background spawning of automatic generation
+- bundle-spec: properly format boolean parameter (issue6960)
+- bundle2: fix a bug where _forwardchunks doesn't work with empty bundles
 
 == Rust ==
 
diff --git a/tests/test-bundle2.py b/tests/test-bundle2.py
new file mode 100644
index 0000000000000000000000000000000000000000..cb2b2242428df5be87693b8acaac71deafcff2c5_dGVzdHMvdGVzdC1idW5kbGUyLnB5
--- /dev/null
+++ b/tests/test-bundle2.py
@@ -0,0 +1,33 @@
+import unittest
+from mercurial import bundle2, ui as uimod
+
+bundle20 = bundle2.bundle20
+unbundle20 = bundle2.unbundle20
+
+ui = uimod.ui.load()
+
+
+class Bundle2tests(unittest.TestCase):
+    def test_nonempty_bundle_forwardchunks(self):
+        bundler = bundle20(ui)
+        bundler.newpart(
+            b'cache:rev-branch-cache', data=b'some-data', mandatory=False
+        )
+        data = b''.join(list(bundler.getchunks()))
+        unbundle = unbundle20(ui, __import__("io").BytesIO(data[4:]))
+        forwarded_data = b''.join(list(unbundle._forwardchunks()))
+        self.assertEqual(data, forwarded_data)
+
+    def test_empty_bundle_forwardchunks(self):
+        bundler = bundle20(ui)
+        data = b''.join(list(bundler.getchunks()))
+        self.assertEqual(data, b'HG20\0\0\0\0\0\0\0\0')
+        unbundle = unbundle20(ui, __import__("io").BytesIO(data[4:]))
+        forwarded_data = b''.join(list(unbundle._forwardchunks()))
+        self.assertEqual(data, forwarded_data)
+
+
+if __name__ == '__main__':
+    import silenttestrunner
+
+    silenttestrunner.main(__name__)