Merge branch 'master' into servlet-4

* master:
  Bazel: align JGit with shared external_deps repository
  Bazel: bump rules_jvm_external to 6.10
  MultiPackIndex: Offer an iterator over the entries in the midx
  Add missing LF at the end of GarbageCollectCommandTest
  Add GarbageCollectCommand#setGcConfig
  GC: add flag to control whether gc should pack all refs
  Downgrade spring-boot-maven-plugin to 3.5.10
  pack-refs: Add sorted flag
  Bazel: enforce strict MODULE.bazel.lock synchronization
  DfsPackFileMidxSingle: No need to set ints to 0 in constructor
  MidxPackFilter: Remove debug printlns
  DfsMidxWriter: add writing bitmaps to the newly created midx
  RefAdvancer: helper to find when a branch enters a pack
  Throw IOException if API tries to use destroyed TemporaryBuffer
  Update com.google.errorprone:error_prone_type_annotations to 2.46.0
  Update Apache sshd to 2.17.1
  Prepare 7.6.0-SNAPSHOT builds
  DfsPackFileMidx: offer local objects as ObjectToPack
  JGit v7.6.0.202601262032-m2
  Update org.assertj:assertj-core to 3.27.7
  DfsPackFileMidxNPacks: getBitmapIndex tries to load midx bitmaps
  PackBitmapIndexBuilderTest: add test to the bitmap builder storage
  Update bytebuddy to 1.18.4
  Update org.objectweb.asm to 9.9.1
  PackBitmapCalculator: Move code to calculate bitmaps out of PackWriter
  DfsPackFileMidx: expose the checksum of the midx
  DfsPackFile: Use getPackIndex while loading bitmaps
  DfsMidxWriter: set file size for the midx extension
  DfsPackFileMidx*Test: Use MidxTestUtils when possible
  DfsPackFileMidx: Implement PackReverseIndex over midx
  DfsPackFileMidx: Implement PackIndex over midx
  MultiPackIndex: add the checksum to the midx
  DfsPackFileMidx: Add method to translate midx position to objectId
  MultiPackIndex: Add #getObjectAt to translate position to id
  MultiPackIndex: implement methods for the reverse index
  Update python dependencies of download_release.py
  Prepare 7.6.0-SNAPSHOT builds
  JGit v7.6.0.202601071437-m1
  Update Maven plugins
  Update compiler versions
  MultiPackIndexLoader: do not ignore the ridx chunk
  MultiPackIndexWriter: write "bitmapped packfiles" chunk
  Add target platform jgit-4.39 for 2025-03
  Switch to 4.38 release URL of release train p2 repo
  Update mockito to 5.21.0
  Fix invalid HTML closing tag in javadoc
  Document how to test new release staged on Maven Central Portal
  MidxPackFilter: Keep max one midx in the stack
  DfsPackFileMidx: Introduce single-pack midx

Change-Id: I5e6ab8ccfa74b79812f4b6d78bfd515acdd36a5a
diff --git a/.bazelrc b/.bazelrc
index 5bf3ef8..385a71d 100644
--- a/.bazelrc
+++ b/.bazelrc
@@ -1,6 +1,6 @@
 # TODO(davido): Migrate all dependencies from WORKSPACE to MODULE.bazel
 # https://issues.gerritcodereview.com/issues/303819949
-common --enable_bzlmod
+common --enable_bzlmod --lockfile_mode=error
 common --enable_workspace
 
 build --workspace_status_command="python3 ./tools/workspace_status.py"
diff --git a/Documentation/config-options.md b/Documentation/config-options.md
index 20c2b58..3d48115 100644
--- a/Documentation/config-options.md
+++ b/Documentation/config-options.md
@@ -80,6 +80,7 @@
 | `gc.autoDetach` | `true` |  ✅ | Make auto gc return immediately and run in background. |
 | `gc.autoPackLimit` | `50` |  ✅ | Number of packs until auto gc consolidates existing packs (except those marked with a .keep file) into a single pack. Setting `gc.autoPackLimit` to 0 disables automatic consolidation of packs. |
 | `gc.logExpiry` | `1.day.ago` | ✅ | If the file `gc.log` exists, then auto gc will print its content and exit successfully instead of running unless that file is more than `gc.logExpiry` old. |
+| `gc.packRefs`| `true` | ✅ | This variable determines whether JGit garbage collection will also pack refs. This can be set to `notbare` to enable it within all non-bare repos or it can be set to a boolean value. |
 | `gc.pruneExpire` | `2.weeks.ago` | ✅ | Grace period after which unreachable objects will be pruned. |
 | `gc.prunePackExpire` | `1.hour.ago` |  ⃞ | Grace period after which packfiles only containing unreachable objects will be pruned. |
 | `gc.writeChangedPaths` | `false`| ⃞ | Whether bloom filter should be written to commit-graph during a gc operation. |
diff --git a/MODULE.bazel b/MODULE.bazel
index 7ce6136..26c36a1 100644
--- a/MODULE.bazel
+++ b/MODULE.bazel
@@ -1,7 +1,7 @@
 module(name = "jgit")
 
 bazel_dep(name = "rules_java", version = "8.11.0")
-bazel_dep(name = "rules_jvm_external", version = "6.7")
+bazel_dep(name = "rules_jvm_external", version = "6.10")
 bazel_dep(name = "rbe_autoconfig")
 git_override(
     module_name = "rbe_autoconfig",
@@ -23,7 +23,7 @@
 
 BOUNCYCASTLE_VERSION = "1.83"
 
-BYTE_BUDDY_VERSION = "1.18.2"
+BYTE_BUDDY_VERSION = "1.18.4"
 
 JETTY_VERSION = "12.1.5"
 
@@ -33,15 +33,15 @@
 
 SLF4J_VERSION = "2.0.17"
 
-SSHD_VERSION = "2.16.0"
+SSHD_VERSION = "2.17.1"
 
 maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven")
 maven.install(
-    name = "jgit_deps",
+    name = "external_deps",
     artifacts = [
         "args4j:args4j:2.37",
         "com.google.code.gson:gson:2.13.2",
-        "com.google.errorprone:error_prone_type_annotations:2.38.0",
+        "com.google.errorprone:error_prone_type_annotations:2.46.0",
         "com.googlecode.javaewah:JavaEWAH:1.2.3",
         "com.jcraft:jsch:0.1.55",
         "com.jcraft:jzlib:1.1.3",
@@ -62,7 +62,7 @@
         "org.apache.httpcomponents:httpcore:4.4.16",
         "org.apache.sshd:sshd-osgi:" + SSHD_VERSION,
         "org.apache.sshd:sshd-sftp:" + SSHD_VERSION,
-        "org.assertj:assertj-core:3.27.6",
+        "org.assertj:assertj-core:3.27.7",
         "org.bouncycastle:bcpg-jdk18on:" + BOUNCYCASTLE_VERSION,
         "org.bouncycastle:bcpkix-jdk18on:" + BOUNCYCASTLE_VERSION,
         "org.bouncycastle:bcprov-jdk18on:" + BOUNCYCASTLE_VERSION,
@@ -78,7 +78,7 @@
         "org.eclipse.jetty.ee8:jetty-ee8-security:" + JETTY_VERSION,
         "org.eclipse.jetty.ee8:jetty-ee8-servlet:" + JETTY_VERSION,
         "org.hamcrest:hamcrest:3.0",
-        "org.mockito:mockito-core:5.20.0",
+        "org.mockito:mockito-core:5.21.0",
         "org.objenesis:objenesis:3.4",
         "org.openjdk.jmh:jmh-core:" + JMH_VERSION,
         "org.openjdk.jmh:jmh-generator-annprocess:" + JMH_VERSION,
@@ -89,9 +89,10 @@
     duplicate_version_warning = "warn",
     fail_on_missing_checksum = True,
     fetch_sources = True,
+    known_contributing_modules = ["jgit"],
     repositories = [
         "https://repo1.maven.org/maven2",
     ],
     strict_visibility = True,
 )
-use_repo(maven, "jgit_deps")
+use_repo(maven, "external_deps")
diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock
index b6cdace..5717851 100644
--- a/MODULE.bazel.lock
+++ b/MODULE.bazel.lock
@@ -6,35 +6,76 @@
     "https://bcr.bazel.build/modules/abseil-cpp/20211102.0/MODULE.bazel": "70390338f7a5106231d20620712f7cccb659cd0e9d073d1991c038eb9fc57589",
     "https://bcr.bazel.build/modules/abseil-cpp/20230125.1/MODULE.bazel": "89047429cb0207707b2dface14ba7f8df85273d484c2572755be4bab7ce9c3a0",
     "https://bcr.bazel.build/modules/abseil-cpp/20230802.0.bcr.1/MODULE.bazel": "1c8cec495288dccd14fdae6e3f95f772c1c91857047a098fad772034264cc8cb",
+    "https://bcr.bazel.build/modules/abseil-cpp/20230802.0/MODULE.bazel": "d253ae36a8bd9ee3c5955384096ccb6baf16a1b1e93e858370da0a3b94f77c16",
     "https://bcr.bazel.build/modules/abseil-cpp/20230802.1/MODULE.bazel": "fa92e2eb41a04df73cdabeec37107316f7e5272650f81d6cc096418fe647b915",
-    "https://bcr.bazel.build/modules/abseil-cpp/20230802.1/source.json": "035b6f1911e17340db722bbc9158f830ee6d5dedba4cb3bcb9e25e590808a32c",
+    "https://bcr.bazel.build/modules/abseil-cpp/20240116.1/MODULE.bazel": "37bcdb4440fbb61df6a1c296ae01b327f19e9bb521f9b8e26ec854b6f97309ed",
+    "https://bcr.bazel.build/modules/abseil-cpp/20240116.2/MODULE.bazel": "73939767a4686cd9a520d16af5ab440071ed75cec1a876bf2fcfaf1f71987a16",
+    "https://bcr.bazel.build/modules/abseil-cpp/20250127.0/MODULE.bazel": "d1086e248cda6576862b4b3fe9ad76a214e08c189af5b42557a6e1888812c5d5",
+    "https://bcr.bazel.build/modules/abseil-cpp/20250127.0/source.json": "1b996859f840d8efc7c720efc61dcf2a84b1261cb3974cbbe9b6666ebf567775",
+    "https://bcr.bazel.build/modules/abseil-py/2.1.0/MODULE.bazel": "5ebe5bf853769c65707e5c28f216798f7a4b1042015e6a36e6d03094d94bec8a",
+    "https://bcr.bazel.build/modules/abseil-py/2.1.0/source.json": "0e8fc4f088ce07099c1cd6594c20c7ddbb48b4b3c0849b7d94ba94be88ff042b",
+    "https://bcr.bazel.build/modules/apple_support/1.11.1/MODULE.bazel": "1843d7cd8a58369a444fc6000e7304425fba600ff641592161d9f15b179fb896",
+    "https://bcr.bazel.build/modules/apple_support/1.15.1/MODULE.bazel": "a0556fefca0b1bb2de8567b8827518f94db6a6e7e7d632b4c48dc5f865bc7c85",
+    "https://bcr.bazel.build/modules/apple_support/1.15.1/source.json": "517f2b77430084c541bc9be2db63fdcbb7102938c5f64c17ee60ffda2e5cf07b",
     "https://bcr.bazel.build/modules/apple_support/1.5.0/MODULE.bazel": "50341a62efbc483e8a2a6aec30994a58749bd7b885e18dd96aa8c33031e558ef",
-    "https://bcr.bazel.build/modules/apple_support/1.5.0/source.json": "eb98a7627c0bc486b57f598ad8da50f6625d974c8f723e9ea71bd39f709c9862",
+    "https://bcr.bazel.build/modules/bazel_features/1.1.0/MODULE.bazel": "cfd42ff3b815a5f39554d97182657f8c4b9719568eb7fded2b9135f084bf760b",
+    "https://bcr.bazel.build/modules/bazel_features/1.1.1/MODULE.bazel": "27b8c79ef57efe08efccbd9dd6ef70d61b4798320b8d3c134fd571f78963dbcd",
     "https://bcr.bazel.build/modules/bazel_features/1.11.0/MODULE.bazel": "f9382337dd5a474c3b7d334c2f83e50b6eaedc284253334cf823044a26de03e8",
+    "https://bcr.bazel.build/modules/bazel_features/1.13.0/MODULE.bazel": "c14c33c7c3c730612bdbe14ebbb5e61936b6f11322ea95a6e91cd1ba962f94df",
+    "https://bcr.bazel.build/modules/bazel_features/1.15.0/MODULE.bazel": "d38ff6e517149dc509406aca0db3ad1efdd890a85e049585b7234d04238e2a4d",
     "https://bcr.bazel.build/modules/bazel_features/1.17.0/MODULE.bazel": "039de32d21b816b47bd42c778e0454217e9c9caac4a3cf8e15c7231ee3ddee4d",
     "https://bcr.bazel.build/modules/bazel_features/1.18.0/MODULE.bazel": "1be0ae2557ab3a72a57aeb31b29be347bcdc5d2b1eb1e70f39e3851a7e97041a",
     "https://bcr.bazel.build/modules/bazel_features/1.19.0/MODULE.bazel": "59adcdf28230d220f0067b1f435b8537dd033bfff8db21335ef9217919c7fb58",
+    "https://bcr.bazel.build/modules/bazel_features/1.21.0/MODULE.bazel": "675642261665d8eea09989aa3b8afb5c37627f1be178382c320d1b46afba5e3b",
+    "https://bcr.bazel.build/modules/bazel_features/1.23.0/MODULE.bazel": "fd1ac84bc4e97a5a0816b7fd7d4d4f6d837b0047cf4cbd81652d616af3a6591a",
     "https://bcr.bazel.build/modules/bazel_features/1.28.0/MODULE.bazel": "4b4200e6cbf8fa335b2c3f43e1d6ef3e240319c33d43d60cc0fbd4b87ece299d",
-    "https://bcr.bazel.build/modules/bazel_features/1.28.0/source.json": "16a3fc5b4483cb307643791f5a4b7365fa98d2e70da7c378cdbde55f0c0b32cf",
+    "https://bcr.bazel.build/modules/bazel_features/1.3.0/MODULE.bazel": "cdcafe83ec318cda34e02948e81d790aab8df7a929cec6f6969f13a489ccecd9",
+    "https://bcr.bazel.build/modules/bazel_features/1.30.0/MODULE.bazel": "a14b62d05969a293b80257e72e597c2da7f717e1e69fa8b339703ed6731bec87",
+    "https://bcr.bazel.build/modules/bazel_features/1.30.0/source.json": "b07e17f067fe4f69f90b03b36ef1e08fe0d1f3cac254c1241a1818773e3423bc",
     "https://bcr.bazel.build/modules/bazel_features/1.4.1/MODULE.bazel": "e45b6bb2350aff3e442ae1111c555e27eac1d915e77775f6fdc4b351b758b5d7",
+    "https://bcr.bazel.build/modules/bazel_features/1.9.1/MODULE.bazel": "8f679097876a9b609ad1f60249c49d68bfab783dd9be012faf9d82547b14815a",
     "https://bcr.bazel.build/modules/bazel_skylib/1.0.3/MODULE.bazel": "bcb0fd896384802d1ad283b4e4eb4d718eebd8cb820b0a2c3a347fb971afd9d8",
+    "https://bcr.bazel.build/modules/bazel_skylib/1.1.1/MODULE.bazel": "1add3e7d93ff2e6998f9e118022c84d163917d912f5afafb3058e3d2f1545b5e",
     "https://bcr.bazel.build/modules/bazel_skylib/1.2.0/MODULE.bazel": "44fe84260e454ed94ad326352a698422dbe372b21a1ac9f3eab76eb531223686",
     "https://bcr.bazel.build/modules/bazel_skylib/1.2.1/MODULE.bazel": "f35baf9da0efe45fa3da1696ae906eea3d615ad41e2e3def4aeb4e8bc0ef9a7a",
     "https://bcr.bazel.build/modules/bazel_skylib/1.3.0/MODULE.bazel": "20228b92868bf5cfc41bda7afc8a8ba2a543201851de39d990ec957b513579c5",
     "https://bcr.bazel.build/modules/bazel_skylib/1.4.1/MODULE.bazel": "a0dcb779424be33100dcae821e9e27e4f2901d9dfd5333efe5ac6a8d7ab75e1d",
+    "https://bcr.bazel.build/modules/bazel_skylib/1.4.2/MODULE.bazel": "3bd40978e7a1fac911d5989e6b09d8f64921865a45822d8b09e815eaa726a651",
     "https://bcr.bazel.build/modules/bazel_skylib/1.5.0/MODULE.bazel": "32880f5e2945ce6a03d1fbd588e9198c0a959bb42297b2cfaf1685b7bc32e138",
     "https://bcr.bazel.build/modules/bazel_skylib/1.6.1/MODULE.bazel": "8fdee2dbaace6c252131c00e1de4b165dc65af02ea278476187765e1a617b917",
+    "https://bcr.bazel.build/modules/bazel_skylib/1.7.0/MODULE.bazel": "0db596f4563de7938de764cc8deeabec291f55e8ec15299718b93c4423e9796d",
     "https://bcr.bazel.build/modules/bazel_skylib/1.7.1/MODULE.bazel": "3120d80c5861aa616222ec015332e5f8d3171e062e3e804a2a0253e1be26e59b",
     "https://bcr.bazel.build/modules/bazel_skylib/1.7.1/source.json": "f121b43eeefc7c29efbd51b83d08631e2347297c95aac9764a701f2a6a2bb953",
+    "https://bcr.bazel.build/modules/bazel_worker_api/0.0.1/MODULE.bazel": "02a13b77321773b2042e70ee5e4c5e099c8ddee4cf2da9cd420442c36938d4bd",
+    "https://bcr.bazel.build/modules/bazel_worker_api/0.0.4/MODULE.bazel": "460aa12d01231a80cce03c548287b433b321d205b0028ae596728c35e5ee442e",
+    "https://bcr.bazel.build/modules/bazel_worker_api/0.0.4/source.json": "d353c410d47a8b65d09fa98e83d57ebec257a2c2b9c6e42d6fda1cb25e5464a5",
+    "https://bcr.bazel.build/modules/bazel_worker_java/0.0.4/MODULE.bazel": "82494a01018bb7ef06d4a17ec4cd7a758721f10eb8b6c820a818e70d669500db",
+    "https://bcr.bazel.build/modules/bazel_worker_java/0.0.4/source.json": "a2d30458fd86cf022c2b6331e652526fa08e17573b2f5034a9dbcacdf9c2583c",
     "https://bcr.bazel.build/modules/buildozer/7.1.2/MODULE.bazel": "2e8dd40ede9c454042645fd8d8d0cd1527966aa5c919de86661e62953cd73d84",
     "https://bcr.bazel.build/modules/buildozer/7.1.2/source.json": "c9028a501d2db85793a6996205c8de120944f50a0d570438fcae0457a5f9d1f8",
+    "https://bcr.bazel.build/modules/gazelle/0.32.0/MODULE.bazel": "b499f58a5d0d3537f3cf5b76d8ada18242f64ec474d8391247438bf04f58c7b8",
+    "https://bcr.bazel.build/modules/gazelle/0.33.0/MODULE.bazel": "a13a0f279b462b784fb8dd52a4074526c4a2afe70e114c7d09066097a46b3350",
+    "https://bcr.bazel.build/modules/gazelle/0.34.0/MODULE.bazel": "abdd8ce4d70978933209db92e436deb3a8b737859e9354fb5fd11fb5c2004c8a",
+    "https://bcr.bazel.build/modules/gazelle/0.36.0/MODULE.bazel": "e375d5d6e9a6ca59b0cb38b0540bc9a05b6aa926d322f2de268ad267a2ee74c0",
+    "https://bcr.bazel.build/modules/gazelle/0.40.0/MODULE.bazel": "42ba5378ebe845fca43989a53186ab436d956db498acde790685fe0e8f9c6146",
+    "https://bcr.bazel.build/modules/gazelle/0.40.0/source.json": "1e5ef6e4d8b9b6836d93273c781e78ff829ea2e077afef7a57298040fa4f010a",
+    "https://bcr.bazel.build/modules/google_benchmark/1.8.2/MODULE.bazel": "a70cf1bba851000ba93b58ae2f6d76490a9feb74192e57ab8e8ff13c34ec50cb",
     "https://bcr.bazel.build/modules/googletest/1.11.0/MODULE.bazel": "3a83f095183f66345ca86aa13c58b59f9f94a2f81999c093d4eeaa2d262d12f4",
+    "https://bcr.bazel.build/modules/googletest/1.14.0.bcr.1/MODULE.bazel": "22c31a561553727960057361aa33bf20fb2e98584bc4fec007906e27053f80c6",
     "https://bcr.bazel.build/modules/googletest/1.14.0/MODULE.bazel": "cfbcbf3e6eac06ef9d85900f64424708cc08687d1b527f0ef65aa7517af8118f",
-    "https://bcr.bazel.build/modules/googletest/1.14.0/source.json": "2478949479000fdd7de9a3d0107ba2c85bb5f961c3ecb1aa448f52549ce310b5",
+    "https://bcr.bazel.build/modules/googletest/1.15.2/MODULE.bazel": "6de1edc1d26cafb0ea1a6ab3f4d4192d91a312fd2d360b63adaa213cd00b2108",
+    "https://bcr.bazel.build/modules/googletest/1.15.2/source.json": "dbdda654dcb3a0d7a8bc5d0ac5fc7e150b58c2a986025ae5bc634bb2cb61f470",
     "https://bcr.bazel.build/modules/jsoncpp/1.9.5/MODULE.bazel": "31271aedc59e815656f5736f282bb7509a97c7ecb43e927ac1a37966e0578075",
-    "https://bcr.bazel.build/modules/jsoncpp/1.9.5/source.json": "4108ee5085dd2885a341c7fab149429db457b3169b86eb081fa245eadf69169d",
+    "https://bcr.bazel.build/modules/jsoncpp/1.9.6/MODULE.bazel": "2f8d20d3b7d54143213c4dfc3d98225c42de7d666011528dc8fe91591e2e17b0",
+    "https://bcr.bazel.build/modules/jsoncpp/1.9.6/source.json": "a04756d367a2126c3541682864ecec52f92cdee80a35735a3cb249ce015ca000",
+    "https://bcr.bazel.build/modules/libpfm/4.11.0/MODULE.bazel": "45061ff025b301940f1e30d2c16bea596c25b176c8b6b3087e92615adbd52902",
+    "https://bcr.bazel.build/modules/nlohmann_json/3.6.1/MODULE.bazel": "6f7b417dcc794d9add9e556673ad25cb3ba835224290f4f848f8e2db1e1fca74",
+    "https://bcr.bazel.build/modules/nlohmann_json/3.6.1/source.json": "f448c6e8963fdfa7eb831457df83ad63d3d6355018f6574fb017e8169deb43a9",
+    "https://bcr.bazel.build/modules/package_metadata/0.0.7/MODULE.bazel": "7adb03933fc8401f495800cf4eafcff0edc6da0ff55c7db223ef69d19f689486",
+    "https://bcr.bazel.build/modules/package_metadata/0.0.7/source.json": "50639625e937b56115012674c797cca7a05a96b4878c87d803c13dc2b31de8a0",
     "https://bcr.bazel.build/modules/platforms/0.0.10/MODULE.bazel": "8cb8efaf200bdeb2150d93e162c40f388529a25852b332cec879373771e48ed5",
-    "https://bcr.bazel.build/modules/platforms/0.0.10/source.json": "f22828ff4cf021a6b577f1bf6341cb9dcd7965092a439f64fc1bb3b7a5ae4bd5",
+    "https://bcr.bazel.build/modules/platforms/0.0.11/MODULE.bazel": "0daefc49732e227caa8bfa834d65dc52e8cc18a2faf80df25e8caea151a9413f",
+    "https://bcr.bazel.build/modules/platforms/0.0.11/source.json": "f7e188b79ebedebfe75e9e1d098b8845226c7992b307e28e1496f23112e8fc29",
     "https://bcr.bazel.build/modules/platforms/0.0.4/MODULE.bazel": "9b328e31ee156f53f3c416a64f8491f7eb731742655a47c9eec4703a71644aee",
     "https://bcr.bazel.build/modules/platforms/0.0.5/MODULE.bazel": "5733b54ea419d5eaf7997054bb55f6a1d0b5ff8aedf0176fef9eea44f3acda37",
     "https://bcr.bazel.build/modules/platforms/0.0.6/MODULE.bazel": "ad6eeef431dc52aefd2d77ed20a4b353f8ebf0f4ecdd26a807d2da5aa8cd0615",
@@ -42,68 +83,141 @@
     "https://bcr.bazel.build/modules/platforms/0.0.8/MODULE.bazel": "9f142c03e348f6d263719f5074b21ef3adf0b139ee4c5133e2aa35664da9eb2d",
     "https://bcr.bazel.build/modules/platforms/0.0.9/MODULE.bazel": "4a87a60c927b56ddd67db50c89acaa62f4ce2a1d2149ccb63ffd871d5ce29ebc",
     "https://bcr.bazel.build/modules/protobuf/21.7/MODULE.bazel": "a5a29bb89544f9b97edce05642fac225a808b5b7be74038ea3640fae2f8e66a7",
+    "https://bcr.bazel.build/modules/protobuf/23.1/MODULE.bazel": "88b393b3eb4101d18129e5db51847cd40a5517a53e81216144a8c32dfeeca52a",
+    "https://bcr.bazel.build/modules/protobuf/24.4/MODULE.bazel": "7bc7ce5f2abf36b3b7b7c8218d3acdebb9426aeb35c2257c96445756f970eb12",
     "https://bcr.bazel.build/modules/protobuf/27.0/MODULE.bazel": "7873b60be88844a0a1d8f80b9d5d20cfbd8495a689b8763e76c6372998d3f64c",
-    "https://bcr.bazel.build/modules/protobuf/27.0/source.json": "1acf3d080c728d42f423fde5422fd0a1a24f44c15908124ce12363a253384193",
+    "https://bcr.bazel.build/modules/protobuf/27.1/MODULE.bazel": "703a7b614728bb06647f965264967a8ef1c39e09e8f167b3ca0bb1fd80449c0d",
+    "https://bcr.bazel.build/modules/protobuf/27.2/MODULE.bazel": "32450b50673882e4c8c3d10a83f3bc82161b213ed2f80d17e38bece8f165c295",
+    "https://bcr.bazel.build/modules/protobuf/29.0-rc2/MODULE.bazel": "6241d35983510143049943fc0d57937937122baf1b287862f9dc8590fc4c37df",
+    "https://bcr.bazel.build/modules/protobuf/29.0-rc3/MODULE.bazel": "33c2dfa286578573afc55a7acaea3cada4122b9631007c594bf0729f41c8de92",
     "https://bcr.bazel.build/modules/protobuf/3.19.0/MODULE.bazel": "6b5fbb433f760a99a22b18b6850ed5784ef0e9928a72668b66e4d7ccd47db9b0",
+    "https://bcr.bazel.build/modules/protobuf/3.19.2/MODULE.bazel": "532ffe5f2186b69fdde039efe6df13ba726ff338c6bc82275ad433013fa10573",
     "https://bcr.bazel.build/modules/protobuf/3.19.6/MODULE.bazel": "9233edc5e1f2ee276a60de3eaa47ac4132302ef9643238f23128fea53ea12858",
+    "https://bcr.bazel.build/modules/protobuf/31.1/MODULE.bazel": "379a389bb330b7b8c1cdf331cc90bf3e13de5614799b3b52cdb7c6f389f6b38e",
+    "https://bcr.bazel.build/modules/protobuf/31.1/source.json": "25af5d0219da0c0fc4d1191a24ce438e6ca7f49d2e1a94f354efeba6ef10426f",
+    "https://bcr.bazel.build/modules/pybind11_bazel/2.11.1/MODULE.bazel": "88af1c246226d87e65be78ed49ecd1e6f5e98648558c14ce99176da041dc378e",
+    "https://bcr.bazel.build/modules/pybind11_bazel/2.12.0/MODULE.bazel": "e6f4c20442eaa7c90d7190d8dc539d0ab422f95c65a57cc59562170c58ae3d34",
+    "https://bcr.bazel.build/modules/pybind11_bazel/2.12.0/source.json": "6900fdc8a9e95866b8c0d4ad4aba4d4236317b5c1cd04c502df3f0d33afed680",
+    "https://bcr.bazel.build/modules/re2/2023-09-01/MODULE.bazel": "cb3d511531b16cfc78a225a9e2136007a48cf8a677e4264baeab57fe78a80206",
+    "https://bcr.bazel.build/modules/re2/2024-07-02.bcr.1/MODULE.bazel": "b4963dda9b31080be1905ef085ecd7dd6cd47c05c79b9cdf83ade83ab2ab271a",
+    "https://bcr.bazel.build/modules/re2/2024-07-02.bcr.1/source.json": "2ff292be6ef3340325ce8a045ecc326e92cbfab47c7cbab4bd85d28971b97ac4",
+    "https://bcr.bazel.build/modules/re2/2024-07-02/MODULE.bazel": "0eadc4395959969297cbcf31a249ff457f2f1d456228c67719480205aa306daa",
     "https://bcr.bazel.build/modules/rules_android/0.1.1/MODULE.bazel": "48809ab0091b07ad0182defb787c4c5328bd3a278938415c00a7b69b50c4d3a8",
-    "https://bcr.bazel.build/modules/rules_android/0.1.1/source.json": "e6986b41626ee10bdc864937ffb6d6bf275bb5b9c65120e6137d56e6331f089e",
+    "https://bcr.bazel.build/modules/rules_android/0.6.6/MODULE.bazel": "b0fb569752aab65ab1a9db0a8f6cfaf5aa1754965e17e95dcf0e4d88e192a68d",
+    "https://bcr.bazel.build/modules/rules_android/0.6.6/source.json": "a9d8dc2d5a102dc03269a94acc886a4cab82cdcb9ccbc77b0f665d6d17a6ae09",
+    "https://bcr.bazel.build/modules/rules_apple/3.16.0/MODULE.bazel": "0d1caf0b8375942ce98ea944be754a18874041e4e0459401d925577624d3a54a",
+    "https://bcr.bazel.build/modules/rules_apple/3.16.0/source.json": "d8b5fe461272018cc07cfafce11fe369c7525330804c37eec5a82f84cd475366",
     "https://bcr.bazel.build/modules/rules_cc/0.0.1/MODULE.bazel": "cb2aa0747f84c6c3a78dad4e2049c154f08ab9d166b1273835a8174940365647",
     "https://bcr.bazel.build/modules/rules_cc/0.0.10/MODULE.bazel": "ec1705118f7eaedd6e118508d3d26deba2a4e76476ada7e0e3965211be012002",
+    "https://bcr.bazel.build/modules/rules_cc/0.0.13/MODULE.bazel": "0e8529ed7b323dad0775ff924d2ae5af7640b23553dfcd4d34344c7e7a867191",
     "https://bcr.bazel.build/modules/rules_cc/0.0.15/MODULE.bazel": "6704c35f7b4a72502ee81f61bf88706b54f06b3cbe5558ac17e2e14666cd5dcc",
+    "https://bcr.bazel.build/modules/rules_cc/0.0.16/MODULE.bazel": "7661303b8fc1b4d7f532e54e9d6565771fea666fbdf839e0a86affcd02defe87",
+    "https://bcr.bazel.build/modules/rules_cc/0.0.17/MODULE.bazel": "2ae1d8f4238ec67d7185d8861cb0a2cdf4bc608697c331b95bf990e69b62e64a",
     "https://bcr.bazel.build/modules/rules_cc/0.0.2/MODULE.bazel": "6915987c90970493ab97393024c156ea8fb9f3bea953b2f3ec05c34f19b5695c",
     "https://bcr.bazel.build/modules/rules_cc/0.0.6/MODULE.bazel": "abf360251023dfe3efcef65ab9d56beefa8394d4176dd29529750e1c57eaa33f",
     "https://bcr.bazel.build/modules/rules_cc/0.0.8/MODULE.bazel": "964c85c82cfeb6f3855e6a07054fdb159aced38e99a5eecf7bce9d53990afa3e",
     "https://bcr.bazel.build/modules/rules_cc/0.0.9/MODULE.bazel": "836e76439f354b89afe6a911a7adf59a6b2518fafb174483ad78a2a2fde7b1c5",
+    "https://bcr.bazel.build/modules/rules_cc/0.1.1/MODULE.bazel": "2f0222a6f229f0bf44cd711dc13c858dad98c62d52bd51d8fc3a764a83125513",
     "https://bcr.bazel.build/modules/rules_cc/0.2.14/MODULE.bazel": "353c99ed148887ee89c54a17d4100ae7e7e436593d104b668476019023b58df8",
     "https://bcr.bazel.build/modules/rules_cc/0.2.14/source.json": "55d0a4587c5592fad350f6e698530f4faf0e7dd15e69d43f8d87e220c78bea54",
+    "https://bcr.bazel.build/modules/rules_foreign_cc/0.9.0/MODULE.bazel": "c9e8c682bf75b0e7c704166d79b599f93b72cfca5ad7477df596947891feeef6",
+    "https://bcr.bazel.build/modules/rules_fuzzing/0.5.2/MODULE.bazel": "40c97d1144356f52905566c55811f13b299453a14ac7769dfba2ac38192337a8",
+    "https://bcr.bazel.build/modules/rules_go/0.41.0/MODULE.bazel": "55861d8e8bb0e62cbd2896f60ff303f62ffcb0eddb74ecb0e5c0cbe36fc292c8",
+    "https://bcr.bazel.build/modules/rules_go/0.42.0/MODULE.bazel": "8cfa875b9aa8c6fce2b2e5925e73c1388173ea3c32a0db4d2b4804b453c14270",
+    "https://bcr.bazel.build/modules/rules_go/0.46.0/MODULE.bazel": "3477df8bdcc49e698b9d25f734c4f3a9f5931ff34ee48a2c662be168f5f2d3fd",
+    "https://bcr.bazel.build/modules/rules_go/0.50.1/MODULE.bazel": "b91a308dc5782bb0a8021ad4330c81fea5bda77f96b9e4c117b9b9c8f6665ee0",
+    "https://bcr.bazel.build/modules/rules_go/0.51.0-rc2/MODULE.bazel": "edfc3a9cea7bedb0eaaff37b0d7817c1a4bf72b3c615580b0ffcee6c52690fd4",
+    "https://bcr.bazel.build/modules/rules_go/0.51.0-rc2/source.json": "6b5cd0b3da2bd0e6949580851db990a04af0a285f072b9a0f059424457cd8cc9",
     "https://bcr.bazel.build/modules/rules_java/4.0.0/MODULE.bazel": "5a78a7ae82cd1a33cef56dc578c7d2a46ed0dca12643ee45edbb8417899e6f74",
     "https://bcr.bazel.build/modules/rules_java/5.3.5/MODULE.bazel": "a4ec4f2db570171e3e5eb753276ee4b389bae16b96207e9d3230895c99644b86",
+    "https://bcr.bazel.build/modules/rules_java/6.3.0/MODULE.bazel": "a97c7678c19f236a956ad260d59c86e10a463badb7eb2eda787490f4c969b963",
+    "https://bcr.bazel.build/modules/rules_java/6.5.2/MODULE.bazel": "1d440d262d0e08453fa0c4d8f699ba81609ed0e9a9a0f02cd10b3e7942e61e31",
+    "https://bcr.bazel.build/modules/rules_java/7.1.0/MODULE.bazel": "30d9135a2b6561c761bd67bd4990da591e6bdc128790ce3e7afd6a3558b2fb64",
+    "https://bcr.bazel.build/modules/rules_java/7.10.0/MODULE.bazel": "530c3beb3067e870561739f1144329a21c851ff771cd752a49e06e3dc9c2e71a",
     "https://bcr.bazel.build/modules/rules_java/7.12.2/MODULE.bazel": "579c505165ee757a4280ef83cda0150eea193eed3bef50b1004ba88b99da6de6",
     "https://bcr.bazel.build/modules/rules_java/7.2.0/MODULE.bazel": "06c0334c9be61e6cef2c8c84a7800cef502063269a5af25ceb100b192453d4ab",
+    "https://bcr.bazel.build/modules/rules_java/7.4.0/MODULE.bazel": "a592852f8a3dd539e82ee6542013bf2cadfc4c6946be8941e189d224500a8934",
     "https://bcr.bazel.build/modules/rules_java/7.6.1/MODULE.bazel": "2f14b7e8a1aa2f67ae92bc69d1ec0fa8d9f827c4e17ff5e5f02e91caa3b2d0fe",
     "https://bcr.bazel.build/modules/rules_java/7.6.5/MODULE.bazel": "481164be5e02e4cab6e77a36927683263be56b7e36fef918b458d7a8a1ebadb1",
     "https://bcr.bazel.build/modules/rules_java/8.11.0/MODULE.bazel": "c3d280bc5ff1038dcb3bacb95d3f6b83da8dd27bba57820ec89ea4085da767ad",
-    "https://bcr.bazel.build/modules/rules_java/8.11.0/source.json": "302b52a39259a85aa06ca3addb9787864ca3e03b432a5f964ea68244397e7544",
+    "https://bcr.bazel.build/modules/rules_java/8.13.0/MODULE.bazel": "0444ebf737d144cf2bb2ccb368e7f1cce735264285f2a3711785827c1686625e",
+    "https://bcr.bazel.build/modules/rules_java/8.13.0/source.json": "4605c0f676b87dd9d1fabd4d743b71f04d97503bd1a79aad53f87399fb5396de",
+    "https://bcr.bazel.build/modules/rules_java/8.3.2/MODULE.bazel": "7336d5511ad5af0b8615fdc7477535a2e4e723a357b6713af439fe8cf0195017",
+    "https://bcr.bazel.build/modules/rules_java/8.5.1/MODULE.bazel": "d8a9e38cc5228881f7055a6079f6f7821a073df3744d441978e7a43e20226939",
+    "https://bcr.bazel.build/modules/rules_java/8.6.0/MODULE.bazel": "9c064c434606d75a086f15ade5edb514308cccd1544c2b2a89bbac4310e41c71",
+    "https://bcr.bazel.build/modules/rules_java/8.6.1/MODULE.bazel": "f4808e2ab5b0197f094cabce9f4b006a27766beb6a9975931da07099560ca9c2",
     "https://bcr.bazel.build/modules/rules_jvm_external/4.4.2/MODULE.bazel": "a56b85e418c83eb1839819f0b515c431010160383306d13ec21959ac412d2fe7",
     "https://bcr.bazel.build/modules/rules_jvm_external/5.1/MODULE.bazel": "33f6f999e03183f7d088c9be518a63467dfd0be94a11d0055fe2d210f89aa909",
     "https://bcr.bazel.build/modules/rules_jvm_external/5.2/MODULE.bazel": "d9351ba35217ad0de03816ef3ed63f89d411349353077348a45348b096615036",
+    "https://bcr.bazel.build/modules/rules_jvm_external/6.10/MODULE.bazel": "33e636ca6bc9ee0fa090a38aa33c631ded2d8cf6fead4124181d1b35dc474f7c",
+    "https://bcr.bazel.build/modules/rules_jvm_external/6.10/source.json": "c191249787625db72616a3fb3cc2786ab57355a2e3b615402b8b3b66b0f995b7",
+    "https://bcr.bazel.build/modules/rules_jvm_external/6.2/MODULE.bazel": "36a6e52487a855f33cb960724eb56547fa87e2c98a0474c3acad94339d7f8e99",
+    "https://bcr.bazel.build/modules/rules_jvm_external/6.3/MODULE.bazel": "c998e060b85f71e00de5ec552019347c8bca255062c990ac02d051bb80a38df0",
+    "https://bcr.bazel.build/modules/rules_jvm_external/6.6/MODULE.bazel": "153042249c7060536dc95b6bb9f9bb8063b8a0b0cb7acdb381bddbc2374aed55",
     "https://bcr.bazel.build/modules/rules_jvm_external/6.7/MODULE.bazel": "e717beabc4d091ecb2c803c2d341b88590e9116b8bf7947915eeb33aab4f96dd",
-    "https://bcr.bazel.build/modules/rules_jvm_external/6.7/source.json": "5426f412d0a7fc6b611643376c7e4a82dec991491b9ce5cb1cfdd25fe2e92be4",
+    "https://bcr.bazel.build/modules/rules_kotlin/1.9.5/MODULE.bazel": "043a16a572f610558ec2030db3ff0c9938574e7dd9f58bded1bb07c0192ef025",
     "https://bcr.bazel.build/modules/rules_kotlin/1.9.6/MODULE.bazel": "d269a01a18ee74d0335450b10f62c9ed81f2321d7958a2934e44272fe82dcef3",
-    "https://bcr.bazel.build/modules/rules_kotlin/1.9.6/source.json": "2faa4794364282db7c06600b7e5e34867a564ae91bda7cae7c29c64e9466b7d5",
+    "https://bcr.bazel.build/modules/rules_kotlin/2.1.3/MODULE.bazel": "ce7def6d576aa8d3a9c6d10e13b4d157296229674371f67dbf788dae0afae3d5",
+    "https://bcr.bazel.build/modules/rules_kotlin/2.1.3/source.json": "0b0dc9400f14b5fbb13d278ad3bf0413cdbaf0da0db337e055b855e35b878a3b",
     "https://bcr.bazel.build/modules/rules_license/0.0.3/MODULE.bazel": "627e9ab0247f7d1e05736b59dbb1b6871373de5ad31c3011880b4133cafd4bd0",
     "https://bcr.bazel.build/modules/rules_license/0.0.7/MODULE.bazel": "088fbeb0b6a419005b89cf93fe62d9517c0a2b8bb56af3244af65ecfe37e7d5d",
     "https://bcr.bazel.build/modules/rules_license/1.0.0/MODULE.bazel": "a7fda60eefdf3d8c827262ba499957e4df06f659330bbe6cdbdb975b768bb65c",
     "https://bcr.bazel.build/modules/rules_license/1.0.0/source.json": "a52c89e54cc311196e478f8382df91c15f7a2bfdf4c6cd0e2675cc2ff0b56efb",
     "https://bcr.bazel.build/modules/rules_pkg/0.7.0/MODULE.bazel": "df99f03fc7934a4737122518bb87e667e62d780b610910f0447665a7e2be62dc",
-    "https://bcr.bazel.build/modules/rules_pkg/0.7.0/source.json": "c2557066e0c0342223ba592510ad3d812d4963b9024831f7f66fd0584dd8c66c",
+    "https://bcr.bazel.build/modules/rules_pkg/1.0.1/MODULE.bazel": "5b1df97dbc29623bccdf2b0dcd0f5cb08e2f2c9050aab1092fd39a41e82686ff",
+    "https://bcr.bazel.build/modules/rules_pkg/1.0.1/source.json": "bd82e5d7b9ce2d31e380dd9f50c111d678c3bdaca190cb76b0e1c71b05e1ba8a",
     "https://bcr.bazel.build/modules/rules_proto/4.0.0/MODULE.bazel": "a7a7b6ce9bee418c1a760b3d84f83a299ad6952f9903c67f19e4edd964894e06",
     "https://bcr.bazel.build/modules/rules_proto/5.3.0-21.7/MODULE.bazel": "e8dff86b0971688790ae75528fe1813f71809b5afd57facb44dad9e8eca631b7",
+    "https://bcr.bazel.build/modules/rules_proto/6.0.0-rc1/MODULE.bazel": "1e5b502e2e1a9e825eef74476a5a1ee524a92297085015a052510b09a1a09483",
+    "https://bcr.bazel.build/modules/rules_proto/6.0.0/MODULE.bazel": "b531d7f09f58dce456cd61b4579ce8c86b38544da75184eadaf0a7cb7966453f",
     "https://bcr.bazel.build/modules/rules_proto/6.0.2/MODULE.bazel": "ce916b775a62b90b61888052a416ccdda405212b6aaeb39522f7dc53431a5e73",
-    "https://bcr.bazel.build/modules/rules_proto/6.0.2/source.json": "17a2e195f56cb28d6bbf763e49973d13890487c6945311ed141e196fb660426d",
+    "https://bcr.bazel.build/modules/rules_proto/7.0.2/MODULE.bazel": "bf81793bd6d2ad89a37a40693e56c61b0ee30f7a7fdbaf3eabbf5f39de47dea2",
+    "https://bcr.bazel.build/modules/rules_proto/7.0.2/source.json": "1e5e7260ae32ef4f2b52fd1d0de8d03b606a44c91b694d2f1afb1d3b28a48ce1",
     "https://bcr.bazel.build/modules/rules_python/0.10.2/MODULE.bazel": "cc82bc96f2997baa545ab3ce73f196d040ffb8756fd2d66125a530031cd90e5f",
     "https://bcr.bazel.build/modules/rules_python/0.22.1/MODULE.bazel": "26114f0c0b5e93018c0c066d6673f1a2c3737c7e90af95eff30cfee38d0bbac7",
     "https://bcr.bazel.build/modules/rules_python/0.23.1/MODULE.bazel": "49ffccf0511cb8414de28321f5fcf2a31312b47c40cc21577144b7447f2bf300",
-    "https://bcr.bazel.build/modules/rules_python/0.23.1/source.json": "a6d9965700e3bd75df4e19140c0e651851bb720d8b9eb280ecd1ee44b92d7646",
+    "https://bcr.bazel.build/modules/rules_python/0.25.0/MODULE.bazel": "72f1506841c920a1afec76975b35312410eea3aa7b63267436bfb1dd91d2d382",
+    "https://bcr.bazel.build/modules/rules_python/0.28.0/MODULE.bazel": "cba2573d870babc976664a912539b320cbaa7114cd3e8f053c720171cde331ed",
+    "https://bcr.bazel.build/modules/rules_python/0.31.0/MODULE.bazel": "93a43dc47ee570e6ec9f5779b2e64c1476a6ce921c48cc9a1678a91dd5f8fd58",
+    "https://bcr.bazel.build/modules/rules_python/0.33.2/MODULE.bazel": "3e036c4ad8d804a4dad897d333d8dce200d943df4827cb849840055be8d2e937",
+    "https://bcr.bazel.build/modules/rules_python/0.37.1/MODULE.bazel": "3faeb2d9fa0a81f8980643ee33f212308f4d93eea4b9ce6f36d0b742e71e9500",
+    "https://bcr.bazel.build/modules/rules_python/0.37.2/MODULE.bazel": "b5ffde91410745750b6c13be1c5dc4555ef5bc50562af4a89fd77807fdde626a",
     "https://bcr.bazel.build/modules/rules_python/0.4.0/MODULE.bazel": "9208ee05fd48bf09ac60ed269791cf17fb343db56c8226a720fbb1cdf467166c",
+    "https://bcr.bazel.build/modules/rules_python/1.0.0/MODULE.bazel": "898a3d999c22caa585eb062b600f88654bf92efb204fa346fb55f6f8edffca43",
+    "https://bcr.bazel.build/modules/rules_python/1.0.0/source.json": "b0162a65c6312e45e7912e39abd1a7f8856c2c7e41ecc9b6dc688a6f6400a917",
+    "https://bcr.bazel.build/modules/rules_robolectric/4.14.1.2/MODULE.bazel": "d44fec647d0aeb67b9f3b980cf68ba634976f3ae7ccd6c07d790b59b87a4f251",
+    "https://bcr.bazel.build/modules/rules_robolectric/4.14.1.2/source.json": "37c10335f2361c337c5c1f34ed36d2da70534c23088062b33a8bdaab68aa9dea",
+    "https://bcr.bazel.build/modules/rules_shell/0.1.2/MODULE.bazel": "66e4ca3ce084b04af0b9ff05ff14cab4e5df7503973818bb91cbc6cda08d32fc",
+    "https://bcr.bazel.build/modules/rules_shell/0.2.0/MODULE.bazel": "fda8a652ab3c7d8fee214de05e7a9916d8b28082234e8d2c0094505c5268ed3c",
     "https://bcr.bazel.build/modules/rules_shell/0.3.0/MODULE.bazel": "de4402cd12f4cc8fda2354fce179fdb068c0b9ca1ec2d2b17b3e21b24c1a937b",
-    "https://bcr.bazel.build/modules/rules_shell/0.3.0/source.json": "c55ed591aa5009401ddf80ded9762ac32c358d2517ee7820be981e2de9756cf3",
+    "https://bcr.bazel.build/modules/rules_shell/0.4.1/MODULE.bazel": "00e501db01bbf4e3e1dd1595959092c2fadf2087b2852d3f553b5370f5633592",
+    "https://bcr.bazel.build/modules/rules_shell/0.4.1/source.json": "4757bd277fe1567763991c4425b483477bb82e35e777a56fd846eb5cceda324a",
+    "https://bcr.bazel.build/modules/rules_swift/1.16.0/MODULE.bazel": "4a09f199545a60d09895e8281362b1ff3bb08bbde69c6fc87aff5b92fcc916ca",
+    "https://bcr.bazel.build/modules/rules_swift/2.1.1/MODULE.bazel": "494900a80f944fc7aa61500c2073d9729dff0b764f0e89b824eb746959bc1046",
+    "https://bcr.bazel.build/modules/rules_swift/2.1.1/source.json": "40fc69dfaac64deddbb75bd99cdac55f4427d9ca0afbe408576a65428427a186",
     "https://bcr.bazel.build/modules/stardoc/0.5.1/MODULE.bazel": "1a05d92974d0c122f5ccf09291442580317cdd859f07a8655f1db9a60374f9f8",
     "https://bcr.bazel.build/modules/stardoc/0.5.3/MODULE.bazel": "c7f6948dae6999bf0db32c1858ae345f112cacf98f174c7a8bb707e41b974f1c",
+    "https://bcr.bazel.build/modules/stardoc/0.6.2/MODULE.bazel": "7060193196395f5dd668eda046ccbeacebfd98efc77fed418dbe2b82ffaa39fd",
     "https://bcr.bazel.build/modules/stardoc/0.7.0/MODULE.bazel": "05e3d6d30c099b6770e97da986c53bd31844d7f13d41412480ea265ac9e8079c",
+    "https://bcr.bazel.build/modules/stardoc/0.7.2/MODULE.bazel": "fc152419aa2ea0f51c29583fab1e8c99ddefd5b3778421845606ee628629e0e5",
+    "https://bcr.bazel.build/modules/stardoc/0.7.2/source.json": "58b029e5e901d6802967754adf0a9056747e8176f017cfe3607c0851f4d42216",
+    "https://bcr.bazel.build/modules/swift_argument_parser/1.3.1.1/MODULE.bazel": "5e463fbfba7b1701d957555ed45097d7f984211330106ccd1352c6e0af0dcf91",
+    "https://bcr.bazel.build/modules/swift_argument_parser/1.3.1.1/source.json": "32bd87e5f4d7acc57c5b2ff7c325ae3061d5e242c0c4c214ae87e0f1c13e54cb",
     "https://bcr.bazel.build/modules/upb/0.0.0-20220923-a547704/MODULE.bazel": "7298990c00040a0e2f121f6c32544bab27d4452f80d9ce51349b1a28f3005c43",
+    "https://bcr.bazel.build/modules/upb/0.0.0-20230516-61a97ef/MODULE.bazel": "c0df5e35ad55e264160417fd0875932ee3c9dda63d9fccace35ac62f45e1b6f9",
     "https://bcr.bazel.build/modules/zlib/1.2.11/MODULE.bazel": "07b389abc85fdbca459b69e2ec656ae5622873af3f845e1c9d80fe179f3effa0",
     "https://bcr.bazel.build/modules/zlib/1.2.12/MODULE.bazel": "3b1a8834ada2a883674be8cbd36ede1b6ec481477ada359cd2d3ddc562340b27",
     "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.3/MODULE.bazel": "af322bc08976524477c79d1e45e241b6efbeb918c497e8840b8ab116802dda79",
-    "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.3/source.json": "2be409ac3c7601245958cd4fcdff4288be79ed23bd690b4b951f500d54ee6e7d"
+    "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.5/MODULE.bazel": "eec517b5bbe5492629466e11dae908d043364302283de25581e3eb944326c4ca",
+    "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.5/source.json": "22bc55c47af97246cfc093d0acf683a7869377de362b5d1c552c2c2e16b7a806",
+    "https://bcr.bazel.build/modules/zlib/1.3.1/MODULE.bazel": "751c9940dcfe869f5f7274e1295422a34623555916eb98c174c1e945594bf198"
   },
   "selectedYankedVersions": {},
   "moduleExtensions": {
     "@@apple_support~//crosstool:setup.bzl%apple_cc_configure_extension": {
       "general": {
-        "bzlTransitiveDigest": "PjIds3feoYE8SGbbIq2SFTZy3zmxeO2tQevJZNDo7iY=",
-        "usagesDigest": "+hz7IHWN6A1oVJJWNDB6yZRG+RYhF76wAYItpAeIUIg=",
+        "bzlTransitiveDigest": "ltCGFbl/LQQZXn/LEMXfKX7pGwyqNiOCHcmiQW0tmjM=",
+        "usagesDigest": "eXsWd8YDJDt7+F94YtjKuTAIRMWBi9JLS8hUiqynRIY=",
         "recordedFileInputs": {},
         "recordedDirentsInputs": {},
         "envVariables": {},
@@ -128,27 +242,207 @@
         ]
       }
     },
-    "@@platforms//host:extension.bzl%host_platform": {
+    "@@pybind11_bazel~//:internal_configure.bzl%internal_configure_extension": {
       "general": {
-        "bzlTransitiveDigest": "xelQcPZH8+tmuOHVjL9vDxMnnQNMlwj0SlvgoqBkm4U=",
-        "usagesDigest": "hgylFkgWSg0ulUwWZzEM1aIftlUnbmw2ynWLdEfHnZc=",
+        "bzlTransitiveDigest": "CyAKLVVonohnkTSqg9II/HA7M49sOlnMkgMHL3CmDuc=",
+        "usagesDigest": "mFrTHX5eCiNU/OIIGVHH3cOILY9Zmjqk8RQYv8o6Thk=",
+        "recordedFileInputs": {
+          "@@pybind11_bazel~//MODULE.bazel": "e6f4c20442eaa7c90d7190d8dc539d0ab422f95c65a57cc59562170c58ae3d34"
+        },
+        "recordedDirentsInputs": {},
+        "envVariables": {},
+        "generatedRepoSpecs": {
+          "pybind11": {
+            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+            "ruleClassName": "http_archive",
+            "attributes": {
+              "build_file": "@@pybind11_bazel~//:pybind11-BUILD.bazel",
+              "strip_prefix": "pybind11-2.12.0",
+              "urls": [
+                "https://github.com/pybind/pybind11/archive/v2.12.0.zip"
+              ]
+            }
+          }
+        },
+        "recordedRepoMappingEntries": [
+          [
+            "pybind11_bazel~",
+            "bazel_tools",
+            "bazel_tools"
+          ]
+        ]
+      }
+    },
+    "@@rules_android~//bzlmod_extensions:apksig.bzl%apksig_extension": {
+      "general": {
+        "bzlTransitiveDigest": "+fNvC5PNWx1aA64JjkW33+1zGbG9xgfi70xQhxbglhY=",
+        "usagesDigest": "TaGkNxVMBZxl1ANdUNPmIjKrA33bO+BpI06yTlpHdos=",
         "recordedFileInputs": {},
         "recordedDirentsInputs": {},
         "envVariables": {},
         "generatedRepoSpecs": {
-          "host_platform": {
-            "bzlFile": "@@platforms//host:extension.bzl",
-            "ruleClassName": "host_platform_repo",
+          "apksig": {
+            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+            "ruleClassName": "http_archive",
+            "attributes": {
+              "url": "https://android.googlesource.com/platform/tools/apksig/+archive/24e3075e68ebe17c0b529bb24bfda819db5e2f3b.tar.gz",
+              "build_file": "@@rules_android~//bzlmod_extensions:apksig.BUILD"
+            }
+          }
+        },
+        "recordedRepoMappingEntries": [
+          [
+            "rules_android~",
+            "bazel_tools",
+            "bazel_tools"
+          ]
+        ]
+      }
+    },
+    "@@rules_android~//bzlmod_extensions:com_android_dex.bzl%com_android_dex_extension": {
+      "general": {
+        "bzlTransitiveDigest": "/KJvxHLYhvSLJihEHN0e5Uzdd7OOMvpFb0BFUl1RUTs=",
+        "usagesDigest": "fh77SU1OUlWN5ivrGpY93+t0MipuVj89/MMUgfTpSa8=",
+        "recordedFileInputs": {},
+        "recordedDirentsInputs": {},
+        "envVariables": {},
+        "generatedRepoSpecs": {
+          "com_android_dex": {
+            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+            "ruleClassName": "http_archive",
+            "attributes": {
+              "url": "https://android.googlesource.com/platform/dalvik/+archive/5a81c499a569731e2395f7c8d13c0e0d4e17a2b6.tar.gz",
+              "build_file": "@@rules_android~//bzlmod_extensions:com_android_dex.BUILD"
+            }
+          }
+        },
+        "recordedRepoMappingEntries": [
+          [
+            "rules_android~",
+            "bazel_tools",
+            "bazel_tools"
+          ]
+        ]
+      }
+    },
+    "@@rules_android~//rules/android_sdk_repository:rule.bzl%android_sdk_repository_extension": {
+      "general": {
+        "bzlTransitiveDigest": "NAy+0M15JNVEBb8Tny6t7j3lKqTnsAMjoBB6LJ+C370=",
+        "usagesDigest": "weZLGEpNa+fTJZ9CEljWxpN3/kuPzj/ULgebzOt2h4g=",
+        "recordedFileInputs": {},
+        "recordedDirentsInputs": {},
+        "envVariables": {},
+        "generatedRepoSpecs": {
+          "androidsdk": {
+            "bzlFile": "@@rules_android~//rules/android_sdk_repository:rule.bzl",
+            "ruleClassName": "_android_sdk_repository",
             "attributes": {}
           }
         },
         "recordedRepoMappingEntries": []
       }
     },
+    "@@rules_apple~//apple:apple.bzl%provisioning_profile_repository_extension": {
+      "general": {
+        "bzlTransitiveDigest": "OLmLOE2zg0CXXzAR24XTccdOw39pMG2gG6R1VFOgDsE=",
+        "usagesDigest": "cLx5XGjlbSDOpyA053y/jlr4GcaXFVTeHQic6eyG38E=",
+        "recordedFileInputs": {},
+        "recordedDirentsInputs": {},
+        "envVariables": {},
+        "generatedRepoSpecs": {
+          "local_provisioning_profiles": {
+            "bzlFile": "@@rules_apple~//apple/internal:local_provisioning_profiles.bzl",
+            "ruleClassName": "provisioning_profile_repository",
+            "attributes": {}
+          }
+        },
+        "recordedRepoMappingEntries": [
+          [
+            "apple_support~",
+            "bazel_skylib",
+            "bazel_skylib~"
+          ],
+          [
+            "rules_apple~",
+            "bazel_skylib",
+            "bazel_skylib~"
+          ],
+          [
+            "rules_apple~",
+            "bazel_tools",
+            "bazel_tools"
+          ],
+          [
+            "rules_apple~",
+            "build_bazel_apple_support",
+            "apple_support~"
+          ],
+          [
+            "rules_apple~",
+            "build_bazel_rules_swift",
+            "rules_swift~"
+          ],
+          [
+            "rules_swift~",
+            "bazel_skylib",
+            "bazel_skylib~"
+          ],
+          [
+            "rules_swift~",
+            "bazel_tools",
+            "bazel_tools"
+          ],
+          [
+            "rules_swift~",
+            "build_bazel_apple_support",
+            "apple_support~"
+          ],
+          [
+            "rules_swift~",
+            "build_bazel_rules_swift",
+            "rules_swift~"
+          ],
+          [
+            "rules_swift~",
+            "build_bazel_rules_swift_local_config",
+            "rules_swift~~non_module_deps~build_bazel_rules_swift_local_config"
+          ]
+        ]
+      }
+    },
+    "@@rules_apple~//apple:extensions.bzl%non_module_deps": {
+      "general": {
+        "bzlTransitiveDigest": "LJ3bhNqfW9y6MZFgtKQoPJyUMg/aEZ8H9QXSzK1VOBk=",
+        "usagesDigest": "5FfEPy/Z0Y2V9RbdJRDabgADFdvlfIIrps/5XYOnMNI=",
+        "recordedFileInputs": {},
+        "recordedDirentsInputs": {},
+        "envVariables": {},
+        "generatedRepoSpecs": {
+          "xctestrunner": {
+            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+            "ruleClassName": "http_archive",
+            "attributes": {
+              "urls": [
+                "https://github.com/google/xctestrunner/archive/b7698df3d435b6491b4b4c0f9fc7a63fbed5e3a6.tar.gz"
+              ],
+              "strip_prefix": "xctestrunner-b7698df3d435b6491b4b4c0f9fc7a63fbed5e3a6",
+              "sha256": "ae3a063c985a8633cb7eb566db21656f8db8eb9a0edb8c182312c7f0db53730d"
+            }
+          }
+        },
+        "recordedRepoMappingEntries": [
+          [
+            "rules_apple~",
+            "bazel_tools",
+            "bazel_tools"
+          ]
+        ]
+      }
+    },
     "@@rules_kotlin~//src/main/starlark/core/repositories:bzlmod_setup.bzl%rules_kotlin_extensions": {
       "general": {
-        "bzlTransitiveDigest": "fus14IFJ/1LGWWGKPH/U18VnJCoMjfDt1ckahqCnM0A=",
-        "usagesDigest": "aJF6fLy82rR95Ff5CZPAqxNoFgOMLMN5ImfBS0nhnkg=",
+        "bzlTransitiveDigest": "BSndOxBXlbe5qZf1NRxf828dpEK6tM429pCnaFoUFYs=",
+        "usagesDigest": "Dg5Nih77FaLAipQB7wgwsAy553a3po0eNGQVTZKgCM8=",
         "recordedFileInputs": {},
         "recordedDirentsInputs": {},
         "envVariables": {},
@@ -158,9 +452,9 @@
             "ruleClassName": "kotlin_compiler_git_repository",
             "attributes": {
               "urls": [
-                "https://github.com/JetBrains/kotlin/releases/download/v1.9.23/kotlin-compiler-1.9.23.zip"
+                "https://github.com/JetBrains/kotlin/releases/download/v2.1.0/kotlin-compiler-2.1.0.zip"
               ],
-              "sha256": "93137d3aab9afa9b27cb06a824c2324195c6b6f6179d8a8653f440f5bd58be88"
+              "sha256": "b6698d5728ad8f9edcdd01617d638073191d8a03139cc538a391b4e3759ad297"
             }
           },
           "com_github_jetbrains_kotlin": {
@@ -168,7 +462,7 @@
             "ruleClassName": "kotlin_capabilities_repository",
             "attributes": {
               "git_repository_name": "com_github_jetbrains_kotlin_git",
-              "compiler_version": "1.9.23"
+              "compiler_version": "2.1.0"
             }
           },
           "com_github_google_ksp": {
@@ -176,31 +470,50 @@
             "ruleClassName": "ksp_compiler_plugin_repository",
             "attributes": {
               "urls": [
-                "https://github.com/google/ksp/releases/download/1.9.23-1.0.20/artifacts.zip"
+                "https://github.com/google/ksp/releases/download/2.1.0-1.0.28/artifacts.zip"
               ],
-              "sha256": "ee0618755913ef7fd6511288a232e8fad24838b9af6ea73972a76e81053c8c2d",
-              "strip_version": "1.9.23-1.0.20"
+              "sha256": "fc27b08cadc061a4a989af01cbeccb613feef1995f4aad68f2be0f886a3ee251",
+              "strip_version": "2.1.0-1.0.28"
             }
           },
           "com_github_pinterest_ktlint": {
             "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
             "ruleClassName": "http_file",
             "attributes": {
-              "sha256": "01b2e0ef893383a50dbeb13970fe7fa3be36ca3e83259e01649945b09d736985",
+              "sha256": "a9f923be58fbd32670a17f0b729b1df804af882fa57402165741cb26e5440ca1",
               "urls": [
-                "https://github.com/pinterest/ktlint/releases/download/1.3.0/ktlint"
+                "https://github.com/pinterest/ktlint/releases/download/1.3.1/ktlint"
               ],
               "executable": true
             }
           },
-          "rules_android": {
+          "kotlinx_serialization_core_jvm": {
             "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
+            "ruleClassName": "http_jar",
             "attributes": {
-              "sha256": "cd06d15dd8bb59926e4d65f9003bfc20f9da4b2519985c27e190cddc8b7a7806",
-              "strip_prefix": "rules_android-0.1.1",
+              "sha256": "29c821a8d4e25cbfe4f2ce96cdd4526f61f8f4e69a135f9612a34a81d93b65f1",
               "urls": [
-                "https://github.com/bazelbuild/rules_android/archive/v0.1.1.zip"
+                "https://repo1.maven.org/maven2/org/jetbrains/kotlinx/kotlinx-serialization-core-jvm/1.6.3/kotlinx-serialization-core-jvm-1.6.3.jar"
+              ]
+            }
+          },
+          "kotlinx_serialization_json": {
+            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+            "ruleClassName": "http_jar",
+            "attributes": {
+              "sha256": "8c0016890a79ab5980dd520a5ab1a6738023c29aa3b6437c482e0e5fdc06dab1",
+              "urls": [
+                "https://repo1.maven.org/maven2/org/jetbrains/kotlinx/kotlinx-serialization-json/1.6.3/kotlinx-serialization-json-1.6.3.jar"
+              ]
+            }
+          },
+          "kotlinx_serialization_json_jvm": {
+            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+            "ruleClassName": "http_jar",
+            "attributes": {
+              "sha256": "d3234179bcff1886d53d67c11eca47f7f3cf7b63c349d16965f6db51b7f3dd9a",
+              "urls": [
+                "https://repo1.maven.org/maven2/org/jetbrains/kotlinx/kotlinx-serialization-json-jvm/1.6.3/kotlinx-serialization-json-jvm-1.6.3.jar"
               ]
             }
           }
@@ -214,582 +527,2480 @@
         ]
       }
     },
-    "@@rules_python~//python/extensions:python.bzl%python": {
+    "@@rules_python~//python/extensions:pip.bzl%pip": {
       "general": {
-        "bzlTransitiveDigest": "l7SEKGzdShn1GH45yoD3IEBi5SxT+5WsAq/OlHiiuiw=",
-        "usagesDigest": "YiLsNY5r63HmlgMVyESsQgfKVj6Ky/w9Zozdju6rXl4=",
-        "recordedFileInputs": {},
+        "bzlTransitiveDigest": "AMoojKsX4Iw9GcO0xHbXz11GhPs9wzQ+Ua4OZ3muUzw=",
+        "usagesDigest": "ZVqDJcq4jlkbKBvSiotiO7ElR126/eiKOiKURsvOcoA=",
+        "recordedFileInputs": {
+          "@@rules_python~//tools/publish/requirements_linux.txt": "8175b4c8df50ae2f22d1706961884beeb54e7da27bd2447018314a175981997d",
+          "@@rules_python~//tools/publish/requirements_windows.txt": "7673adc71dc1a81d3661b90924d7a7c0fc998cd508b3cb4174337cef3f2de556",
+          "@@rules_python~//tools/publish/requirements_darwin.txt": "2994136eab7e57b083c3de76faf46f70fad130bc8e7360a7fed2b288b69e79dc"
+        },
         "recordedDirentsInputs": {},
-        "envVariables": {},
+        "envVariables": {
+          "RULES_PYTHON_REPO_DEBUG": null,
+          "RULES_PYTHON_REPO_DEBUG_VERBOSITY": null
+        },
         "generatedRepoSpecs": {
-          "python_3_11_aarch64-apple-darwin": {
-            "bzlFile": "@@rules_python~//python:repositories.bzl",
-            "ruleClassName": "python_repository",
+          "rules_python_publish_deps_311_backports_tarfile_py3_none_any_77e284d7": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
             "attributes": {
-              "sha256": "4918cdf1cab742a90f85318f88b8122aeaa2d04705803c7b6e78e81a3dd40f80",
-              "patches": [],
-              "platform": "aarch64-apple-darwin",
-              "python_version": "3.11.1",
-              "release_filename": "20230116/cpython-3.11.1+20230116-aarch64-apple-darwin-install_only.tar.gz",
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "backports.tarfile-1.2.0-py3-none-any.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "backports-tarfile==1.2.0",
+              "sha256": "77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34",
               "urls": [
-                "https://github.com/indygreg/python-build-standalone/releases/download/20230116/cpython-3.11.1+20230116-aarch64-apple-darwin-install_only.tar.gz"
-              ],
-              "distutils_content": "",
-              "strip_prefix": "python",
-              "ignore_root_user_error": false
-            }
-          },
-          "python_3_11_aarch64-unknown-linux-gnu": {
-            "bzlFile": "@@rules_python~//python:repositories.bzl",
-            "ruleClassName": "python_repository",
-            "attributes": {
-              "sha256": "debf15783bdcb5530504f533d33fda75a7b905cec5361ae8f33da5ba6599f8b4",
-              "patches": [],
-              "platform": "aarch64-unknown-linux-gnu",
-              "python_version": "3.11.1",
-              "release_filename": "20230116/cpython-3.11.1+20230116-aarch64-unknown-linux-gnu-install_only.tar.gz",
-              "urls": [
-                "https://github.com/indygreg/python-build-standalone/releases/download/20230116/cpython-3.11.1+20230116-aarch64-unknown-linux-gnu-install_only.tar.gz"
-              ],
-              "distutils_content": "",
-              "strip_prefix": "python",
-              "ignore_root_user_error": false
-            }
-          },
-          "python_3_11_x86_64-apple-darwin": {
-            "bzlFile": "@@rules_python~//python:repositories.bzl",
-            "ruleClassName": "python_repository",
-            "attributes": {
-              "sha256": "20a4203d069dc9b710f70b09e7da2ce6f473d6b1110f9535fb6f4c469ed54733",
-              "patches": [],
-              "platform": "x86_64-apple-darwin",
-              "python_version": "3.11.1",
-              "release_filename": "20230116/cpython-3.11.1+20230116-x86_64-apple-darwin-install_only.tar.gz",
-              "urls": [
-                "https://github.com/indygreg/python-build-standalone/releases/download/20230116/cpython-3.11.1+20230116-x86_64-apple-darwin-install_only.tar.gz"
-              ],
-              "distutils_content": "",
-              "strip_prefix": "python",
-              "ignore_root_user_error": false
-            }
-          },
-          "python_3_11_x86_64-pc-windows-msvc": {
-            "bzlFile": "@@rules_python~//python:repositories.bzl",
-            "ruleClassName": "python_repository",
-            "attributes": {
-              "sha256": "edc08979cb0666a597466176511529c049a6f0bba8adf70df441708f766de5bf",
-              "patches": [],
-              "platform": "x86_64-pc-windows-msvc",
-              "python_version": "3.11.1",
-              "release_filename": "20230116/cpython-3.11.1+20230116-x86_64-pc-windows-msvc-shared-install_only.tar.gz",
-              "urls": [
-                "https://github.com/indygreg/python-build-standalone/releases/download/20230116/cpython-3.11.1+20230116-x86_64-pc-windows-msvc-shared-install_only.tar.gz"
-              ],
-              "distutils_content": "",
-              "strip_prefix": "python",
-              "ignore_root_user_error": false
-            }
-          },
-          "python_3_11_x86_64-unknown-linux-gnu": {
-            "bzlFile": "@@rules_python~//python:repositories.bzl",
-            "ruleClassName": "python_repository",
-            "attributes": {
-              "sha256": "02a551fefab3750effd0e156c25446547c238688a32fabde2995c941c03a6423",
-              "patches": [],
-              "platform": "x86_64-unknown-linux-gnu",
-              "python_version": "3.11.1",
-              "release_filename": "20230116/cpython-3.11.1+20230116-x86_64-unknown-linux-gnu-install_only.tar.gz",
-              "urls": [
-                "https://github.com/indygreg/python-build-standalone/releases/download/20230116/cpython-3.11.1+20230116-x86_64-unknown-linux-gnu-install_only.tar.gz"
-              ],
-              "distutils_content": "",
-              "strip_prefix": "python",
-              "ignore_root_user_error": false
-            }
-          },
-          "python_3_11": {
-            "bzlFile": "@@rules_python~//python/private:toolchains_repo.bzl",
-            "ruleClassName": "toolchain_aliases",
-            "attributes": {
-              "python_version": "3.11.1",
-              "user_repository_name": "python_3_11"
-            }
-          },
-          "pythons_hub": {
-            "bzlFile": "@@rules_python~//python/extensions/private:pythons_hub.bzl",
-            "ruleClassName": "hub_repo",
-            "attributes": {
-              "toolchain_prefixes": [
-                "_0000_python_3_11_"
-              ],
-              "toolchain_python_versions": [
-                "3.11"
-              ],
-              "toolchain_set_python_version_constraints": [
-                "False"
-              ],
-              "toolchain_user_repository_names": [
-                "python_3_11"
+                "https://files.pythonhosted.org/packages/b9/fa/123043af240e49752f1c4bd24da5053b6bd00cad78c2be53c0d1e8b975bc/backports.tarfile-1.2.0-py3-none-any.whl"
               ]
             }
           },
-          "python_aliases": {
-            "bzlFile": "@@rules_python~//python/private:toolchains_repo.bzl",
-            "ruleClassName": "multi_toolchain_aliases",
+          "rules_python_publish_deps_311_backports_tarfile_sdist_d75e02c2": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
             "attributes": {
-              "python_versions": {
-                "3.11": "python_3_11"
-              }
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "extra_pip_args": [
+                "--index-url",
+                "https://pypi.org/simple"
+              ],
+              "filename": "backports_tarfile-1.2.0.tar.gz",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "backports-tarfile==1.2.0",
+              "sha256": "d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991",
+              "urls": [
+                "https://files.pythonhosted.org/packages/86/72/cd9b395f25e290e633655a100af28cb253e4393396264a98bd5f5951d50f/backports_tarfile-1.2.0.tar.gz"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_certifi_py3_none_any_922820b5": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "certifi-2024.8.30-py3-none-any.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "certifi==2024.8.30",
+              "sha256": "922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8",
+              "urls": [
+                "https://files.pythonhosted.org/packages/12/90/3c9ff0512038035f59d279fddeb79f5f1eccd8859f06d6163c58798b9487/certifi-2024.8.30-py3-none-any.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_certifi_sdist_bec941d2": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "extra_pip_args": [
+                "--index-url",
+                "https://pypi.org/simple"
+              ],
+              "filename": "certifi-2024.8.30.tar.gz",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "certifi==2024.8.30",
+              "sha256": "bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9",
+              "urls": [
+                "https://files.pythonhosted.org/packages/b0/ee/9b19140fe824b367c04c5e1b369942dd754c4c5462d5674002f75c4dedc1/certifi-2024.8.30.tar.gz"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_cffi_cp311_cp311_manylinux_2_17_aarch64_a1ed2dd2": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64"
+              ],
+              "filename": "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "cffi==1.17.1",
+              "sha256": "a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41",
+              "urls": [
+                "https://files.pythonhosted.org/packages/2e/ea/70ce63780f096e16ce8588efe039d3c4f91deb1dc01e9c73a287939c79a6/cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_cffi_cp311_cp311_manylinux_2_17_ppc64le_46bf4316": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64"
+              ],
+              "filename": "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "cffi==1.17.1",
+              "sha256": "46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1",
+              "urls": [
+                "https://files.pythonhosted.org/packages/1c/a0/a4fa9f4f781bda074c3ddd57a572b060fa0df7655d2a4247bbe277200146/cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_cffi_cp311_cp311_manylinux_2_17_s390x_a24ed04c": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64"
+              ],
+              "filename": "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "cffi==1.17.1",
+              "sha256": "a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6",
+              "urls": [
+                "https://files.pythonhosted.org/packages/62/12/ce8710b5b8affbcdd5c6e367217c242524ad17a02fe5beec3ee339f69f85/cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_cffi_cp311_cp311_manylinux_2_17_x86_64_610faea7": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64"
+              ],
+              "filename": "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "cffi==1.17.1",
+              "sha256": "610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d",
+              "urls": [
+                "https://files.pythonhosted.org/packages/ff/6b/d45873c5e0242196f042d555526f92aa9e0c32355a1be1ff8c27f077fd37/cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_cffi_cp311_cp311_musllinux_1_1_aarch64_a9b15d49": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64"
+              ],
+              "filename": "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "cffi==1.17.1",
+              "sha256": "a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6",
+              "urls": [
+                "https://files.pythonhosted.org/packages/1a/52/d9a0e523a572fbccf2955f5abe883cfa8bcc570d7faeee06336fbd50c9fc/cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_cffi_cp311_cp311_musllinux_1_1_x86_64_fc48c783": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64"
+              ],
+              "filename": "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "cffi==1.17.1",
+              "sha256": "fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b",
+              "urls": [
+                "https://files.pythonhosted.org/packages/f8/4a/34599cac7dfcd888ff54e801afe06a19c17787dfd94495ab0c8d35fe99fb/cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_cffi_sdist_1c39c601": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64"
+              ],
+              "extra_pip_args": [
+                "--index-url",
+                "https://pypi.org/simple"
+              ],
+              "filename": "cffi-1.17.1.tar.gz",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "cffi==1.17.1",
+              "sha256": "1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824",
+              "urls": [
+                "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_macosx_10_9_universal2_0d99dd8f": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "charset-normalizer==3.4.0",
+              "sha256": "0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c",
+              "urls": [
+                "https://files.pythonhosted.org/packages/9c/61/73589dcc7a719582bf56aae309b6103d2762b526bffe189d635a7fcfd998/charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_macosx_10_9_x86_64_c57516e5": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "charset-normalizer==3.4.0",
+              "sha256": "c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944",
+              "urls": [
+                "https://files.pythonhosted.org/packages/77/d5/8c982d58144de49f59571f940e329ad6e8615e1e82ef84584c5eeb5e1d72/charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_macosx_11_0_arm64_6dba5d19": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "charset-normalizer==3.4.0",
+              "sha256": "6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee",
+              "urls": [
+                "https://files.pythonhosted.org/packages/bf/19/411a64f01ee971bed3231111b69eb56f9331a769072de479eae7de52296d/charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_manylinux_2_17_aarch64_bf4475b8": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "charset-normalizer==3.4.0",
+              "sha256": "bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c",
+              "urls": [
+                "https://files.pythonhosted.org/packages/4c/92/97509850f0d00e9f14a46bc751daabd0ad7765cff29cdfb66c68b6dad57f/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_manylinux_2_17_ppc64le_ce031db0": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "charset-normalizer==3.4.0",
+              "sha256": "ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6",
+              "urls": [
+                "https://files.pythonhosted.org/packages/e2/29/d227805bff72ed6d6cb1ce08eec707f7cfbd9868044893617eb331f16295/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_manylinux_2_17_s390x_8ff4e7cd": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "charset-normalizer==3.4.0",
+              "sha256": "8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea",
+              "urls": [
+                "https://files.pythonhosted.org/packages/13/bc/87c2c9f2c144bedfa62f894c3007cd4530ba4b5351acb10dc786428a50f0/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_manylinux_2_17_x86_64_3710a975": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "charset-normalizer==3.4.0",
+              "sha256": "3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc",
+              "urls": [
+                "https://files.pythonhosted.org/packages/eb/5b/6f10bad0f6461fa272bfbbdf5d0023b5fb9bc6217c92bf068fa5a99820f5/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_musllinux_1_2_aarch64_47334db7": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "charset-normalizer==3.4.0",
+              "sha256": "47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594",
+              "urls": [
+                "https://files.pythonhosted.org/packages/d7/a1/493919799446464ed0299c8eef3c3fad0daf1c3cd48bff9263c731b0d9e2/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_musllinux_1_2_ppc64le_f1a2f519": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "charset-normalizer==3.4.0",
+              "sha256": "f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365",
+              "urls": [
+                "https://files.pythonhosted.org/packages/75/d2/0ab54463d3410709c09266dfb416d032a08f97fd7d60e94b8c6ef54ae14b/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_musllinux_1_2_s390x_63bc5c4a": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "charset-normalizer==3.4.0",
+              "sha256": "63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129",
+              "urls": [
+                "https://files.pythonhosted.org/packages/8d/c9/27e41d481557be53d51e60750b85aa40eaf52b841946b3cdeff363105737/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_musllinux_1_2_x86_64_bcb4f8ea": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "charset-normalizer==3.4.0",
+              "sha256": "bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236",
+              "urls": [
+                "https://files.pythonhosted.org/packages/ee/44/4f62042ca8cdc0cabf87c0fc00ae27cd8b53ab68be3605ba6d071f742ad3/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_win_amd64_cee4373f": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "charset-normalizer==3.4.0",
+              "sha256": "cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27",
+              "urls": [
+                "https://files.pythonhosted.org/packages/0b/6e/b13bd47fa9023b3699e94abf565b5a2f0b0be6e9ddac9812182596ee62e4/charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_charset_normalizer_py3_none_any_fe9f97fe": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "charset_normalizer-3.4.0-py3-none-any.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "charset-normalizer==3.4.0",
+              "sha256": "fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079",
+              "urls": [
+                "https://files.pythonhosted.org/packages/bf/9b/08c0432272d77b04803958a4598a51e2a4b51c06640af8b8f0f908c18bf2/charset_normalizer-3.4.0-py3-none-any.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_charset_normalizer_sdist_223217c3": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "extra_pip_args": [
+                "--index-url",
+                "https://pypi.org/simple"
+              ],
+              "filename": "charset_normalizer-3.4.0.tar.gz",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "charset-normalizer==3.4.0",
+              "sha256": "223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e",
+              "urls": [
+                "https://files.pythonhosted.org/packages/f2/4f/e1808dc01273379acc506d18f1504eb2d299bd4131743b9fc54d7be4df1e/charset_normalizer-3.4.0.tar.gz"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_cryptography_cp39_abi3_manylinux_2_17_aarch64_846da004": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64"
+              ],
+              "filename": "cryptography-43.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "cryptography==43.0.3",
+              "sha256": "846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5",
+              "urls": [
+                "https://files.pythonhosted.org/packages/2f/78/55356eb9075d0be6e81b59f45c7b48df87f76a20e73893872170471f3ee8/cryptography-43.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_cryptography_cp39_abi3_manylinux_2_17_x86_64_0f996e72": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64"
+              ],
+              "filename": "cryptography-43.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "cryptography==43.0.3",
+              "sha256": "0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4",
+              "urls": [
+                "https://files.pythonhosted.org/packages/2a/2c/488776a3dc843f95f86d2f957ca0fc3407d0242b50bede7fad1e339be03f/cryptography-43.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_cryptography_cp39_abi3_manylinux_2_28_aarch64_f7b178f1": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64"
+              ],
+              "filename": "cryptography-43.0.3-cp39-abi3-manylinux_2_28_aarch64.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "cryptography==43.0.3",
+              "sha256": "f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7",
+              "urls": [
+                "https://files.pythonhosted.org/packages/7c/04/2345ca92f7a22f601a9c62961741ef7dd0127c39f7310dffa0041c80f16f/cryptography-43.0.3-cp39-abi3-manylinux_2_28_aarch64.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_cryptography_cp39_abi3_manylinux_2_28_x86_64_c2e6fc39": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64"
+              ],
+              "filename": "cryptography-43.0.3-cp39-abi3-manylinux_2_28_x86_64.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "cryptography==43.0.3",
+              "sha256": "c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405",
+              "urls": [
+                "https://files.pythonhosted.org/packages/ac/25/e715fa0bc24ac2114ed69da33adf451a38abb6f3f24ec207908112e9ba53/cryptography-43.0.3-cp39-abi3-manylinux_2_28_x86_64.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_cryptography_cp39_abi3_musllinux_1_2_aarch64_e1be4655": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64"
+              ],
+              "filename": "cryptography-43.0.3-cp39-abi3-musllinux_1_2_aarch64.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "cryptography==43.0.3",
+              "sha256": "e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16",
+              "urls": [
+                "https://files.pythonhosted.org/packages/21/ce/b9c9ff56c7164d8e2edfb6c9305045fbc0df4508ccfdb13ee66eb8c95b0e/cryptography-43.0.3-cp39-abi3-musllinux_1_2_aarch64.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_cryptography_cp39_abi3_musllinux_1_2_x86_64_df6b6c6d": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64"
+              ],
+              "filename": "cryptography-43.0.3-cp39-abi3-musllinux_1_2_x86_64.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "cryptography==43.0.3",
+              "sha256": "df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73",
+              "urls": [
+                "https://files.pythonhosted.org/packages/2a/33/b3682992ab2e9476b9c81fff22f02c8b0a1e6e1d49ee1750a67d85fd7ed2/cryptography-43.0.3-cp39-abi3-musllinux_1_2_x86_64.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_cryptography_sdist_315b9001": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64"
+              ],
+              "extra_pip_args": [
+                "--index-url",
+                "https://pypi.org/simple"
+              ],
+              "filename": "cryptography-43.0.3.tar.gz",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "cryptography==43.0.3",
+              "sha256": "315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805",
+              "urls": [
+                "https://files.pythonhosted.org/packages/0d/05/07b55d1fa21ac18c3a8c79f764e2514e6f6a9698f1be44994f5adf0d29db/cryptography-43.0.3.tar.gz"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_docutils_py3_none_any_dafca5b9": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "docutils-0.21.2-py3-none-any.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "docutils==0.21.2",
+              "sha256": "dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2",
+              "urls": [
+                "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_docutils_sdist_3a6b1873": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "extra_pip_args": [
+                "--index-url",
+                "https://pypi.org/simple"
+              ],
+              "filename": "docutils-0.21.2.tar.gz",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "docutils==0.21.2",
+              "sha256": "3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f",
+              "urls": [
+                "https://files.pythonhosted.org/packages/ae/ed/aefcc8cd0ba62a0560c3c18c33925362d46c6075480bfa4df87b28e169a9/docutils-0.21.2.tar.gz"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_idna_py3_none_any_946d195a": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "idna-3.10-py3-none-any.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "idna==3.10",
+              "sha256": "946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3",
+              "urls": [
+                "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_idna_sdist_12f65c9b": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "extra_pip_args": [
+                "--index-url",
+                "https://pypi.org/simple"
+              ],
+              "filename": "idna-3.10.tar.gz",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "idna==3.10",
+              "sha256": "12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9",
+              "urls": [
+                "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_importlib_metadata_py3_none_any_45e54197": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "importlib_metadata-8.5.0-py3-none-any.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "importlib-metadata==8.5.0",
+              "sha256": "45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b",
+              "urls": [
+                "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_importlib_metadata_sdist_71522656": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "extra_pip_args": [
+                "--index-url",
+                "https://pypi.org/simple"
+              ],
+              "filename": "importlib_metadata-8.5.0.tar.gz",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "importlib-metadata==8.5.0",
+              "sha256": "71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7",
+              "urls": [
+                "https://files.pythonhosted.org/packages/cd/12/33e59336dca5be0c398a7482335911a33aa0e20776128f038019f1a95f1b/importlib_metadata-8.5.0.tar.gz"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_jaraco_classes_py3_none_any_f662826b": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "jaraco.classes-3.4.0-py3-none-any.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "jaraco-classes==3.4.0",
+              "sha256": "f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790",
+              "urls": [
+                "https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_jaraco_classes_sdist_47a024b5": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "extra_pip_args": [
+                "--index-url",
+                "https://pypi.org/simple"
+              ],
+              "filename": "jaraco.classes-3.4.0.tar.gz",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "jaraco-classes==3.4.0",
+              "sha256": "47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd",
+              "urls": [
+                "https://files.pythonhosted.org/packages/06/c0/ed4a27bc5571b99e3cff68f8a9fa5b56ff7df1c2251cc715a652ddd26402/jaraco.classes-3.4.0.tar.gz"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_jaraco_context_py3_none_any_f797fc48": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "jaraco.context-6.0.1-py3-none-any.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "jaraco-context==6.0.1",
+              "sha256": "f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4",
+              "urls": [
+                "https://files.pythonhosted.org/packages/ff/db/0c52c4cf5e4bd9f5d7135ec7669a3a767af21b3a308e1ed3674881e52b62/jaraco.context-6.0.1-py3-none-any.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_jaraco_context_sdist_9bae4ea5": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "extra_pip_args": [
+                "--index-url",
+                "https://pypi.org/simple"
+              ],
+              "filename": "jaraco_context-6.0.1.tar.gz",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "jaraco-context==6.0.1",
+              "sha256": "9bae4ea555cf0b14938dc0aee7c9f32ed303aa20a3b73e7dc80111628792d1b3",
+              "urls": [
+                "https://files.pythonhosted.org/packages/df/ad/f3777b81bf0b6e7bc7514a1656d3e637b2e8e15fab2ce3235730b3e7a4e6/jaraco_context-6.0.1.tar.gz"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_jaraco_functools_py3_none_any_ad159f13": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "jaraco.functools-4.1.0-py3-none-any.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "jaraco-functools==4.1.0",
+              "sha256": "ad159f13428bc4acbf5541ad6dec511f91573b90fba04df61dafa2a1231cf649",
+              "urls": [
+                "https://files.pythonhosted.org/packages/9f/4f/24b319316142c44283d7540e76c7b5a6dbd5db623abd86bb7b3491c21018/jaraco.functools-4.1.0-py3-none-any.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_jaraco_functools_sdist_70f7e0e2": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "extra_pip_args": [
+                "--index-url",
+                "https://pypi.org/simple"
+              ],
+              "filename": "jaraco_functools-4.1.0.tar.gz",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "jaraco-functools==4.1.0",
+              "sha256": "70f7e0e2ae076498e212562325e805204fc092d7b4c17e0e86c959e249701a9d",
+              "urls": [
+                "https://files.pythonhosted.org/packages/ab/23/9894b3df5d0a6eb44611c36aec777823fc2e07740dabbd0b810e19594013/jaraco_functools-4.1.0.tar.gz"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_jeepney_py3_none_any_c0a454ad": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64"
+              ],
+              "filename": "jeepney-0.8.0-py3-none-any.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "jeepney==0.8.0",
+              "sha256": "c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755",
+              "urls": [
+                "https://files.pythonhosted.org/packages/ae/72/2a1e2290f1ab1e06f71f3d0f1646c9e4634e70e1d37491535e19266e8dc9/jeepney-0.8.0-py3-none-any.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_jeepney_sdist_5efe48d2": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64"
+              ],
+              "extra_pip_args": [
+                "--index-url",
+                "https://pypi.org/simple"
+              ],
+              "filename": "jeepney-0.8.0.tar.gz",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "jeepney==0.8.0",
+              "sha256": "5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806",
+              "urls": [
+                "https://files.pythonhosted.org/packages/d6/f4/154cf374c2daf2020e05c3c6a03c91348d59b23c5366e968feb198306fdf/jeepney-0.8.0.tar.gz"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_keyring_py3_none_any_5426f817": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "keyring-25.4.1-py3-none-any.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "keyring==25.4.1",
+              "sha256": "5426f817cf7f6f007ba5ec722b1bcad95a75b27d780343772ad76b17cb47b0bf",
+              "urls": [
+                "https://files.pythonhosted.org/packages/83/25/e6d59e5f0a0508d0dca8bb98c7f7fd3772fc943ac3f53d5ab18a218d32c0/keyring-25.4.1-py3-none-any.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_keyring_sdist_b07ebc55": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "extra_pip_args": [
+                "--index-url",
+                "https://pypi.org/simple"
+              ],
+              "filename": "keyring-25.4.1.tar.gz",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "keyring==25.4.1",
+              "sha256": "b07ebc55f3e8ed86ac81dd31ef14e81ace9dd9c3d4b5d77a6e9a2016d0d71a1b",
+              "urls": [
+                "https://files.pythonhosted.org/packages/a5/1c/2bdbcfd5d59dc6274ffb175bc29aa07ecbfab196830e0cfbde7bd861a2ea/keyring-25.4.1.tar.gz"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_markdown_it_py_py3_none_any_35521684": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "markdown_it_py-3.0.0-py3-none-any.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "markdown-it-py==3.0.0",
+              "sha256": "355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1",
+              "urls": [
+                "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_markdown_it_py_sdist_e3f60a94": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "extra_pip_args": [
+                "--index-url",
+                "https://pypi.org/simple"
+              ],
+              "filename": "markdown-it-py-3.0.0.tar.gz",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "markdown-it-py==3.0.0",
+              "sha256": "e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb",
+              "urls": [
+                "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_mdurl_py3_none_any_84008a41": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "mdurl-0.1.2-py3-none-any.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "mdurl==0.1.2",
+              "sha256": "84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8",
+              "urls": [
+                "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_mdurl_sdist_bb413d29": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "extra_pip_args": [
+                "--index-url",
+                "https://pypi.org/simple"
+              ],
+              "filename": "mdurl-0.1.2.tar.gz",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "mdurl==0.1.2",
+              "sha256": "bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba",
+              "urls": [
+                "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_more_itertools_py3_none_any_037b0d32": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "more_itertools-10.5.0-py3-none-any.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "more-itertools==10.5.0",
+              "sha256": "037b0d3203ce90cca8ab1defbbdac29d5f993fc20131f3664dc8d6acfa872aef",
+              "urls": [
+                "https://files.pythonhosted.org/packages/48/7e/3a64597054a70f7c86eb0a7d4fc315b8c1ab932f64883a297bdffeb5f967/more_itertools-10.5.0-py3-none-any.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_more_itertools_sdist_5482bfef": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "extra_pip_args": [
+                "--index-url",
+                "https://pypi.org/simple"
+              ],
+              "filename": "more-itertools-10.5.0.tar.gz",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "more-itertools==10.5.0",
+              "sha256": "5482bfef7849c25dc3c6dd53a6173ae4795da2a41a80faea6700d9f5846c5da6",
+              "urls": [
+                "https://files.pythonhosted.org/packages/51/78/65922308c4248e0eb08ebcbe67c95d48615cc6f27854b6f2e57143e9178f/more-itertools-10.5.0.tar.gz"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_nh3_cp37_abi3_macosx_10_12_x86_64_14c5a72e": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "nh3-0.2.18-cp37-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "nh3==0.2.18",
+              "sha256": "14c5a72e9fe82aea5fe3072116ad4661af5cf8e8ff8fc5ad3450f123e4925e86",
+              "urls": [
+                "https://files.pythonhosted.org/packages/b3/89/1daff5d9ba5a95a157c092c7c5f39b8dd2b1ddb4559966f808d31cfb67e0/nh3-0.2.18-cp37-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_nh3_cp37_abi3_macosx_10_12_x86_64_7b7c2a3c": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "nh3-0.2.18-cp37-abi3-macosx_10_12_x86_64.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "nh3==0.2.18",
+              "sha256": "7b7c2a3c9eb1a827d42539aa64091640bd275b81e097cd1d8d82ef91ffa2e811",
+              "urls": [
+                "https://files.pythonhosted.org/packages/2c/b6/42fc3c69cabf86b6b81e4c051a9b6e249c5ba9f8155590222c2622961f58/nh3-0.2.18-cp37-abi3-macosx_10_12_x86_64.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_nh3_cp37_abi3_manylinux_2_17_aarch64_42c64511": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "nh3-0.2.18-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "nh3==0.2.18",
+              "sha256": "42c64511469005058cd17cc1537578eac40ae9f7200bedcfd1fc1a05f4f8c200",
+              "urls": [
+                "https://files.pythonhosted.org/packages/45/b9/833f385403abaf0023c6547389ec7a7acf141ddd9d1f21573723a6eab39a/nh3-0.2.18-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_nh3_cp37_abi3_manylinux_2_17_armv7l_0411beb0": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "nh3-0.2.18-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "nh3==0.2.18",
+              "sha256": "0411beb0589eacb6734f28d5497ca2ed379eafab8ad8c84b31bb5c34072b7164",
+              "urls": [
+                "https://files.pythonhosted.org/packages/05/2b/85977d9e11713b5747595ee61f381bc820749daf83f07b90b6c9964cf932/nh3-0.2.18-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_nh3_cp37_abi3_manylinux_2_17_ppc64_5f36b271": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "nh3-0.2.18-cp37-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "nh3==0.2.18",
+              "sha256": "5f36b271dae35c465ef5e9090e1fdaba4a60a56f0bb0ba03e0932a66f28b9189",
+              "urls": [
+                "https://files.pythonhosted.org/packages/72/f2/5c894d5265ab80a97c68ca36f25c8f6f0308abac649aaf152b74e7e854a8/nh3-0.2.18-cp37-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_nh3_cp37_abi3_manylinux_2_17_ppc64le_34c03fa7": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "nh3-0.2.18-cp37-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "nh3==0.2.18",
+              "sha256": "34c03fa78e328c691f982b7c03d4423bdfd7da69cd707fe572f544cf74ac23ad",
+              "urls": [
+                "https://files.pythonhosted.org/packages/ab/a7/375afcc710dbe2d64cfbd69e31f82f3e423d43737258af01f6a56d844085/nh3-0.2.18-cp37-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_nh3_cp37_abi3_manylinux_2_17_s390x_19aaba96": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "nh3-0.2.18-cp37-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "nh3==0.2.18",
+              "sha256": "19aaba96e0f795bd0a6c56291495ff59364f4300d4a39b29a0abc9cb3774a84b",
+              "urls": [
+                "https://files.pythonhosted.org/packages/c2/a8/3bb02d0c60a03ad3a112b76c46971e9480efa98a8946677b5a59f60130ca/nh3-0.2.18-cp37-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_nh3_cp37_abi3_manylinux_2_17_x86_64_de3ceed6": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "nh3-0.2.18-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "nh3==0.2.18",
+              "sha256": "de3ceed6e661954871d6cd78b410213bdcb136f79aafe22aa7182e028b8c7307",
+              "urls": [
+                "https://files.pythonhosted.org/packages/1b/63/6ab90d0e5225ab9780f6c9fb52254fa36b52bb7c188df9201d05b647e5e1/nh3-0.2.18-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_nh3_cp37_abi3_musllinux_1_2_aarch64_f0eca9ca": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "nh3-0.2.18-cp37-abi3-musllinux_1_2_aarch64.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "nh3==0.2.18",
+              "sha256": "f0eca9ca8628dbb4e916ae2491d72957fdd35f7a5d326b7032a345f111ac07fe",
+              "urls": [
+                "https://files.pythonhosted.org/packages/a3/da/0c4e282bc3cff4a0adf37005fa1fb42257673fbc1bbf7d1ff639ec3d255a/nh3-0.2.18-cp37-abi3-musllinux_1_2_aarch64.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_nh3_cp37_abi3_musllinux_1_2_armv7l_3a157ab1": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "nh3-0.2.18-cp37-abi3-musllinux_1_2_armv7l.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "nh3==0.2.18",
+              "sha256": "3a157ab149e591bb638a55c8c6bcb8cdb559c8b12c13a8affaba6cedfe51713a",
+              "urls": [
+                "https://files.pythonhosted.org/packages/de/81/c291231463d21da5f8bba82c8167a6d6893cc5419b0639801ee5d3aeb8a9/nh3-0.2.18-cp37-abi3-musllinux_1_2_armv7l.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_nh3_cp37_abi3_musllinux_1_2_x86_64_36c95d4b": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "nh3-0.2.18-cp37-abi3-musllinux_1_2_x86_64.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "nh3==0.2.18",
+              "sha256": "36c95d4b70530b320b365659bb5034341316e6a9b30f0b25fa9c9eff4c27a204",
+              "urls": [
+                "https://files.pythonhosted.org/packages/eb/61/73a007c74c37895fdf66e0edcd881f5eaa17a348ff02f4bb4bc906d61085/nh3-0.2.18-cp37-abi3-musllinux_1_2_x86_64.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_nh3_cp37_abi3_win_amd64_8ce0f819": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "nh3-0.2.18-cp37-abi3-win_amd64.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "nh3==0.2.18",
+              "sha256": "8ce0f819d2f1933953fca255db2471ad58184a60508f03e6285e5114b6254844",
+              "urls": [
+                "https://files.pythonhosted.org/packages/26/8d/53c5b19c4999bdc6ba95f246f4ef35ca83d7d7423e5e38be43ad66544e5d/nh3-0.2.18-cp37-abi3-win_amd64.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_nh3_sdist_94a16692": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "extra_pip_args": [
+                "--index-url",
+                "https://pypi.org/simple"
+              ],
+              "filename": "nh3-0.2.18.tar.gz",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "nh3==0.2.18",
+              "sha256": "94a166927e53972a9698af9542ace4e38b9de50c34352b962f4d9a7d4c927af4",
+              "urls": [
+                "https://files.pythonhosted.org/packages/62/73/10df50b42ddb547a907deeb2f3c9823022580a7a47281e8eae8e003a9639/nh3-0.2.18.tar.gz"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_pkginfo_py3_none_any_889a6da2": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "pkginfo-1.10.0-py3-none-any.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "pkginfo==1.10.0",
+              "sha256": "889a6da2ed7ffc58ab5b900d888ddce90bce912f2d2de1dc1c26f4cb9fe65097",
+              "urls": [
+                "https://files.pythonhosted.org/packages/56/09/054aea9b7534a15ad38a363a2bd974c20646ab1582a387a95b8df1bfea1c/pkginfo-1.10.0-py3-none-any.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_pkginfo_sdist_5df73835": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "extra_pip_args": [
+                "--index-url",
+                "https://pypi.org/simple"
+              ],
+              "filename": "pkginfo-1.10.0.tar.gz",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "pkginfo==1.10.0",
+              "sha256": "5df73835398d10db79f8eecd5cd86b1f6d29317589ea70796994d49399af6297",
+              "urls": [
+                "https://files.pythonhosted.org/packages/2f/72/347ec5be4adc85c182ed2823d8d1c7b51e13b9a6b0c1aae59582eca652df/pkginfo-1.10.0.tar.gz"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_pycparser_py3_none_any_c3702b6d": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64"
+              ],
+              "filename": "pycparser-2.22-py3-none-any.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "pycparser==2.22",
+              "sha256": "c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc",
+              "urls": [
+                "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_pycparser_sdist_491c8be9": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64"
+              ],
+              "extra_pip_args": [
+                "--index-url",
+                "https://pypi.org/simple"
+              ],
+              "filename": "pycparser-2.22.tar.gz",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "pycparser==2.22",
+              "sha256": "491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6",
+              "urls": [
+                "https://files.pythonhosted.org/packages/1d/b2/31537cf4b1ca988837256c910a668b553fceb8f069bedc4b1c826024b52c/pycparser-2.22.tar.gz"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_pygments_py3_none_any_b8e6aca0": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "pygments-2.18.0-py3-none-any.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "pygments==2.18.0",
+              "sha256": "b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a",
+              "urls": [
+                "https://files.pythonhosted.org/packages/f7/3f/01c8b82017c199075f8f788d0d906b9ffbbc5a47dc9918a945e13d5a2bda/pygments-2.18.0-py3-none-any.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_pygments_sdist_786ff802": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "extra_pip_args": [
+                "--index-url",
+                "https://pypi.org/simple"
+              ],
+              "filename": "pygments-2.18.0.tar.gz",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "pygments==2.18.0",
+              "sha256": "786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199",
+              "urls": [
+                "https://files.pythonhosted.org/packages/8e/62/8336eff65bcbc8e4cb5d05b55faf041285951b6e80f33e2bff2024788f31/pygments-2.18.0.tar.gz"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_pywin32_ctypes_py3_none_any_8a151337": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_windows_x86_64"
+              ],
+              "filename": "pywin32_ctypes-0.2.3-py3-none-any.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "pywin32-ctypes==0.2.3",
+              "sha256": "8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8",
+              "urls": [
+                "https://files.pythonhosted.org/packages/de/3d/8161f7711c017e01ac9f008dfddd9410dff3674334c233bde66e7ba65bbf/pywin32_ctypes-0.2.3-py3-none-any.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_pywin32_ctypes_sdist_d162dc04": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_windows_x86_64"
+              ],
+              "extra_pip_args": [
+                "--index-url",
+                "https://pypi.org/simple"
+              ],
+              "filename": "pywin32-ctypes-0.2.3.tar.gz",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "pywin32-ctypes==0.2.3",
+              "sha256": "d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755",
+              "urls": [
+                "https://files.pythonhosted.org/packages/85/9f/01a1a99704853cb63f253eea009390c88e7131c67e66a0a02099a8c917cb/pywin32-ctypes-0.2.3.tar.gz"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_readme_renderer_py3_none_any_2fbca89b": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "readme_renderer-44.0-py3-none-any.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "readme-renderer==44.0",
+              "sha256": "2fbca89b81a08526aadf1357a8c2ae889ec05fb03f5da67f9769c9a592166151",
+              "urls": [
+                "https://files.pythonhosted.org/packages/e1/67/921ec3024056483db83953ae8e48079ad62b92db7880013ca77632921dd0/readme_renderer-44.0-py3-none-any.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_readme_renderer_sdist_8712034e": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "extra_pip_args": [
+                "--index-url",
+                "https://pypi.org/simple"
+              ],
+              "filename": "readme_renderer-44.0.tar.gz",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "readme-renderer==44.0",
+              "sha256": "8712034eabbfa6805cacf1402b4eeb2a73028f72d1166d6f5cb7f9c047c5d1e1",
+              "urls": [
+                "https://files.pythonhosted.org/packages/5a/a9/104ec9234c8448c4379768221ea6df01260cd6c2ce13182d4eac531c8342/readme_renderer-44.0.tar.gz"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_requests_py3_none_any_70761cfe": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "requests-2.32.3-py3-none-any.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "requests==2.32.3",
+              "sha256": "70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6",
+              "urls": [
+                "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_requests_sdist_55365417": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "extra_pip_args": [
+                "--index-url",
+                "https://pypi.org/simple"
+              ],
+              "filename": "requests-2.32.3.tar.gz",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "requests==2.32.3",
+              "sha256": "55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760",
+              "urls": [
+                "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_requests_toolbelt_py2_none_any_cccfdd66": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "requests_toolbelt-1.0.0-py2.py3-none-any.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "requests-toolbelt==1.0.0",
+              "sha256": "cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06",
+              "urls": [
+                "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_requests_toolbelt_sdist_7681a0a3": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "extra_pip_args": [
+                "--index-url",
+                "https://pypi.org/simple"
+              ],
+              "filename": "requests-toolbelt-1.0.0.tar.gz",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "requests-toolbelt==1.0.0",
+              "sha256": "7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6",
+              "urls": [
+                "https://files.pythonhosted.org/packages/f3/61/d7545dafb7ac2230c70d38d31cbfe4cc64f7144dc41f6e4e4b78ecd9f5bb/requests-toolbelt-1.0.0.tar.gz"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_rfc3986_py2_none_any_50b1502b": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "rfc3986-2.0.0-py2.py3-none-any.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "rfc3986==2.0.0",
+              "sha256": "50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd",
+              "urls": [
+                "https://files.pythonhosted.org/packages/ff/9a/9afaade874b2fa6c752c36f1548f718b5b83af81ed9b76628329dab81c1b/rfc3986-2.0.0-py2.py3-none-any.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_rfc3986_sdist_97aacf9d": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "extra_pip_args": [
+                "--index-url",
+                "https://pypi.org/simple"
+              ],
+              "filename": "rfc3986-2.0.0.tar.gz",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "rfc3986==2.0.0",
+              "sha256": "97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c",
+              "urls": [
+                "https://files.pythonhosted.org/packages/85/40/1520d68bfa07ab5a6f065a186815fb6610c86fe957bc065754e47f7b0840/rfc3986-2.0.0.tar.gz"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_rich_py3_none_any_9836f509": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "rich-13.9.3-py3-none-any.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "rich==13.9.3",
+              "sha256": "9836f5096eb2172c9e77df411c1b009bace4193d6a481d534fea75ebba758283",
+              "urls": [
+                "https://files.pythonhosted.org/packages/9a/e2/10e9819cf4a20bd8ea2f5dabafc2e6bf4a78d6a0965daeb60a4b34d1c11f/rich-13.9.3-py3-none-any.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_rich_sdist_bc1e01b8": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "extra_pip_args": [
+                "--index-url",
+                "https://pypi.org/simple"
+              ],
+              "filename": "rich-13.9.3.tar.gz",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "rich==13.9.3",
+              "sha256": "bc1e01b899537598cf02579d2b9f4a415104d3fc439313a7a2c165d76557a08e",
+              "urls": [
+                "https://files.pythonhosted.org/packages/d9/e9/cf9ef5245d835065e6673781dbd4b8911d352fb770d56cf0879cf11b7ee1/rich-13.9.3.tar.gz"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_secretstorage_py3_none_any_f356e662": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64"
+              ],
+              "filename": "SecretStorage-3.3.3-py3-none-any.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "secretstorage==3.3.3",
+              "sha256": "f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99",
+              "urls": [
+                "https://files.pythonhosted.org/packages/54/24/b4293291fa1dd830f353d2cb163295742fa87f179fcc8a20a306a81978b7/SecretStorage-3.3.3-py3-none-any.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_secretstorage_sdist_2403533e": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64"
+              ],
+              "extra_pip_args": [
+                "--index-url",
+                "https://pypi.org/simple"
+              ],
+              "filename": "SecretStorage-3.3.3.tar.gz",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "secretstorage==3.3.3",
+              "sha256": "2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77",
+              "urls": [
+                "https://files.pythonhosted.org/packages/53/a4/f48c9d79cb507ed1373477dbceaba7401fd8a23af63b837fa61f1dcd3691/SecretStorage-3.3.3.tar.gz"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_twine_py3_none_any_215dbe7b": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "twine-5.1.1-py3-none-any.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "twine==5.1.1",
+              "sha256": "215dbe7b4b94c2c50a7315c0275d2258399280fbb7d04182c7e55e24b5f93997",
+              "urls": [
+                "https://files.pythonhosted.org/packages/5d/ec/00f9d5fd040ae29867355e559a94e9a8429225a0284a3f5f091a3878bfc0/twine-5.1.1-py3-none-any.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_twine_sdist_9aa08251": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "extra_pip_args": [
+                "--index-url",
+                "https://pypi.org/simple"
+              ],
+              "filename": "twine-5.1.1.tar.gz",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "twine==5.1.1",
+              "sha256": "9aa0825139c02b3434d913545c7b847a21c835e11597f5255842d457da2322db",
+              "urls": [
+                "https://files.pythonhosted.org/packages/77/68/bd982e5e949ef8334e6f7dcf76ae40922a8750aa2e347291ae1477a4782b/twine-5.1.1.tar.gz"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_urllib3_py3_none_any_ca899ca0": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "urllib3-2.2.3-py3-none-any.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "urllib3==2.2.3",
+              "sha256": "ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac",
+              "urls": [
+                "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_urllib3_sdist_e7d814a8": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "extra_pip_args": [
+                "--index-url",
+                "https://pypi.org/simple"
+              ],
+              "filename": "urllib3-2.2.3.tar.gz",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "urllib3==2.2.3",
+              "sha256": "e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9",
+              "urls": [
+                "https://files.pythonhosted.org/packages/ed/63/22ba4ebfe7430b76388e7cd448d5478814d3032121827c12a2cc287e2260/urllib3-2.2.3.tar.gz"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_zipp_py3_none_any_a817ac80": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "filename": "zipp-3.20.2-py3-none-any.whl",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "zipp==3.20.2",
+              "sha256": "a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350",
+              "urls": [
+                "https://files.pythonhosted.org/packages/62/8b/5ba542fa83c90e09eac972fc9baca7a88e7e7ca4b221a89251954019308b/zipp-3.20.2-py3-none-any.whl"
+              ]
+            }
+          },
+          "rules_python_publish_deps_311_zipp_sdist_bc9eb26f": {
+            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
+            "ruleClassName": "whl_library",
+            "attributes": {
+              "dep_template": "@rules_python_publish_deps//{name}:{target}",
+              "experimental_target_platforms": [
+                "cp311_linux_aarch64",
+                "cp311_linux_arm",
+                "cp311_linux_ppc",
+                "cp311_linux_s390x",
+                "cp311_linux_x86_64",
+                "cp311_osx_aarch64",
+                "cp311_osx_x86_64",
+                "cp311_windows_x86_64"
+              ],
+              "extra_pip_args": [
+                "--index-url",
+                "https://pypi.org/simple"
+              ],
+              "filename": "zipp-3.20.2.tar.gz",
+              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
+              "repo": "rules_python_publish_deps_311",
+              "requirement": "zipp==3.20.2",
+              "sha256": "bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29",
+              "urls": [
+                "https://files.pythonhosted.org/packages/54/bf/5c0000c44ebc80123ecbdddba1f5dcd94a5ada602a9c225d84b5aaa55e86/zipp-3.20.2.tar.gz"
+              ]
+            }
+          },
+          "rules_python_publish_deps": {
+            "bzlFile": "@@rules_python~//python/private/pypi:hub_repository.bzl",
+            "ruleClassName": "hub_repository",
+            "attributes": {
+              "repo_name": "rules_python_publish_deps",
+              "extra_hub_aliases": {},
+              "whl_map": {
+                "backports_tarfile": "{\"rules_python_publish_deps_311_backports_tarfile_py3_none_any_77e284d7\":[{\"filename\":\"backports.tarfile-1.2.0-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_backports_tarfile_sdist_d75e02c2\":[{\"filename\":\"backports_tarfile-1.2.0.tar.gz\",\"version\":\"3.11\"}]}",
+                "certifi": "{\"rules_python_publish_deps_311_certifi_py3_none_any_922820b5\":[{\"filename\":\"certifi-2024.8.30-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_certifi_sdist_bec941d2\":[{\"filename\":\"certifi-2024.8.30.tar.gz\",\"version\":\"3.11\"}]}",
+                "cffi": "{\"rules_python_publish_deps_311_cffi_cp311_cp311_manylinux_2_17_aarch64_a1ed2dd2\":[{\"filename\":\"cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_cffi_cp311_cp311_manylinux_2_17_ppc64le_46bf4316\":[{\"filename\":\"cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_cffi_cp311_cp311_manylinux_2_17_s390x_a24ed04c\":[{\"filename\":\"cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_cffi_cp311_cp311_manylinux_2_17_x86_64_610faea7\":[{\"filename\":\"cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_cffi_cp311_cp311_musllinux_1_1_aarch64_a9b15d49\":[{\"filename\":\"cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_cffi_cp311_cp311_musllinux_1_1_x86_64_fc48c783\":[{\"filename\":\"cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_cffi_sdist_1c39c601\":[{\"filename\":\"cffi-1.17.1.tar.gz\",\"version\":\"3.11\"}]}",
+                "charset_normalizer": "{\"rules_python_publish_deps_311_charset_normalizer_cp311_cp311_macosx_10_9_universal2_0d99dd8f\":[{\"filename\":\"charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_charset_normalizer_cp311_cp311_macosx_10_9_x86_64_c57516e5\":[{\"filename\":\"charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_charset_normalizer_cp311_cp311_macosx_11_0_arm64_6dba5d19\":[{\"filename\":\"charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_charset_normalizer_cp311_cp311_manylinux_2_17_aarch64_bf4475b8\":[{\"filename\":\"charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_charset_normalizer_cp311_cp311_manylinux_2_17_ppc64le_ce031db0\":[{\"filename\":\"charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_charset_normalizer_cp311_cp311_manylinux_2_17_s390x_8ff4e7cd\":[{\"filename\":\"charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_charset_normalizer_cp311_cp311_manylinux_2_17_x86_64_3710a975\":[{\"filename\":\"charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_charset_normalizer_cp311_cp311_musllinux_1_2_aarch64_47334db7\":[{\"filename\":\"charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_charset_normalizer_cp311_cp311_musllinux_1_2_ppc64le_f1a2f519\":[{\"filename\":\"charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_charset_normalizer_cp311_cp311_musllinux_1_2_s390x_63bc5c4a\":[{\"filename\":\"charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_charset_normalizer_cp311_cp311_musllinux_1_2_x86_64_bcb4f8ea\":[{\"filename\":\"charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_charset_normalizer_cp311_cp311_win_amd64_cee4373f\":[{\"filename\":\"charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_charset_normalizer_py3_none_any_fe9f97fe\":[{\"filename\":\"charset_normalizer-3.4.0-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_charset_normalizer_sdist_223217c3\":[{\"filename\":\"charset_normalizer-3.4.0.tar.gz\",\"version\":\"3.11\"}]}",
+                "cryptography": "{\"rules_python_publish_deps_311_cryptography_cp39_abi3_manylinux_2_17_aarch64_846da004\":[{\"filename\":\"cryptography-43.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_cryptography_cp39_abi3_manylinux_2_17_x86_64_0f996e72\":[{\"filename\":\"cryptography-43.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_cryptography_cp39_abi3_manylinux_2_28_aarch64_f7b178f1\":[{\"filename\":\"cryptography-43.0.3-cp39-abi3-manylinux_2_28_aarch64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_cryptography_cp39_abi3_manylinux_2_28_x86_64_c2e6fc39\":[{\"filename\":\"cryptography-43.0.3-cp39-abi3-manylinux_2_28_x86_64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_cryptography_cp39_abi3_musllinux_1_2_aarch64_e1be4655\":[{\"filename\":\"cryptography-43.0.3-cp39-abi3-musllinux_1_2_aarch64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_cryptography_cp39_abi3_musllinux_1_2_x86_64_df6b6c6d\":[{\"filename\":\"cryptography-43.0.3-cp39-abi3-musllinux_1_2_x86_64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_cryptography_sdist_315b9001\":[{\"filename\":\"cryptography-43.0.3.tar.gz\",\"version\":\"3.11\"}]}",
+                "docutils": "{\"rules_python_publish_deps_311_docutils_py3_none_any_dafca5b9\":[{\"filename\":\"docutils-0.21.2-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_docutils_sdist_3a6b1873\":[{\"filename\":\"docutils-0.21.2.tar.gz\",\"version\":\"3.11\"}]}",
+                "idna": "{\"rules_python_publish_deps_311_idna_py3_none_any_946d195a\":[{\"filename\":\"idna-3.10-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_idna_sdist_12f65c9b\":[{\"filename\":\"idna-3.10.tar.gz\",\"version\":\"3.11\"}]}",
+                "importlib_metadata": "{\"rules_python_publish_deps_311_importlib_metadata_py3_none_any_45e54197\":[{\"filename\":\"importlib_metadata-8.5.0-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_importlib_metadata_sdist_71522656\":[{\"filename\":\"importlib_metadata-8.5.0.tar.gz\",\"version\":\"3.11\"}]}",
+                "jaraco_classes": "{\"rules_python_publish_deps_311_jaraco_classes_py3_none_any_f662826b\":[{\"filename\":\"jaraco.classes-3.4.0-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_jaraco_classes_sdist_47a024b5\":[{\"filename\":\"jaraco.classes-3.4.0.tar.gz\",\"version\":\"3.11\"}]}",
+                "jaraco_context": "{\"rules_python_publish_deps_311_jaraco_context_py3_none_any_f797fc48\":[{\"filename\":\"jaraco.context-6.0.1-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_jaraco_context_sdist_9bae4ea5\":[{\"filename\":\"jaraco_context-6.0.1.tar.gz\",\"version\":\"3.11\"}]}",
+                "jaraco_functools": "{\"rules_python_publish_deps_311_jaraco_functools_py3_none_any_ad159f13\":[{\"filename\":\"jaraco.functools-4.1.0-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_jaraco_functools_sdist_70f7e0e2\":[{\"filename\":\"jaraco_functools-4.1.0.tar.gz\",\"version\":\"3.11\"}]}",
+                "jeepney": "{\"rules_python_publish_deps_311_jeepney_py3_none_any_c0a454ad\":[{\"filename\":\"jeepney-0.8.0-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_jeepney_sdist_5efe48d2\":[{\"filename\":\"jeepney-0.8.0.tar.gz\",\"version\":\"3.11\"}]}",
+                "keyring": "{\"rules_python_publish_deps_311_keyring_py3_none_any_5426f817\":[{\"filename\":\"keyring-25.4.1-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_keyring_sdist_b07ebc55\":[{\"filename\":\"keyring-25.4.1.tar.gz\",\"version\":\"3.11\"}]}",
+                "markdown_it_py": "{\"rules_python_publish_deps_311_markdown_it_py_py3_none_any_35521684\":[{\"filename\":\"markdown_it_py-3.0.0-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_markdown_it_py_sdist_e3f60a94\":[{\"filename\":\"markdown-it-py-3.0.0.tar.gz\",\"version\":\"3.11\"}]}",
+                "mdurl": "{\"rules_python_publish_deps_311_mdurl_py3_none_any_84008a41\":[{\"filename\":\"mdurl-0.1.2-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_mdurl_sdist_bb413d29\":[{\"filename\":\"mdurl-0.1.2.tar.gz\",\"version\":\"3.11\"}]}",
+                "more_itertools": "{\"rules_python_publish_deps_311_more_itertools_py3_none_any_037b0d32\":[{\"filename\":\"more_itertools-10.5.0-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_more_itertools_sdist_5482bfef\":[{\"filename\":\"more-itertools-10.5.0.tar.gz\",\"version\":\"3.11\"}]}",
+                "nh3": "{\"rules_python_publish_deps_311_nh3_cp37_abi3_macosx_10_12_x86_64_14c5a72e\":[{\"filename\":\"nh3-0.2.18-cp37-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_nh3_cp37_abi3_macosx_10_12_x86_64_7b7c2a3c\":[{\"filename\":\"nh3-0.2.18-cp37-abi3-macosx_10_12_x86_64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_nh3_cp37_abi3_manylinux_2_17_aarch64_42c64511\":[{\"filename\":\"nh3-0.2.18-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_nh3_cp37_abi3_manylinux_2_17_armv7l_0411beb0\":[{\"filename\":\"nh3-0.2.18-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_nh3_cp37_abi3_manylinux_2_17_ppc64_5f36b271\":[{\"filename\":\"nh3-0.2.18-cp37-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_nh3_cp37_abi3_manylinux_2_17_ppc64le_34c03fa7\":[{\"filename\":\"nh3-0.2.18-cp37-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_nh3_cp37_abi3_manylinux_2_17_s390x_19aaba96\":[{\"filename\":\"nh3-0.2.18-cp37-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_nh3_cp37_abi3_manylinux_2_17_x86_64_de3ceed6\":[{\"filename\":\"nh3-0.2.18-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_nh3_cp37_abi3_musllinux_1_2_aarch64_f0eca9ca\":[{\"filename\":\"nh3-0.2.18-cp37-abi3-musllinux_1_2_aarch64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_nh3_cp37_abi3_musllinux_1_2_armv7l_3a157ab1\":[{\"filename\":\"nh3-0.2.18-cp37-abi3-musllinux_1_2_armv7l.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_nh3_cp37_abi3_musllinux_1_2_x86_64_36c95d4b\":[{\"filename\":\"nh3-0.2.18-cp37-abi3-musllinux_1_2_x86_64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_nh3_cp37_abi3_win_amd64_8ce0f819\":[{\"filename\":\"nh3-0.2.18-cp37-abi3-win_amd64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_nh3_sdist_94a16692\":[{\"filename\":\"nh3-0.2.18.tar.gz\",\"version\":\"3.11\"}]}",
+                "pkginfo": "{\"rules_python_publish_deps_311_pkginfo_py3_none_any_889a6da2\":[{\"filename\":\"pkginfo-1.10.0-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_pkginfo_sdist_5df73835\":[{\"filename\":\"pkginfo-1.10.0.tar.gz\",\"version\":\"3.11\"}]}",
+                "pycparser": "{\"rules_python_publish_deps_311_pycparser_py3_none_any_c3702b6d\":[{\"filename\":\"pycparser-2.22-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_pycparser_sdist_491c8be9\":[{\"filename\":\"pycparser-2.22.tar.gz\",\"version\":\"3.11\"}]}",
+                "pygments": "{\"rules_python_publish_deps_311_pygments_py3_none_any_b8e6aca0\":[{\"filename\":\"pygments-2.18.0-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_pygments_sdist_786ff802\":[{\"filename\":\"pygments-2.18.0.tar.gz\",\"version\":\"3.11\"}]}",
+                "pywin32_ctypes": "{\"rules_python_publish_deps_311_pywin32_ctypes_py3_none_any_8a151337\":[{\"filename\":\"pywin32_ctypes-0.2.3-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_pywin32_ctypes_sdist_d162dc04\":[{\"filename\":\"pywin32-ctypes-0.2.3.tar.gz\",\"version\":\"3.11\"}]}",
+                "readme_renderer": "{\"rules_python_publish_deps_311_readme_renderer_py3_none_any_2fbca89b\":[{\"filename\":\"readme_renderer-44.0-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_readme_renderer_sdist_8712034e\":[{\"filename\":\"readme_renderer-44.0.tar.gz\",\"version\":\"3.11\"}]}",
+                "requests": "{\"rules_python_publish_deps_311_requests_py3_none_any_70761cfe\":[{\"filename\":\"requests-2.32.3-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_requests_sdist_55365417\":[{\"filename\":\"requests-2.32.3.tar.gz\",\"version\":\"3.11\"}]}",
+                "requests_toolbelt": "{\"rules_python_publish_deps_311_requests_toolbelt_py2_none_any_cccfdd66\":[{\"filename\":\"requests_toolbelt-1.0.0-py2.py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_requests_toolbelt_sdist_7681a0a3\":[{\"filename\":\"requests-toolbelt-1.0.0.tar.gz\",\"version\":\"3.11\"}]}",
+                "rfc3986": "{\"rules_python_publish_deps_311_rfc3986_py2_none_any_50b1502b\":[{\"filename\":\"rfc3986-2.0.0-py2.py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_rfc3986_sdist_97aacf9d\":[{\"filename\":\"rfc3986-2.0.0.tar.gz\",\"version\":\"3.11\"}]}",
+                "rich": "{\"rules_python_publish_deps_311_rich_py3_none_any_9836f509\":[{\"filename\":\"rich-13.9.3-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_rich_sdist_bc1e01b8\":[{\"filename\":\"rich-13.9.3.tar.gz\",\"version\":\"3.11\"}]}",
+                "secretstorage": "{\"rules_python_publish_deps_311_secretstorage_py3_none_any_f356e662\":[{\"filename\":\"SecretStorage-3.3.3-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_secretstorage_sdist_2403533e\":[{\"filename\":\"SecretStorage-3.3.3.tar.gz\",\"version\":\"3.11\"}]}",
+                "twine": "{\"rules_python_publish_deps_311_twine_py3_none_any_215dbe7b\":[{\"filename\":\"twine-5.1.1-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_twine_sdist_9aa08251\":[{\"filename\":\"twine-5.1.1.tar.gz\",\"version\":\"3.11\"}]}",
+                "urllib3": "{\"rules_python_publish_deps_311_urllib3_py3_none_any_ca899ca0\":[{\"filename\":\"urllib3-2.2.3-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_urllib3_sdist_e7d814a8\":[{\"filename\":\"urllib3-2.2.3.tar.gz\",\"version\":\"3.11\"}]}",
+                "zipp": "{\"rules_python_publish_deps_311_zipp_py3_none_any_a817ac80\":[{\"filename\":\"zipp-3.20.2-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_zipp_sdist_bc9eb26f\":[{\"filename\":\"zipp-3.20.2.tar.gz\",\"version\":\"3.11\"}]}"
+              },
+              "packages": [
+                "backports_tarfile",
+                "certifi",
+                "charset_normalizer",
+                "docutils",
+                "idna",
+                "importlib_metadata",
+                "jaraco_classes",
+                "jaraco_context",
+                "jaraco_functools",
+                "keyring",
+                "markdown_it_py",
+                "mdurl",
+                "more_itertools",
+                "nh3",
+                "pkginfo",
+                "pygments",
+                "readme_renderer",
+                "requests",
+                "requests_toolbelt",
+                "rfc3986",
+                "rich",
+                "twine",
+                "urllib3",
+                "zipp"
+              ],
+              "groups": {}
             }
           }
         },
+        "moduleExtensionMetadata": {
+          "useAllRepos": "NO",
+          "reproducible": false
+        },
         "recordedRepoMappingEntries": [
           [
+            "bazel_features~",
+            "bazel_features_globals",
+            "bazel_features~~version_extension~bazel_features_globals"
+          ],
+          [
+            "bazel_features~",
+            "bazel_features_version",
+            "bazel_features~~version_extension~bazel_features_version"
+          ],
+          [
             "rules_python~",
-            "bazel_tools",
-            "bazel_tools"
-          ]
-        ]
-      }
-    },
-    "@@rules_python~//python/extensions/private:internal_deps.bzl%internal_deps": {
-      "general": {
-        "bzlTransitiveDigest": "HZia2x2zClxBbkyhPtNWVBPeKOTV8j7xJuwILyef0YY=",
-        "usagesDigest": "9RSsqSb2/36w50hPv3LjfktbwXR/5SiHNcdkp4m2BVA=",
-        "recordedFileInputs": {},
-        "recordedDirentsInputs": {},
-        "envVariables": {},
-        "generatedRepoSpecs": {
-          "pypi__build": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
-            "attributes": {
-              "url": "https://files.pythonhosted.org/packages/03/97/f58c723ff036a8d8b4d3115377c0a37ed05c1f68dd9a0d66dab5e82c5c1c/build-0.9.0-py3-none-any.whl",
-              "sha256": "38a7a2b7a0bdc61a42a0a67509d88c71ecfc37b393baba770fae34e20929ff69",
-              "type": "zip",
-              "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n    name = \"lib\",\n    srcs = glob([\"**/*.py\"]),\n    data = glob([\"**/*\"], exclude=[\n        # These entries include those put into user-installed dependencies by\n        # data_exclude in /python/pip_install/tools/bazel.py\n        # to avoid non-determinism following pip install's behavior.\n        \"**/*.py\",\n        \"**/*.pyc\",\n        \"**/* *\",\n        \"**/*.dist-info/RECORD\",\n        \"BUILD\",\n        \"WORKSPACE\",\n    ]),\n    # This makes this directory a top-level in the python import\n    # search path for anything that depends on this.\n    imports = [\".\"],\n)\n"
-            }
-          },
-          "pypi__click": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
-            "attributes": {
-              "url": "https://files.pythonhosted.org/packages/76/0a/b6c5f311e32aeb3b406e03c079ade51e905ea630fc19d1262a46249c1c86/click-8.0.1-py3-none-any.whl",
-              "sha256": "fba402a4a47334742d782209a7c79bc448911afe1149d07bdabdf480b3e2f4b6",
-              "type": "zip",
-              "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n    name = \"lib\",\n    srcs = glob([\"**/*.py\"]),\n    data = glob([\"**/*\"], exclude=[\n        # These entries include those put into user-installed dependencies by\n        # data_exclude in /python/pip_install/tools/bazel.py\n        # to avoid non-determinism following pip install's behavior.\n        \"**/*.py\",\n        \"**/*.pyc\",\n        \"**/* *\",\n        \"**/*.dist-info/RECORD\",\n        \"BUILD\",\n        \"WORKSPACE\",\n    ]),\n    # This makes this directory a top-level in the python import\n    # search path for anything that depends on this.\n    imports = [\".\"],\n)\n"
-            }
-          },
-          "pypi__colorama": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
-            "attributes": {
-              "url": "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl",
-              "sha256": "4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6",
-              "type": "zip",
-              "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n    name = \"lib\",\n    srcs = glob([\"**/*.py\"]),\n    data = glob([\"**/*\"], exclude=[\n        # These entries include those put into user-installed dependencies by\n        # data_exclude in /python/pip_install/tools/bazel.py\n        # to avoid non-determinism following pip install's behavior.\n        \"**/*.py\",\n        \"**/*.pyc\",\n        \"**/* *\",\n        \"**/*.dist-info/RECORD\",\n        \"BUILD\",\n        \"WORKSPACE\",\n    ]),\n    # This makes this directory a top-level in the python import\n    # search path for anything that depends on this.\n    imports = [\".\"],\n)\n"
-            }
-          },
-          "pypi__installer": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
-            "attributes": {
-              "url": "https://files.pythonhosted.org/packages/e5/ca/1172b6638d52f2d6caa2dd262ec4c811ba59eee96d54a7701930726bce18/installer-0.7.0-py3-none-any.whl",
-              "sha256": "05d1933f0a5ba7d8d6296bb6d5018e7c94fa473ceb10cf198a92ccea19c27b53",
-              "type": "zip",
-              "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n    name = \"lib\",\n    srcs = glob([\"**/*.py\"]),\n    data = glob([\"**/*\"], exclude=[\n        # These entries include those put into user-installed dependencies by\n        # data_exclude in /python/pip_install/tools/bazel.py\n        # to avoid non-determinism following pip install's behavior.\n        \"**/*.py\",\n        \"**/*.pyc\",\n        \"**/* *\",\n        \"**/*.dist-info/RECORD\",\n        \"BUILD\",\n        \"WORKSPACE\",\n    ]),\n    # This makes this directory a top-level in the python import\n    # search path for anything that depends on this.\n    imports = [\".\"],\n)\n"
-            }
-          },
-          "pypi__packaging": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
-            "attributes": {
-              "url": "https://files.pythonhosted.org/packages/8f/7b/42582927d281d7cb035609cd3a543ffac89b74f3f4ee8e1c50914bcb57eb/packaging-22.0-py3-none-any.whl",
-              "sha256": "957e2148ba0e1a3b282772e791ef1d8083648bc131c8ab0c1feba110ce1146c3",
-              "type": "zip",
-              "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n    name = \"lib\",\n    srcs = glob([\"**/*.py\"]),\n    data = glob([\"**/*\"], exclude=[\n        # These entries include those put into user-installed dependencies by\n        # data_exclude in /python/pip_install/tools/bazel.py\n        # to avoid non-determinism following pip install's behavior.\n        \"**/*.py\",\n        \"**/*.pyc\",\n        \"**/* *\",\n        \"**/*.dist-info/RECORD\",\n        \"BUILD\",\n        \"WORKSPACE\",\n    ]),\n    # This makes this directory a top-level in the python import\n    # search path for anything that depends on this.\n    imports = [\".\"],\n)\n"
-            }
-          },
-          "pypi__pep517": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
-            "attributes": {
-              "url": "https://files.pythonhosted.org/packages/ee/2f/ef63e64e9429111e73d3d6cbee80591672d16f2725e648ebc52096f3d323/pep517-0.13.0-py3-none-any.whl",
-              "sha256": "4ba4446d80aed5b5eac6509ade100bff3e7943a8489de249654a5ae9b33ee35b",
-              "type": "zip",
-              "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n    name = \"lib\",\n    srcs = glob([\"**/*.py\"]),\n    data = glob([\"**/*\"], exclude=[\n        # These entries include those put into user-installed dependencies by\n        # data_exclude in /python/pip_install/tools/bazel.py\n        # to avoid non-determinism following pip install's behavior.\n        \"**/*.py\",\n        \"**/*.pyc\",\n        \"**/* *\",\n        \"**/*.dist-info/RECORD\",\n        \"BUILD\",\n        \"WORKSPACE\",\n    ]),\n    # This makes this directory a top-level in the python import\n    # search path for anything that depends on this.\n    imports = [\".\"],\n)\n"
-            }
-          },
-          "pypi__pip": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
-            "attributes": {
-              "url": "https://files.pythonhosted.org/packages/09/bd/2410905c76ee14c62baf69e3f4aa780226c1bbfc9485731ad018e35b0cb5/pip-22.3.1-py3-none-any.whl",
-              "sha256": "908c78e6bc29b676ede1c4d57981d490cb892eb45cd8c214ab6298125119e077",
-              "type": "zip",
-              "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n    name = \"lib\",\n    srcs = glob([\"**/*.py\"]),\n    data = glob([\"**/*\"], exclude=[\n        # These entries include those put into user-installed dependencies by\n        # data_exclude in /python/pip_install/tools/bazel.py\n        # to avoid non-determinism following pip install's behavior.\n        \"**/*.py\",\n        \"**/*.pyc\",\n        \"**/* *\",\n        \"**/*.dist-info/RECORD\",\n        \"BUILD\",\n        \"WORKSPACE\",\n    ]),\n    # This makes this directory a top-level in the python import\n    # search path for anything that depends on this.\n    imports = [\".\"],\n)\n"
-            }
-          },
-          "pypi__pip_tools": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
-            "attributes": {
-              "url": "https://files.pythonhosted.org/packages/5e/e8/f6d7d1847c7351048da870417724ace5c4506e816b38db02f4d7c675c189/pip_tools-6.12.1-py3-none-any.whl",
-              "sha256": "f0c0c0ec57b58250afce458e2e6058b1f30a4263db895b7d72fd6311bf1dc6f7",
-              "type": "zip",
-              "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n    name = \"lib\",\n    srcs = glob([\"**/*.py\"]),\n    data = glob([\"**/*\"], exclude=[\n        # These entries include those put into user-installed dependencies by\n        # data_exclude in /python/pip_install/tools/bazel.py\n        # to avoid non-determinism following pip install's behavior.\n        \"**/*.py\",\n        \"**/*.pyc\",\n        \"**/* *\",\n        \"**/*.dist-info/RECORD\",\n        \"BUILD\",\n        \"WORKSPACE\",\n    ]),\n    # This makes this directory a top-level in the python import\n    # search path for anything that depends on this.\n    imports = [\".\"],\n)\n"
-            }
-          },
-          "pypi__setuptools": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
-            "attributes": {
-              "url": "https://files.pythonhosted.org/packages/7c/5b/3d92b9f0f7ca1645cba48c080b54fe7d8b1033a4e5720091d1631c4266db/setuptools-60.10.0-py3-none-any.whl",
-              "sha256": "782ef48d58982ddb49920c11a0c5c9c0b02e7d7d1c2ad0aa44e1a1e133051c96",
-              "type": "zip",
-              "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n    name = \"lib\",\n    srcs = glob([\"**/*.py\"]),\n    data = glob([\"**/*\"], exclude=[\n        # These entries include those put into user-installed dependencies by\n        # data_exclude in /python/pip_install/tools/bazel.py\n        # to avoid non-determinism following pip install's behavior.\n        \"**/*.py\",\n        \"**/*.pyc\",\n        \"**/* *\",\n        \"**/*.dist-info/RECORD\",\n        \"BUILD\",\n        \"WORKSPACE\",\n    ]),\n    # This makes this directory a top-level in the python import\n    # search path for anything that depends on this.\n    imports = [\".\"],\n)\n"
-            }
-          },
-          "pypi__tomli": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
-            "attributes": {
-              "url": "https://files.pythonhosted.org/packages/97/75/10a9ebee3fd790d20926a90a2547f0bf78f371b2f13aa822c759680ca7b9/tomli-2.0.1-py3-none-any.whl",
-              "sha256": "939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc",
-              "type": "zip",
-              "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n    name = \"lib\",\n    srcs = glob([\"**/*.py\"]),\n    data = glob([\"**/*\"], exclude=[\n        # These entries include those put into user-installed dependencies by\n        # data_exclude in /python/pip_install/tools/bazel.py\n        # to avoid non-determinism following pip install's behavior.\n        \"**/*.py\",\n        \"**/*.pyc\",\n        \"**/* *\",\n        \"**/*.dist-info/RECORD\",\n        \"BUILD\",\n        \"WORKSPACE\",\n    ]),\n    # This makes this directory a top-level in the python import\n    # search path for anything that depends on this.\n    imports = [\".\"],\n)\n"
-            }
-          },
-          "pypi__wheel": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
-            "attributes": {
-              "url": "https://files.pythonhosted.org/packages/bd/7c/d38a0b30ce22fc26ed7dbc087c6d00851fb3395e9d0dac40bec1f905030c/wheel-0.38.4-py3-none-any.whl",
-              "sha256": "b60533f3f5d530e971d6737ca6d58681ee434818fab630c83a734bb10c083ce8",
-              "type": "zip",
-              "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n    name = \"lib\",\n    srcs = glob([\"**/*.py\"]),\n    data = glob([\"**/*\"], exclude=[\n        # These entries include those put into user-installed dependencies by\n        # data_exclude in /python/pip_install/tools/bazel.py\n        # to avoid non-determinism following pip install's behavior.\n        \"**/*.py\",\n        \"**/*.pyc\",\n        \"**/* *\",\n        \"**/*.dist-info/RECORD\",\n        \"BUILD\",\n        \"WORKSPACE\",\n    ]),\n    # This makes this directory a top-level in the python import\n    # search path for anything that depends on this.\n    imports = [\".\"],\n)\n"
-            }
-          },
-          "pypi__importlib_metadata": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
-            "attributes": {
-              "url": "https://files.pythonhosted.org/packages/d7/31/74dcb59a601b95fce3b0334e8fc9db758f78e43075f22aeb3677dfb19f4c/importlib_metadata-1.4.0-py2.py3-none-any.whl",
-              "sha256": "bdd9b7c397c273bcc9a11d6629a38487cd07154fa255a467bf704cd2c258e359",
-              "type": "zip",
-              "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n    name = \"lib\",\n    srcs = glob([\"**/*.py\"]),\n    data = glob([\"**/*\"], exclude=[\n        # These entries include those put into user-installed dependencies by\n        # data_exclude in /python/pip_install/tools/bazel.py\n        # to avoid non-determinism following pip install's behavior.\n        \"**/*.py\",\n        \"**/*.pyc\",\n        \"**/* *\",\n        \"**/*.dist-info/RECORD\",\n        \"BUILD\",\n        \"WORKSPACE\",\n    ]),\n    # This makes this directory a top-level in the python import\n    # search path for anything that depends on this.\n    imports = [\".\"],\n)\n"
-            }
-          },
-          "pypi__zipp": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
-            "attributes": {
-              "url": "https://files.pythonhosted.org/packages/f4/50/cc72c5bcd48f6e98219fc4a88a5227e9e28b81637a99c49feba1d51f4d50/zipp-1.0.0-py2.py3-none-any.whl",
-              "sha256": "8dda78f06bd1674bd8720df8a50bb47b6e1233c503a4eed8e7810686bde37656",
-              "type": "zip",
-              "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n    name = \"lib\",\n    srcs = glob([\"**/*.py\"]),\n    data = glob([\"**/*\"], exclude=[\n        # These entries include those put into user-installed dependencies by\n        # data_exclude in /python/pip_install/tools/bazel.py\n        # to avoid non-determinism following pip install's behavior.\n        \"**/*.py\",\n        \"**/*.pyc\",\n        \"**/* *\",\n        \"**/*.dist-info/RECORD\",\n        \"BUILD\",\n        \"WORKSPACE\",\n    ]),\n    # This makes this directory a top-level in the python import\n    # search path for anything that depends on this.\n    imports = [\".\"],\n)\n"
-            }
-          },
-          "pypi__more_itertools": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
-            "attributes": {
-              "url": "https://files.pythonhosted.org/packages/bd/3f/c4b3dbd315e248f84c388bd4a72b131a29f123ecacc37ffb2b3834546e42/more_itertools-8.13.0-py3-none-any.whl",
-              "sha256": "c5122bffc5f104d37c1626b8615b511f3427aa5389b94d61e5ef8236bfbc3ddb",
-              "type": "zip",
-              "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n    name = \"lib\",\n    srcs = glob([\"**/*.py\"]),\n    data = glob([\"**/*\"], exclude=[\n        # These entries include those put into user-installed dependencies by\n        # data_exclude in /python/pip_install/tools/bazel.py\n        # to avoid non-determinism following pip install's behavior.\n        \"**/*.py\",\n        \"**/*.pyc\",\n        \"**/* *\",\n        \"**/*.dist-info/RECORD\",\n        \"BUILD\",\n        \"WORKSPACE\",\n    ]),\n    # This makes this directory a top-level in the python import\n    # search path for anything that depends on this.\n    imports = [\".\"],\n)\n"
-            }
-          },
-          "pypi__coverage_cp38_aarch64-apple-darwin": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
-            "attributes": {
-              "build_file_content": "\nfilegroup(\n    name = \"coverage\",\n    srcs = [\"coverage/__main__.py\"],\n    data = glob([\"coverage/*.py\", \"coverage/**/*.py\", \"coverage/*.so\"]),\n    visibility = [\"//visibility:public\"],\n)\n    ",
-              "patch_args": [
-                "-p1"
-              ],
-              "patches": [
-                "@@rules_python~//python/private:coverage.patch"
-              ],
-              "sha256": "3d376df58cc111dc8e21e3b6e24606b5bb5dee6024f46a5abca99124b2229ef5",
-              "type": "zip",
-              "urls": [
-                "https://files.pythonhosted.org/packages/28/d7/9a8de57d87f4bbc6f9a6a5ded1eaac88a89bf71369bb935dac3c0cf2893e/coverage-7.2.7-cp38-cp38-macosx_11_0_arm64.whl"
-              ]
-            }
-          },
-          "pypi__coverage_cp38_aarch64-unknown-linux-gnu": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
-            "attributes": {
-              "build_file_content": "\nfilegroup(\n    name = \"coverage\",\n    srcs = [\"coverage/__main__.py\"],\n    data = glob([\"coverage/*.py\", \"coverage/**/*.py\", \"coverage/*.so\"]),\n    visibility = [\"//visibility:public\"],\n)\n    ",
-              "patch_args": [
-                "-p1"
-              ],
-              "patches": [
-                "@@rules_python~//python/private:coverage.patch"
-              ],
-              "sha256": "5e330fc79bd7207e46c7d7fd2bb4af2963f5f635703925543a70b99574b0fea9",
-              "type": "zip",
-              "urls": [
-                "https://files.pythonhosted.org/packages/c8/e4/e6182e4697665fb594a7f4e4f27cb3a4dd00c2e3d35c5c706765de8c7866/coverage-7.2.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"
-              ]
-            }
-          },
-          "pypi__coverage_cp38_x86_64-apple-darwin": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
-            "attributes": {
-              "build_file_content": "\nfilegroup(\n    name = \"coverage\",\n    srcs = [\"coverage/__main__.py\"],\n    data = glob([\"coverage/*.py\", \"coverage/**/*.py\", \"coverage/*.so\"]),\n    visibility = [\"//visibility:public\"],\n)\n    ",
-              "patch_args": [
-                "-p1"
-              ],
-              "patches": [
-                "@@rules_python~//python/private:coverage.patch"
-              ],
-              "sha256": "54b896376ab563bd38453cecb813c295cf347cf5906e8b41d340b0321a5433e5",
-              "type": "zip",
-              "urls": [
-                "https://files.pythonhosted.org/packages/c6/fc/be19131010930a6cf271da48202c8cc1d3f971f68c02fb2d3a78247f43dc/coverage-7.2.7-cp38-cp38-macosx_10_9_x86_64.whl"
-              ]
-            }
-          },
-          "pypi__coverage_cp38_x86_64-unknown-linux-gnu": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
-            "attributes": {
-              "build_file_content": "\nfilegroup(\n    name = \"coverage\",\n    srcs = [\"coverage/__main__.py\"],\n    data = glob([\"coverage/*.py\", \"coverage/**/*.py\", \"coverage/*.so\"]),\n    visibility = [\"//visibility:public\"],\n)\n    ",
-              "patch_args": [
-                "-p1"
-              ],
-              "patches": [
-                "@@rules_python~//python/private:coverage.patch"
-              ],
-              "sha256": "8d13c64ee2d33eccf7437961b6ea7ad8673e2be040b4f7fd4fd4d4d28d9ccb1e",
-              "type": "zip",
-              "urls": [
-                "https://files.pythonhosted.org/packages/44/55/49f65ccdd4dfd6d5528e966b28c37caec64170c725af32ab312889d2f857/coverage-7.2.7-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl"
-              ]
-            }
-          },
-          "pypi__coverage_cp39_aarch64-apple-darwin": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
-            "attributes": {
-              "build_file_content": "\nfilegroup(\n    name = \"coverage\",\n    srcs = [\"coverage/__main__.py\"],\n    data = glob([\"coverage/*.py\", \"coverage/**/*.py\", \"coverage/*.so\"]),\n    visibility = [\"//visibility:public\"],\n)\n    ",
-              "patch_args": [
-                "-p1"
-              ],
-              "patches": [
-                "@@rules_python~//python/private:coverage.patch"
-              ],
-              "sha256": "06fb182e69f33f6cd1d39a6c597294cff3143554b64b9825d1dc69d18cc2fff2",
-              "type": "zip",
-              "urls": [
-                "https://files.pythonhosted.org/packages/ca/0c/3dfeeb1006c44b911ee0ed915350db30325d01808525ae7cc8d57643a2ce/coverage-7.2.7-cp39-cp39-macosx_11_0_arm64.whl"
-              ]
-            }
-          },
-          "pypi__coverage_cp39_aarch64-unknown-linux-gnu": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
-            "attributes": {
-              "build_file_content": "\nfilegroup(\n    name = \"coverage\",\n    srcs = [\"coverage/__main__.py\"],\n    data = glob([\"coverage/*.py\", \"coverage/**/*.py\", \"coverage/*.so\"]),\n    visibility = [\"//visibility:public\"],\n)\n    ",
-              "patch_args": [
-                "-p1"
-              ],
-              "patches": [
-                "@@rules_python~//python/private:coverage.patch"
-              ],
-              "sha256": "201e7389591af40950a6480bd9edfa8ed04346ff80002cec1a66cac4549c1ad7",
-              "type": "zip",
-              "urls": [
-                "https://files.pythonhosted.org/packages/61/af/5964b8d7d9a5c767785644d9a5a63cacba9a9c45cc42ba06d25895ec87be/coverage-7.2.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"
-              ]
-            }
-          },
-          "pypi__coverage_cp39_x86_64-apple-darwin": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
-            "attributes": {
-              "build_file_content": "\nfilegroup(\n    name = \"coverage\",\n    srcs = [\"coverage/__main__.py\"],\n    data = glob([\"coverage/*.py\", \"coverage/**/*.py\", \"coverage/*.so\"]),\n    visibility = [\"//visibility:public\"],\n)\n    ",
-              "patch_args": [
-                "-p1"
-              ],
-              "patches": [
-                "@@rules_python~//python/private:coverage.patch"
-              ],
-              "sha256": "537891ae8ce59ef63d0123f7ac9e2ae0fc8b72c7ccbe5296fec45fd68967b6c9",
-              "type": "zip",
-              "urls": [
-                "https://files.pythonhosted.org/packages/88/da/495944ebf0ad246235a6bd523810d9f81981f9b81c6059ba1f56e943abe0/coverage-7.2.7-cp39-cp39-macosx_10_9_x86_64.whl"
-              ]
-            }
-          },
-          "pypi__coverage_cp39_x86_64-unknown-linux-gnu": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
-            "attributes": {
-              "build_file_content": "\nfilegroup(\n    name = \"coverage\",\n    srcs = [\"coverage/__main__.py\"],\n    data = glob([\"coverage/*.py\", \"coverage/**/*.py\", \"coverage/*.so\"]),\n    visibility = [\"//visibility:public\"],\n)\n    ",
-              "patch_args": [
-                "-p1"
-              ],
-              "patches": [
-                "@@rules_python~//python/private:coverage.patch"
-              ],
-              "sha256": "6f48351d66575f535669306aa7d6d6f71bc43372473b54a832222803eb956fd1",
-              "type": "zip",
-              "urls": [
-                "https://files.pythonhosted.org/packages/fe/57/e4f8ad64d84ca9e759d783a052795f62a9f9111585e46068845b1cb52c2b/coverage-7.2.7-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl"
-              ]
-            }
-          },
-          "pypi__coverage_cp310_aarch64-apple-darwin": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
-            "attributes": {
-              "build_file_content": "\nfilegroup(\n    name = \"coverage\",\n    srcs = [\"coverage/__main__.py\"],\n    data = glob([\"coverage/*.py\", \"coverage/**/*.py\", \"coverage/*.so\"]),\n    visibility = [\"//visibility:public\"],\n)\n    ",
-              "patch_args": [
-                "-p1"
-              ],
-              "patches": [
-                "@@rules_python~//python/private:coverage.patch"
-              ],
-              "sha256": "6d040ef7c9859bb11dfeb056ff5b3872436e3b5e401817d87a31e1750b9ae2fb",
-              "type": "zip",
-              "urls": [
-                "https://files.pythonhosted.org/packages/3d/80/7060a445e1d2c9744b683dc935248613355657809d6c6b2716cdf4ca4766/coverage-7.2.7-cp310-cp310-macosx_11_0_arm64.whl"
-              ]
-            }
-          },
-          "pypi__coverage_cp310_aarch64-unknown-linux-gnu": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
-            "attributes": {
-              "build_file_content": "\nfilegroup(\n    name = \"coverage\",\n    srcs = [\"coverage/__main__.py\"],\n    data = glob([\"coverage/*.py\", \"coverage/**/*.py\", \"coverage/*.so\"]),\n    visibility = [\"//visibility:public\"],\n)\n    ",
-              "patch_args": [
-                "-p1"
-              ],
-              "patches": [
-                "@@rules_python~//python/private:coverage.patch"
-              ],
-              "sha256": "ba90a9563ba44a72fda2e85302c3abc71c5589cea608ca16c22b9804262aaeb6",
-              "type": "zip",
-              "urls": [
-                "https://files.pythonhosted.org/packages/b8/9d/926fce7e03dbfc653104c2d981c0fa71f0572a9ebd344d24c573bd6f7c4f/coverage-7.2.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"
-              ]
-            }
-          },
-          "pypi__coverage_cp310_x86_64-apple-darwin": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
-            "attributes": {
-              "build_file_content": "\nfilegroup(\n    name = \"coverage\",\n    srcs = [\"coverage/__main__.py\"],\n    data = glob([\"coverage/*.py\", \"coverage/**/*.py\", \"coverage/*.so\"]),\n    visibility = [\"//visibility:public\"],\n)\n    ",
-              "patch_args": [
-                "-p1"
-              ],
-              "patches": [
-                "@@rules_python~//python/private:coverage.patch"
-              ],
-              "sha256": "d39b5b4f2a66ccae8b7263ac3c8170994b65266797fb96cbbfd3fb5b23921db8",
-              "type": "zip",
-              "urls": [
-                "https://files.pythonhosted.org/packages/01/24/be01e62a7bce89bcffe04729c540382caa5a06bee45ae42136c93e2499f5/coverage-7.2.7-cp310-cp310-macosx_10_9_x86_64.whl"
-              ]
-            }
-          },
-          "pypi__coverage_cp310_x86_64-unknown-linux-gnu": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
-            "attributes": {
-              "build_file_content": "\nfilegroup(\n    name = \"coverage\",\n    srcs = [\"coverage/__main__.py\"],\n    data = glob([\"coverage/*.py\", \"coverage/**/*.py\", \"coverage/*.so\"]),\n    visibility = [\"//visibility:public\"],\n)\n    ",
-              "patch_args": [
-                "-p1"
-              ],
-              "patches": [
-                "@@rules_python~//python/private:coverage.patch"
-              ],
-              "sha256": "31563e97dae5598556600466ad9beea39fb04e0229e61c12eaa206e0aa202063",
-              "type": "zip",
-              "urls": [
-                "https://files.pythonhosted.org/packages/b4/bd/1b2331e3a04f4cc9b7b332b1dd0f3a1261dfc4114f8479bebfcc2afee9e8/coverage-7.2.7-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl"
-              ]
-            }
-          },
-          "pypi__coverage_cp311_aarch64-apple-darwin": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
-            "attributes": {
-              "build_file_content": "\nfilegroup(\n    name = \"coverage\",\n    srcs = [\"coverage/__main__.py\"],\n    data = glob([\"coverage/*.py\", \"coverage/**/*.py\", \"coverage/*.so\"]),\n    visibility = [\"//visibility:public\"],\n)\n    ",
-              "patch_args": [
-                "-p1"
-              ],
-              "patches": [
-                "@@rules_python~//python/private:coverage.patch"
-              ],
-              "sha256": "5baa06420f837184130752b7c5ea0808762083bf3487b5038d68b012e5937dbe",
-              "type": "zip",
-              "urls": [
-                "https://files.pythonhosted.org/packages/67/d7/cd8fe689b5743fffac516597a1222834c42b80686b99f5b44ef43ccc2a43/coverage-7.2.7-cp311-cp311-macosx_11_0_arm64.whl"
-              ]
-            }
-          },
-          "pypi__coverage_cp311_aarch64-unknown-linux-gnu": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
-            "attributes": {
-              "build_file_content": "\nfilegroup(\n    name = \"coverage\",\n    srcs = [\"coverage/__main__.py\"],\n    data = glob([\"coverage/*.py\", \"coverage/**/*.py\", \"coverage/*.so\"]),\n    visibility = [\"//visibility:public\"],\n)\n    ",
-              "patch_args": [
-                "-p1"
-              ],
-              "patches": [
-                "@@rules_python~//python/private:coverage.patch"
-              ],
-              "sha256": "fdec9e8cbf13a5bf63290fc6013d216a4c7232efb51548594ca3631a7f13c3a3",
-              "type": "zip",
-              "urls": [
-                "https://files.pythonhosted.org/packages/8c/95/16eed713202406ca0a37f8ac259bbf144c9d24f9b8097a8e6ead61da2dbb/coverage-7.2.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"
-              ]
-            }
-          },
-          "pypi__coverage_cp311_x86_64-apple-darwin": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
-            "attributes": {
-              "build_file_content": "\nfilegroup(\n    name = \"coverage\",\n    srcs = [\"coverage/__main__.py\"],\n    data = glob([\"coverage/*.py\", \"coverage/**/*.py\", \"coverage/*.so\"]),\n    visibility = [\"//visibility:public\"],\n)\n    ",
-              "patch_args": [
-                "-p1"
-              ],
-              "patches": [
-                "@@rules_python~//python/private:coverage.patch"
-              ],
-              "sha256": "06a9a2be0b5b576c3f18f1a241f0473575c4a26021b52b2a85263a00f034d51f",
-              "type": "zip",
-              "urls": [
-                "https://files.pythonhosted.org/packages/c6/fa/529f55c9a1029c840bcc9109d5a15ff00478b7ff550a1ae361f8745f8ad5/coverage-7.2.7-cp311-cp311-macosx_10_9_x86_64.whl"
-              ]
-            }
-          },
-          "pypi__coverage_cp311_x86_64-unknown-linux-gnu": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
-            "attributes": {
-              "build_file_content": "\nfilegroup(\n    name = \"coverage\",\n    srcs = [\"coverage/__main__.py\"],\n    data = glob([\"coverage/*.py\", \"coverage/**/*.py\", \"coverage/*.so\"]),\n    visibility = [\"//visibility:public\"],\n)\n    ",
-              "patch_args": [
-                "-p1"
-              ],
-              "patches": [
-                "@@rules_python~//python/private:coverage.patch"
-              ],
-              "sha256": "63426706118b7f5cf6bb6c895dc215d8a418d5952544042c8a2d9fe87fcf09cb",
-              "type": "zip",
-              "urls": [
-                "https://files.pythonhosted.org/packages/a7/cd/3ce94ad9d407a052dc2a74fbeb1c7947f442155b28264eb467ee78dea812/coverage-7.2.7-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl"
-              ]
-            }
-          }
-        },
-        "recordedRepoMappingEntries": [
+            "bazel_features",
+            "bazel_features~"
+          ],
           [
             "rules_python~",
             "bazel_skylib",
@@ -802,8 +3013,275 @@
           ],
           [
             "rules_python~",
-            "rules_python",
-            "rules_python~"
+            "pypi__build",
+            "rules_python~~internal_deps~pypi__build"
+          ],
+          [
+            "rules_python~",
+            "pypi__click",
+            "rules_python~~internal_deps~pypi__click"
+          ],
+          [
+            "rules_python~",
+            "pypi__colorama",
+            "rules_python~~internal_deps~pypi__colorama"
+          ],
+          [
+            "rules_python~",
+            "pypi__importlib_metadata",
+            "rules_python~~internal_deps~pypi__importlib_metadata"
+          ],
+          [
+            "rules_python~",
+            "pypi__installer",
+            "rules_python~~internal_deps~pypi__installer"
+          ],
+          [
+            "rules_python~",
+            "pypi__more_itertools",
+            "rules_python~~internal_deps~pypi__more_itertools"
+          ],
+          [
+            "rules_python~",
+            "pypi__packaging",
+            "rules_python~~internal_deps~pypi__packaging"
+          ],
+          [
+            "rules_python~",
+            "pypi__pep517",
+            "rules_python~~internal_deps~pypi__pep517"
+          ],
+          [
+            "rules_python~",
+            "pypi__pip",
+            "rules_python~~internal_deps~pypi__pip"
+          ],
+          [
+            "rules_python~",
+            "pypi__pip_tools",
+            "rules_python~~internal_deps~pypi__pip_tools"
+          ],
+          [
+            "rules_python~",
+            "pypi__pyproject_hooks",
+            "rules_python~~internal_deps~pypi__pyproject_hooks"
+          ],
+          [
+            "rules_python~",
+            "pypi__setuptools",
+            "rules_python~~internal_deps~pypi__setuptools"
+          ],
+          [
+            "rules_python~",
+            "pypi__tomli",
+            "rules_python~~internal_deps~pypi__tomli"
+          ],
+          [
+            "rules_python~",
+            "pypi__wheel",
+            "rules_python~~internal_deps~pypi__wheel"
+          ],
+          [
+            "rules_python~",
+            "pypi__zipp",
+            "rules_python~~internal_deps~pypi__zipp"
+          ],
+          [
+            "rules_python~",
+            "pythons_hub",
+            "rules_python~~python~pythons_hub"
+          ],
+          [
+            "rules_python~~python~pythons_hub",
+            "python_3_10_host",
+            "rules_python~~python~python_3_10_host"
+          ],
+          [
+            "rules_python~~python~pythons_hub",
+            "python_3_11_host",
+            "rules_python~~python~python_3_11_host"
+          ],
+          [
+            "rules_python~~python~pythons_hub",
+            "python_3_12_host",
+            "rules_python~~python~python_3_12_host"
+          ],
+          [
+            "rules_python~~python~pythons_hub",
+            "python_3_9_host",
+            "rules_python~~python~python_3_9_host"
+          ]
+        ]
+      }
+    },
+    "@@rules_swift~//swift:extensions.bzl%non_module_deps": {
+      "general": {
+        "bzlTransitiveDigest": "vhXfCi07IAmWf5hLHcxh5xCtTwvEGrmMkOavEMD5pzs=",
+        "usagesDigest": "/dVEtCLqIAaLXjfRXsJupTS9pTgmYVN/tFdJlGgE5NA=",
+        "recordedFileInputs": {},
+        "recordedDirentsInputs": {},
+        "envVariables": {},
+        "generatedRepoSpecs": {
+          "com_github_apple_swift_protobuf": {
+            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+            "ruleClassName": "http_archive",
+            "attributes": {
+              "urls": [
+                "https://github.com/apple/swift-protobuf/archive/1.20.2.tar.gz"
+              ],
+              "sha256": "3fb50bd4d293337f202d917b6ada22f9548a0a0aed9d9a4d791e6fbd8a246ebb",
+              "strip_prefix": "swift-protobuf-1.20.2/",
+              "build_file": "@@rules_swift~//third_party:com_github_apple_swift_protobuf/BUILD.overlay"
+            }
+          },
+          "com_github_grpc_grpc_swift": {
+            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+            "ruleClassName": "http_archive",
+            "attributes": {
+              "urls": [
+                "https://github.com/grpc/grpc-swift/archive/1.16.0.tar.gz"
+              ],
+              "sha256": "58b60431d0064969f9679411264b82e40a217ae6bd34e17096d92cc4e47556a5",
+              "strip_prefix": "grpc-swift-1.16.0/",
+              "build_file": "@@rules_swift~//third_party:com_github_grpc_grpc_swift/BUILD.overlay"
+            }
+          },
+          "com_github_apple_swift_docc_symbolkit": {
+            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+            "ruleClassName": "http_archive",
+            "attributes": {
+              "urls": [
+                "https://github.com/apple/swift-docc-symbolkit/archive/refs/tags/swift-5.10-RELEASE.tar.gz"
+              ],
+              "sha256": "de1d4b6940468ddb53b89df7aa1a81323b9712775b0e33e8254fa0f6f7469a97",
+              "strip_prefix": "swift-docc-symbolkit-swift-5.10-RELEASE",
+              "build_file": "@@rules_swift~//third_party:com_github_apple_swift_docc_symbolkit/BUILD.overlay"
+            }
+          },
+          "com_github_apple_swift_nio": {
+            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+            "ruleClassName": "http_archive",
+            "attributes": {
+              "urls": [
+                "https://github.com/apple/swift-nio/archive/2.42.0.tar.gz"
+              ],
+              "sha256": "e3304bc3fb53aea74a3e54bd005ede11f6dc357117d9b1db642d03aea87194a0",
+              "strip_prefix": "swift-nio-2.42.0/",
+              "build_file": "@@rules_swift~//third_party:com_github_apple_swift_nio/BUILD.overlay"
+            }
+          },
+          "com_github_apple_swift_nio_http2": {
+            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+            "ruleClassName": "http_archive",
+            "attributes": {
+              "urls": [
+                "https://github.com/apple/swift-nio-http2/archive/1.26.0.tar.gz"
+              ],
+              "sha256": "f0edfc9d6a7be1d587e5b403f2d04264bdfae59aac1d74f7d974a9022c6d2b25",
+              "strip_prefix": "swift-nio-http2-1.26.0/",
+              "build_file": "@@rules_swift~//third_party:com_github_apple_swift_nio_http2/BUILD.overlay"
+            }
+          },
+          "com_github_apple_swift_nio_transport_services": {
+            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+            "ruleClassName": "http_archive",
+            "attributes": {
+              "urls": [
+                "https://github.com/apple/swift-nio-transport-services/archive/1.15.0.tar.gz"
+              ],
+              "sha256": "f3498dafa633751a52b9b7f741f7ac30c42bcbeb3b9edca6d447e0da8e693262",
+              "strip_prefix": "swift-nio-transport-services-1.15.0/",
+              "build_file": "@@rules_swift~//third_party:com_github_apple_swift_nio_transport_services/BUILD.overlay"
+            }
+          },
+          "com_github_apple_swift_nio_extras": {
+            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+            "ruleClassName": "http_archive",
+            "attributes": {
+              "urls": [
+                "https://github.com/apple/swift-nio-extras/archive/1.4.0.tar.gz"
+              ],
+              "sha256": "4684b52951d9d9937bb3e8ccd6b5daedd777021ef2519ea2f18c4c922843b52b",
+              "strip_prefix": "swift-nio-extras-1.4.0/",
+              "build_file": "@@rules_swift~//third_party:com_github_apple_swift_nio_extras/BUILD.overlay"
+            }
+          },
+          "com_github_apple_swift_log": {
+            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+            "ruleClassName": "http_archive",
+            "attributes": {
+              "urls": [
+                "https://github.com/apple/swift-log/archive/1.4.4.tar.gz"
+              ],
+              "sha256": "48fe66426c784c0c20031f15dc17faf9f4c9037c192bfac2f643f65cb2321ba0",
+              "strip_prefix": "swift-log-1.4.4/",
+              "build_file": "@@rules_swift~//third_party:com_github_apple_swift_log/BUILD.overlay"
+            }
+          },
+          "com_github_apple_swift_nio_ssl": {
+            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+            "ruleClassName": "http_archive",
+            "attributes": {
+              "urls": [
+                "https://github.com/apple/swift-nio-ssl/archive/2.23.0.tar.gz"
+              ],
+              "sha256": "4787c63f61dd04d99e498adc3d1a628193387e41efddf8de19b8db04544d016d",
+              "strip_prefix": "swift-nio-ssl-2.23.0/",
+              "build_file": "@@rules_swift~//third_party:com_github_apple_swift_nio_ssl/BUILD.overlay"
+            }
+          },
+          "com_github_apple_swift_collections": {
+            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+            "ruleClassName": "http_archive",
+            "attributes": {
+              "urls": [
+                "https://github.com/apple/swift-collections/archive/1.0.4.tar.gz"
+              ],
+              "sha256": "d9e4c8a91c60fb9c92a04caccbb10ded42f4cb47b26a212bc6b39cc390a4b096",
+              "strip_prefix": "swift-collections-1.0.4/",
+              "build_file": "@@rules_swift~//third_party:com_github_apple_swift_collections/BUILD.overlay"
+            }
+          },
+          "com_github_apple_swift_atomics": {
+            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+            "ruleClassName": "http_archive",
+            "attributes": {
+              "urls": [
+                "https://github.com/apple/swift-atomics/archive/1.1.0.tar.gz"
+              ],
+              "sha256": "1bee7f469f7e8dc49f11cfa4da07182fbc79eab000ec2c17bfdce468c5d276fb",
+              "strip_prefix": "swift-atomics-1.1.0/",
+              "build_file": "@@rules_swift~//third_party:com_github_apple_swift_atomics/BUILD.overlay"
+            }
+          },
+          "build_bazel_rules_swift_index_import": {
+            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
+            "ruleClassName": "http_archive",
+            "attributes": {
+              "build_file": "@@rules_swift~//third_party:build_bazel_rules_swift_index_import/BUILD.overlay",
+              "canonical_id": "index-import-5.8",
+              "urls": [
+                "https://github.com/MobileNativeFoundation/index-import/releases/download/5.8.0.1/index-import.tar.gz"
+              ],
+              "sha256": "28c1ffa39d99e74ed70623899b207b41f79214c498c603915aef55972a851a15"
+            }
+          },
+          "build_bazel_rules_swift_local_config": {
+            "bzlFile": "@@rules_swift~//swift/internal:swift_autoconfiguration.bzl",
+            "ruleClassName": "swift_autoconfiguration",
+            "attributes": {}
+          }
+        },
+        "recordedRepoMappingEntries": [
+          [
+            "rules_swift~",
+            "bazel_tools",
+            "bazel_tools"
+          ],
+          [
+            "rules_swift~",
+            "build_bazel_rules_swift",
+            "rules_swift~"
           ]
         ]
       }
diff --git a/lib/BUILD b/lib/BUILD
index 5994907..fa50d0d 100644
--- a/lib/BUILD
+++ b/lib/BUILD
@@ -6,7 +6,7 @@
         "//org.eclipse.jgit.pgm:__pkg__",
         "//org.eclipse.jgit.pgm.test:__pkg__",
     ],
-    exports = ["@jgit_deps//:args4j_args4j"],
+    exports = ["@external_deps//:args4j_args4j"],
 )
 
 java_library(
@@ -16,7 +16,7 @@
         "//org.eclipse.jgit.pgm.test:__pkg__",
         "//org.eclipse.jgit.test:__pkg__",
     ],
-    exports = ["@jgit_deps//:org_apache_commons_commons_compress"],
+    exports = ["@external_deps//:org_apache_commons_commons_compress"],
 )
 
 java_library(
@@ -26,7 +26,7 @@
         "//org.eclipse.jgit.pgm.test:__pkg__",
         "//org.eclipse.jgit.test:__pkg__",
     ],
-    exports = ["@jgit_deps//:org_apache_commons_commons_lang3"],
+    exports = ["@external_deps//:org_apache_commons_commons_lang3"],
 )
 
 java_library(
@@ -36,7 +36,7 @@
         "//org.eclipse.jgit.pgm.test:__pkg__",
         "//org.eclipse.jgit.test:__pkg__",
     ],
-    exports = ["@jgit_deps//:commons_io_commons_io"],
+    exports = ["@external_deps//:commons_io_commons_io"],
 )
 
 java_library(
@@ -45,13 +45,13 @@
         "//org.eclipse.jgit:__pkg__",
         "//org.eclipse.jgit.test:__pkg__",
     ],
-    exports = ["@jgit_deps//:commons_codec_commons_codec"],
+    exports = ["@external_deps//:commons_codec_commons_codec"],
 )
 
 java_library(
     name = "commons-logging",
     visibility = ["//visibility:public"],
-    exports = ["@jgit_deps//:commons_logging_commons_logging"],
+    exports = ["@external_deps//:commons_logging_commons_logging"],
 )
 
 java_library(
@@ -60,7 +60,7 @@
         "//org.eclipse.jgit.lfs:__pkg__",
         "//org.eclipse.jgit.lfs.server:__pkg__",
     ],
-    exports = ["@jgit_deps//:com_google_code_gson_gson"],
+    exports = ["@external_deps//:com_google_code_gson_gson"],
 )
 
 java_library(
@@ -70,7 +70,7 @@
         "//org.eclipse.jgit.lfs.server.test:__pkg__",
         "//org.eclipse.jgit.pgm:__pkg__",
     ],
-    exports = ["@jgit_deps//:org_apache_httpcomponents_httpclient"],
+    exports = ["@external_deps//:org_apache_httpcomponents_httpclient"],
 )
 
 java_library(
@@ -82,7 +82,7 @@
         "//org.eclipse.jgit.lfs.server.test:__pkg__",
         "//org.eclipse.jgit.pgm:__pkg__",
     ],
-    exports = ["@jgit_deps//:org_apache_httpcomponents_httpcore"],
+    exports = ["@external_deps//:org_apache_httpcomponents_httpcore"],
 )
 
 java_library(
@@ -94,7 +94,7 @@
         "//org.eclipse.jgit.ssh.apache.test:__pkg__",
         "//org.eclipse.jgit.test:__pkg__",
     ],
-    exports = ["@jgit_deps//:org_apache_sshd_sshd_osgi"],
+    exports = ["@external_deps//:org_apache_sshd_sshd_osgi"],
 )
 
 java_library(
@@ -105,7 +105,7 @@
         "//org.eclipse.jgit.ssh.apache.test:__pkg__",
         "//org.eclipse.jgit.test:__pkg__",
     ],
-    exports = ["@jgit_deps//:org_apache_sshd_sshd_sftp"],
+    exports = ["@external_deps//:org_apache_sshd_sshd_sftp"],
 )
 
 java_library(
@@ -113,7 +113,7 @@
     visibility = [
         "//org.eclipse.jgit.ssh.apache.agent:__pkg__",
     ],
-    exports = ["@jgit_deps//:net_java_dev_jna_jna"],
+    exports = ["@external_deps//:net_java_dev_jna_jna"],
 )
 
 java_library(
@@ -121,20 +121,20 @@
     visibility = [
         "//org.eclipse.jgit.ssh.apache.agent:__pkg__",
     ],
-    exports = ["@jgit_deps//:net_java_dev_jna_jna_platform"],
+    exports = ["@external_deps//:net_java_dev_jna_jna_platform"],
 )
 
 java_library(
     name = "javaewah",
     visibility = ["//visibility:public"],
-    exports = ["@jgit_deps//:com_googlecode_javaewah_JavaEWAH"],
+    exports = ["@external_deps//:com_googlecode_javaewah_JavaEWAH"],
 )
 
 java_library(
     name = "jetty-http",
     # TODO: This should be testonly but org.eclipse.jgit.pgm depends on it.
     visibility = ["//visibility:public"],
-    exports = ["@jgit_deps//:org_eclipse_jetty_jetty_http"],
+    exports = ["@external_deps//:org_eclipse_jetty_jetty_http"],
     runtime_deps = [":commons-codec"],
 )
 
@@ -142,42 +142,42 @@
     name = "jetty-io",
     # TODO: This should be testonly but org.eclipse.jgit.pgm depends on it.
     visibility = ["//visibility:public"],
-    exports = ["@jgit_deps//:org_eclipse_jetty_jetty_io"],
+    exports = ["@external_deps//:org_eclipse_jetty_jetty_io"],
 )
 
 java_library(
     name = "jetty-security",
     # TODO: This should be testonly but org.eclipse.jgit.pgm depends on it.
     visibility = ["//visibility:public"],
-    exports = ["@jgit_deps//:org_eclipse_jetty_jetty_security"],
+    exports = ["@external_deps//:org_eclipse_jetty_jetty_security"],
 )
 
 java_library(
     name = "jetty-session",
     # TODO: This should be testonly but org.eclipse.jgit.pgm depends on it.
     visibility = ["//visibility:public"],
-    exports = ["@jgit_deps//:org_eclipse_jetty_jetty_session"],
+    exports = ["@external_deps//:org_eclipse_jetty_jetty_session"],
 )
 
 java_library(
     name = "jetty-server",
     # TODO: This should be testonly but org.eclipse.jgit.pgm depends on it.
     visibility = ["//visibility:public"],
-    exports = ["@jgit_deps//:org_eclipse_jetty_jetty_server"],
+    exports = ["@external_deps//:org_eclipse_jetty_jetty_server"],
 )
 
 java_library(
     name = "jetty-ee8-nested",
     # TODO: This should be testonly but org.eclipse.jgit.pgm depends on it.
     visibility = ["//visibility:public"],
-    exports = ["@jgit_deps//:org_eclipse_jetty_ee8_jetty_ee8_nested"],
+    exports = ["@external_deps//:org_eclipse_jetty_ee8_jetty_ee8_nested"],
 )
 
 java_library(
     name = "jetty-ee8-security",
     # TODO: This should be testonly but org.eclipse.jgit.pgm depends on it.
     visibility = ["//visibility:public"],
-    exports = ["@jgit_deps//:org_eclipse_jetty_ee8_jetty_ee8_security"],
+    exports = ["@external_deps//:org_eclipse_jetty_ee8_jetty_ee8_security"],
 )
 
 java_library(
@@ -185,8 +185,8 @@
     # TODO: This should be testonly but org.eclipse.jgit.pgm depends on it.
     visibility = ["//visibility:public"],
     exports = [
-        "@jgit_deps//:org_eclipse_jetty_ee8_jetty_ee8_servlet",
-        "@jgit_deps//:org_eclipse_jetty_jetty_util_ajax",
+        "@external_deps//:org_eclipse_jetty_ee8_jetty_ee8_servlet",
+        "@external_deps//:org_eclipse_jetty_jetty_util_ajax",
     ],
 )
 
@@ -194,7 +194,7 @@
     name = "jetty-util",
     # TODO: This should be testonly but org.eclipse.jgit.pgm depends on it.
     visibility = ["//visibility:public"],
-    exports = ["@jgit_deps//:org_eclipse_jetty_jetty_util"],
+    exports = ["@external_deps//:org_eclipse_jetty_jetty_util"],
 )
 
 java_library(
@@ -204,7 +204,7 @@
         "//org.eclipse.jgit.ssh.jsch:__pkg__",
         "//org.eclipse.jgit.ssh.jsch.test:__pkg__",
     ],
-    exports = ["@jgit_deps//:com_jcraft_jsch"],
+    exports = ["@external_deps//:com_jcraft_jsch"],
 )
 
 java_library(
@@ -216,7 +216,7 @@
         "//org.eclipse.jgit.ssh.apache.test:__pkg__",
         "//org.eclipse.jgit.test:__pkg__",
     ],
-    exports = ["@jgit_deps//:org_bouncycastle_bcpg_jdk18on"],
+    exports = ["@external_deps//:org_bouncycastle_bcpg_jdk18on"],
 )
 
 java_library(
@@ -229,7 +229,7 @@
         "//org.eclipse.jgit.ssh.jsch.test:__pkg__",
         "//org.eclipse.jgit.test:__pkg__",
     ],
-    exports = ["@jgit_deps//:org_bouncycastle_bcprov_jdk18on"],
+    exports = ["@external_deps//:org_bouncycastle_bcprov_jdk18on"],
 )
 
 java_library(
@@ -242,7 +242,7 @@
         "//org.eclipse.jgit.ssh.jsch.test:__pkg__",
         "//org.eclipse.jgit.test:__pkg__",
     ],
-    exports = ["@jgit_deps//:org_bouncycastle_bcutil_jdk18on"],
+    exports = ["@external_deps//:org_bouncycastle_bcutil_jdk18on"],
 )
 
 java_library(
@@ -254,7 +254,7 @@
         "//org.eclipse.jgit.ssh.jsch.test:__pkg__",
         "//org.eclipse.jgit.test:__pkg__",
     ],
-    exports = ["@jgit_deps//:org_bouncycastle_bcpkix_jdk18on"],
+    exports = ["@external_deps//:org_bouncycastle_bcpkix_jdk18on"],
 )
 
 java_library(
@@ -263,7 +263,7 @@
         "//org.eclipse.jgit.ssh.jsch:__pkg__",
         "//org.eclipse.jgit.test:__pkg__",
     ],
-    exports = ["@jgit_deps//:com_jcraft_jzlib"],
+    exports = ["@external_deps//:com_jcraft_jzlib"],
 )
 
 java_library(
@@ -271,12 +271,12 @@
     testonly = 1,
     visibility = ["//visibility:public"],
     exports = [
-        "@jgit_deps//:net_bytebuddy_byte_buddy_agent",
-        "@jgit_deps//:net_bytebuddy_byte_buddy",
-        "@jgit_deps//:org_hamcrest_hamcrest",
-        "@jgit_deps//:junit_junit",
-        "@jgit_deps//:org_mockito_mockito_core",
-        "@jgit_deps//:org_objenesis_objenesis",
+        "@external_deps//:net_bytebuddy_byte_buddy_agent",
+        "@external_deps//:net_bytebuddy_byte_buddy",
+        "@external_deps//:org_hamcrest_hamcrest",
+        "@external_deps//:junit_junit",
+        "@external_deps//:org_mockito_mockito_core",
+        "@external_deps//:org_objenesis_objenesis",
     ],
 )
 
@@ -285,10 +285,10 @@
     testonly = 1,
     visibility = ["//visibility:public"],
     exports = [
-        "@jgit_deps//:net_bytebuddy_byte_buddy_agent",
-        "@jgit_deps//:net_bytebuddy_byte_buddy",
-        "@jgit_deps//:org_mockito_mockito_core",
-        "@jgit_deps//:org_objenesis_objenesis",
+        "@external_deps//:net_bytebuddy_byte_buddy_agent",
+        "@external_deps//:net_bytebuddy_byte_buddy",
+        "@external_deps//:org_mockito_mockito_core",
+        "@external_deps//:org_objenesis_objenesis",
     ],
 )
 
@@ -297,7 +297,7 @@
     testonly = 1,
     visibility = ["//visibility:public"],
     exports = [
-        "@jgit_deps//:org_assertj_assertj_core",
+        "@external_deps//:org_assertj_assertj_core",
     ],
 )
 
@@ -312,24 +312,24 @@
         "//org.eclipse.jgit.lfs.server.test:__pkg__",
         "//org.eclipse.jgit.pgm:__pkg__",
     ],
-    exports = ["@jgit_deps//:jakarta_servlet_jakarta_servlet_api_4_0_4"],
+    exports = ["@external_deps//:jakarta_servlet_jakarta_servlet_api_4_0_4"],
 )
 
 java_library(
     name = "slf4j-api",
     visibility = ["//visibility:public"],
-    exports = ["@jgit_deps//:org_slf4j_slf4j_api"],
+    exports = ["@external_deps//:org_slf4j_slf4j_api"],
 )
 
 java_library(
     name = "slf4j-simple",
     visibility = ["//visibility:public"],
-    exports = ["@jgit_deps//:org_slf4j_slf4j_simple"],
+    exports = ["@external_deps//:org_slf4j_slf4j_simple"],
 )
 
 java_library(
     name = "xz",
     testonly = 1,
     visibility = ["//visibility:public"],
-    exports = ["@jgit_deps//:org_tukaani_xz"],
+    exports = ["@external_deps//:org_tukaani_xz"],
 )
diff --git a/lib/jmh/BUILD b/lib/jmh/BUILD
index 1bba1a5..2b15300 100644
--- a/lib/jmh/BUILD
+++ b/lib/jmh/BUILD
@@ -4,9 +4,9 @@
     name = "jmh",
     visibility = ["//visibility:public"],
     exports = [
-        "@jgit_deps//:org_openjdk_jmh_jmh_generator_annprocess",
-        "@jgit_deps//:org_openjdk_jmh_jmh_core",
-        "@jgit_deps//:net_sf_jopt_simple_jopt_simple",
-        "@jgit_deps//:org_apache_commons_commons_math3",
+        "@external_deps//:org_openjdk_jmh_jmh_generator_annprocess",
+        "@external_deps//:org_openjdk_jmh_jmh_core",
+        "@external_deps//:net_sf_jopt_simple_jopt_simple",
+        "@external_deps//:org_apache_commons_commons_math3",
     ],
 )
diff --git a/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF
index 400a5dc..012f00b 100644
--- a/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF
@@ -9,31 +9,31 @@
 Bundle-ActivationPolicy: lazy
 Bundle-RequiredExecutionEnvironment: JavaSE-17
 Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git
-Import-Package: org.apache.sshd.common;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.config.keys;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.file.virtualfs;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.helpers;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.io;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.kex;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.keyprovider;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.session;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.signature;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.util.buffer;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.util.logging;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.util.security;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.util.threads;version="[2.16.0,2.17.0)",
- org.apache.sshd.core;version="[2.16.0,2.17.0)",
- org.apache.sshd.server;version="[2.16.0,2.17.0)",
- org.apache.sshd.server.auth;version="[2.16.0,2.17.0)",
- org.apache.sshd.server.auth.gss;version="[2.16.0,2.17.0)",
- org.apache.sshd.server.auth.keyboard;version="[2.16.0,2.17.0)",
- org.apache.sshd.server.auth.password;version="[2.16.0,2.17.0)",
- org.apache.sshd.server.command;version="[2.16.0,2.17.0)",
- org.apache.sshd.server.session;version="[2.16.0,2.17.0)",
- org.apache.sshd.server.shell;version="[2.16.0,2.17.0)",
- org.apache.sshd.server.subsystem;version="[2.16.0,2.17.0)",
- org.apache.sshd.sftp;version="[2.16.0,2.17.0)",
- org.apache.sshd.sftp.server;version="[2.16.0,2.17.0)",
+Import-Package: org.apache.sshd.common;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.config.keys;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.file.virtualfs;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.helpers;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.io;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.kex;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.keyprovider;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.session;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.signature;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.util.buffer;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.util.logging;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.util.security;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.util.threads;version="[2.17.1,2.18.0)",
+ org.apache.sshd.core;version="[2.17.1,2.18.0)",
+ org.apache.sshd.server;version="[2.17.1,2.18.0)",
+ org.apache.sshd.server.auth;version="[2.17.1,2.18.0)",
+ org.apache.sshd.server.auth.gss;version="[2.17.1,2.18.0)",
+ org.apache.sshd.server.auth.keyboard;version="[2.17.1,2.18.0)",
+ org.apache.sshd.server.auth.password;version="[2.17.1,2.18.0)",
+ org.apache.sshd.server.command;version="[2.17.1,2.18.0)",
+ org.apache.sshd.server.session;version="[2.17.1,2.18.0)",
+ org.apache.sshd.server.shell;version="[2.17.1,2.18.0)",
+ org.apache.sshd.server.subsystem;version="[2.17.1,2.18.0)",
+ org.apache.sshd.sftp;version="[2.17.1,2.18.0)",
+ org.apache.sshd.sftp.server;version="[2.17.1,2.18.0)",
  org.eclipse.jgit.annotations;version="[7.6.0,7.7.0)",
  org.eclipse.jgit.api;version="[7.6.0,7.7.0)",
  org.eclipse.jgit.api.errors;version="[7.6.0,7.7.0)",
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.34.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.34.target
index f26a46d..c928a9c 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.34.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.34.target
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.34" sequenceNumber="1765188982">
+<target name="jgit-4.34" sequenceNumber="1770852958">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/>
@@ -65,13 +65,13 @@
         <dependency>
           <groupId>org.apache.sshd</groupId>
           <artifactId>sshd-osgi</artifactId>
-          <version>2.16.0</version>
+          <version>2.17.1</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.apache.sshd</groupId>
           <artifactId>sshd-sftp</artifactId>
-          <version>2.16.0</version>
+          <version>2.17.1</version>
           <type>jar</type>
         </dependency>
       </dependencies>
@@ -81,7 +81,7 @@
         <dependency>
           <groupId>org.mockito</groupId>
           <artifactId>mockito-core</artifactId>
-          <version>5.20.0</version>
+          <version>5.21.0</version>
           <type>jar</type>
         </dependency>
       </dependencies>
@@ -207,13 +207,13 @@
         <dependency>
           <groupId>net.bytebuddy</groupId>
           <artifactId>byte-buddy</artifactId>
-          <version>1.18.2</version>
+          <version>1.18.4</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>net.bytebuddy</groupId>
           <artifactId>byte-buddy-agent</artifactId>
-          <version>1.18.2</version>
+          <version>1.18.4</version>
           <type>jar</type>
         </dependency>
       </dependencies>
@@ -251,7 +251,7 @@
         <dependency>
           <groupId>org.assertj</groupId>
           <artifactId>assertj-core</artifactId>
-          <version>3.27.6</version>
+          <version>3.27.7</version>
           <type>jar</type>
         </dependency>
       </dependencies>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.35.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.35.target
index 86a8150..36727c2 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.35.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.35.target
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.35" sequenceNumber="1765188982">
+<target name="jgit-4.35" sequenceNumber="1770852958">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/>
@@ -65,13 +65,13 @@
         <dependency>
           <groupId>org.apache.sshd</groupId>
           <artifactId>sshd-osgi</artifactId>
-          <version>2.16.0</version>
+          <version>2.17.1</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.apache.sshd</groupId>
           <artifactId>sshd-sftp</artifactId>
-          <version>2.16.0</version>
+          <version>2.17.1</version>
           <type>jar</type>
         </dependency>
       </dependencies>
@@ -81,7 +81,7 @@
         <dependency>
           <groupId>org.mockito</groupId>
           <artifactId>mockito-core</artifactId>
-          <version>5.20.0</version>
+          <version>5.21.0</version>
           <type>jar</type>
         </dependency>
       </dependencies>
@@ -207,13 +207,13 @@
         <dependency>
           <groupId>net.bytebuddy</groupId>
           <artifactId>byte-buddy</artifactId>
-          <version>1.18.2</version>
+          <version>1.18.4</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>net.bytebuddy</groupId>
           <artifactId>byte-buddy-agent</artifactId>
-          <version>1.18.2</version>
+          <version>1.18.4</version>
           <type>jar</type>
         </dependency>
       </dependencies>
@@ -251,7 +251,7 @@
         <dependency>
           <groupId>org.assertj</groupId>
           <artifactId>assertj-core</artifactId>
-          <version>3.27.6</version>
+          <version>3.27.7</version>
           <type>jar</type>
         </dependency>
       </dependencies>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.36.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.36.target
index aece501..8415e29 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.36.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.36.target
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.36" sequenceNumber="1765188982">
+<target name="jgit-4.36" sequenceNumber="1770852958">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/>
@@ -65,13 +65,13 @@
         <dependency>
           <groupId>org.apache.sshd</groupId>
           <artifactId>sshd-osgi</artifactId>
-          <version>2.16.0</version>
+          <version>2.17.1</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.apache.sshd</groupId>
           <artifactId>sshd-sftp</artifactId>
-          <version>2.16.0</version>
+          <version>2.17.1</version>
           <type>jar</type>
         </dependency>
       </dependencies>
@@ -81,7 +81,7 @@
         <dependency>
           <groupId>org.mockito</groupId>
           <artifactId>mockito-core</artifactId>
-          <version>5.20.0</version>
+          <version>5.21.0</version>
           <type>jar</type>
         </dependency>
       </dependencies>
@@ -207,13 +207,13 @@
         <dependency>
           <groupId>net.bytebuddy</groupId>
           <artifactId>byte-buddy</artifactId>
-          <version>1.18.2</version>
+          <version>1.18.4</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>net.bytebuddy</groupId>
           <artifactId>byte-buddy-agent</artifactId>
-          <version>1.18.2</version>
+          <version>1.18.4</version>
           <type>jar</type>
         </dependency>
       </dependencies>
@@ -251,7 +251,7 @@
         <dependency>
           <groupId>org.assertj</groupId>
           <artifactId>assertj-core</artifactId>
-          <version>3.27.6</version>
+          <version>3.27.7</version>
           <type>jar</type>
         </dependency>
       </dependencies>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.37.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.37.target
index ea754a6..a4746e6 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.37.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.37.target
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.37" sequenceNumber="1765188982">
+<target name="jgit-4.37" sequenceNumber="1770852959">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/>
@@ -65,13 +65,13 @@
         <dependency>
           <groupId>org.apache.sshd</groupId>
           <artifactId>sshd-osgi</artifactId>
-          <version>2.16.0</version>
+          <version>2.17.1</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.apache.sshd</groupId>
           <artifactId>sshd-sftp</artifactId>
-          <version>2.16.0</version>
+          <version>2.17.1</version>
           <type>jar</type>
         </dependency>
       </dependencies>
@@ -81,7 +81,7 @@
         <dependency>
           <groupId>org.mockito</groupId>
           <artifactId>mockito-core</artifactId>
-          <version>5.20.0</version>
+          <version>5.21.0</version>
           <type>jar</type>
         </dependency>
       </dependencies>
@@ -207,13 +207,13 @@
         <dependency>
           <groupId>net.bytebuddy</groupId>
           <artifactId>byte-buddy</artifactId>
-          <version>1.18.2</version>
+          <version>1.18.4</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>net.bytebuddy</groupId>
           <artifactId>byte-buddy-agent</artifactId>
-          <version>1.18.2</version>
+          <version>1.18.4</version>
           <type>jar</type>
         </dependency>
       </dependencies>
@@ -251,7 +251,7 @@
         <dependency>
           <groupId>org.assertj</groupId>
           <artifactId>assertj-core</artifactId>
-          <version>3.27.6</version>
+          <version>3.27.7</version>
           <type>jar</type>
         </dependency>
       </dependencies>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.38.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.38.target
index 3eefbe5..f2ebb23 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.38.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.38.target
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.38" sequenceNumber="1765188983">
+<target name="jgit-4.38" sequenceNumber="1770852959">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/>
@@ -32,7 +32,7 @@
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.eclipse.osgi" version="0.0.0"/>
-      <repository location="https://download.eclipse.org/staging/2025-12/"/>
+      <repository location="https://download.eclipse.org/releases/2025-12/"/>
     </location>
     <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="xz">
       <dependencies>
@@ -65,13 +65,13 @@
         <dependency>
           <groupId>org.apache.sshd</groupId>
           <artifactId>sshd-osgi</artifactId>
-          <version>2.16.0</version>
+          <version>2.17.1</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.apache.sshd</groupId>
           <artifactId>sshd-sftp</artifactId>
-          <version>2.16.0</version>
+          <version>2.17.1</version>
           <type>jar</type>
         </dependency>
       </dependencies>
@@ -81,7 +81,7 @@
         <dependency>
           <groupId>org.mockito</groupId>
           <artifactId>mockito-core</artifactId>
-          <version>5.20.0</version>
+          <version>5.21.0</version>
           <type>jar</type>
         </dependency>
       </dependencies>
@@ -207,13 +207,13 @@
         <dependency>
           <groupId>net.bytebuddy</groupId>
           <artifactId>byte-buddy</artifactId>
-          <version>1.18.2</version>
+          <version>1.18.4</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>net.bytebuddy</groupId>
           <artifactId>byte-buddy-agent</artifactId>
-          <version>1.18.2</version>
+          <version>1.18.4</version>
           <type>jar</type>
         </dependency>
       </dependencies>
@@ -251,7 +251,7 @@
         <dependency>
           <groupId>org.assertj</groupId>
           <artifactId>assertj-core</artifactId>
-          <version>3.27.6</version>
+          <version>3.27.7</version>
           <type>jar</type>
         </dependency>
       </dependencies>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.38.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.38.tpd
index cd20f43..a440dc6 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.38.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.38.tpd
@@ -3,6 +3,6 @@
 include "orbit/orbit-4.38.tpd"
 include "maven/dependencies.tpd"
 
-location "https://download.eclipse.org/staging/2025-12/" {
+location "https://download.eclipse.org/releases/2025-12/" {
 	org.eclipse.osgi lazy
 }
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.39.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.39.target
new file mode 100644
index 0000000..5fb4633
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.39.target
@@ -0,0 +1,304 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?pde?>
+<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
+<target name="jgit-4.39" sequenceNumber="1770852961">
+  <locations>
+    <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
+      <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/>
+      <unit id="com.jcraft.jsch.source" version="0.1.55.v20230916-1400"/>
+      <unit id="com.jcraft.jzlib" version="1.1.3.v20230916-1400"/>
+      <unit id="com.jcraft.jzlib.source" version="1.1.3.v20230916-1400"/>
+      <unit id="org.apache.ant" version="1.10.15.v20240901-1000"/>
+      <unit id="org.apache.ant.source" version="1.10.15.v20240901-1000"/>
+      <unit id="org.apache.aries.spifly.dynamic.bundle" version="1.3.7"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.5.14"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.14"/>
+      <unit id="org.apache.httpcomponents.httpcore" version="4.4.16"/>
+      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.16"/>
+      <unit id="org.hamcrest" version="3.0.0"/>
+      <unit id="org.hamcrest.source" version="3.0.0"/>
+      <unit id="org.junit" version="4.13.2.v20240929-1000"/>
+      <unit id="org.junit.source" version="4.13.2.v20240929-1000"/>
+      <unit id="org.objectweb.asm" version="9.9.1"/>
+      <unit id="org.objectweb.asm.commons" version="9.9.1"/>
+      <unit id="org.objectweb.asm.util" version="9.9.1"/>
+      <unit id="org.objectweb.asm.tree" version="9.9.1"/>
+      <unit id="org.objectweb.asm.tree.analysis" version="9.9.1"/>
+      <unit id="org.objenesis" version="3.4.0"/>
+      <unit id="org.objenesis.source" version="3.4.0"/>
+      <unit id="org.osgi.service.cm" version="1.6.1.202109301733"/>
+      <unit id="org.osgi.service.cm.source" version="1.6.1.202109301733"/>
+      <repository location="https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2026-03"/>
+    </location>
+    <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
+      <unit id="org.eclipse.osgi" version="0.0.0"/>
+      <repository location="https://download.eclipse.org/staging/2026-03/"/>
+    </location>
+    <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="xz">
+      <dependencies>
+        <dependency>
+          <groupId>org.tukaani</groupId>
+          <artifactId>xz</artifactId>
+          <version>1.11</version>
+          <type>jar</type>
+        </dependency>
+      </dependencies>
+    </location>
+    <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="slf4j">
+      <dependencies>
+        <dependency>
+          <groupId>org.slf4j</groupId>
+          <artifactId>slf4j-api</artifactId>
+          <version>2.0.17</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>org.slf4j</groupId>
+          <artifactId>slf4j-simple</artifactId>
+          <version>2.0.17</version>
+          <type>jar</type>
+        </dependency>
+      </dependencies>
+    </location>
+    <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="sshd">
+      <dependencies>
+        <dependency>
+          <groupId>org.apache.sshd</groupId>
+          <artifactId>sshd-osgi</artifactId>
+          <version>2.17.1</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>org.apache.sshd</groupId>
+          <artifactId>sshd-sftp</artifactId>
+          <version>2.17.1</version>
+          <type>jar</type>
+        </dependency>
+      </dependencies>
+    </location>
+    <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="mockito">
+      <dependencies>
+        <dependency>
+          <groupId>org.mockito</groupId>
+          <artifactId>mockito-core</artifactId>
+          <version>5.21.0</version>
+          <type>jar</type>
+        </dependency>
+      </dependencies>
+    </location>
+    <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jna">
+      <dependencies>
+        <dependency>
+          <groupId>net.java.dev.jna</groupId>
+          <artifactId>jna</artifactId>
+          <version>5.18.1</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>net.java.dev.jna</groupId>
+          <artifactId>jna-platform</artifactId>
+          <version>5.18.1</version>
+          <type>jar</type>
+        </dependency>
+      </dependencies>
+    </location>
+    <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jetty">
+      <dependencies>
+        <dependency>
+          <groupId>org.eclipse.jetty.ee8</groupId>
+          <artifactId>jetty-ee8-servlet</artifactId>
+          <version>12.1.5</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>org.eclipse.jetty.ee8</groupId>
+          <artifactId>jetty-ee8-nested</artifactId>
+          <version>12.1.5</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>org.eclipse.jetty.ee8</groupId>
+          <artifactId>jetty-ee8-security</artifactId>
+          <version>12.1.5</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>org.eclipse.jetty</groupId>
+          <artifactId>jetty-http</artifactId>
+          <version>12.1.5</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>org.eclipse.jetty</groupId>
+          <artifactId>jetty-io</artifactId>
+          <version>12.1.5</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>org.eclipse.jetty</groupId>
+          <artifactId>jetty-security</artifactId>
+          <version>12.1.5</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>org.eclipse.jetty</groupId>
+          <artifactId>jetty-server</artifactId>
+          <version>12.1.5</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>org.eclipse.jetty</groupId>
+          <artifactId>jetty-session</artifactId>
+          <version>12.1.5</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>org.eclipse.jetty</groupId>
+          <artifactId>jetty-util</artifactId>
+          <version>12.1.5</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>org.eclipse.jetty</groupId>
+          <artifactId>jetty-util-ajax</artifactId>
+          <version>12.1.5</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>jakarta.servlet</groupId>
+          <artifactId>jakarta.servlet-api</artifactId>
+          <version>4.0.4</version>
+          <type>jar</type>
+        </dependency>
+      </dependencies>
+    </location>
+    <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="javaewah">
+      <dependencies>
+        <dependency>
+          <groupId>com.googlecode.javaewah</groupId>
+          <artifactId>JavaEWAH</artifactId>
+          <version>1.2.3</version>
+          <type>jar</type>
+        </dependency>
+      </dependencies>
+    </location>
+    <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="hamcrest">
+      <dependencies>
+        <dependency>
+          <groupId>org.hamcrest</groupId>
+          <artifactId>hamcrest</artifactId>
+          <version>3.0</version>
+          <type>jar</type>
+        </dependency>
+      </dependencies>
+    </location>
+    <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="gson">
+      <dependencies>
+        <dependency>
+          <groupId>com.google.code.gson</groupId>
+          <artifactId>gson</artifactId>
+          <version>2.13.2</version>
+          <type>jar</type>
+        </dependency>
+      </dependencies>
+    </location>
+    <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bytebuddy">
+      <dependencies>
+        <dependency>
+          <groupId>net.bytebuddy</groupId>
+          <artifactId>byte-buddy</artifactId>
+          <version>1.18.4</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>net.bytebuddy</groupId>
+          <artifactId>byte-buddy-agent</artifactId>
+          <version>1.18.4</version>
+          <type>jar</type>
+        </dependency>
+      </dependencies>
+    </location>
+    <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bouncycastle">
+      <dependencies>
+        <dependency>
+          <groupId>org.bouncycastle</groupId>
+          <artifactId>bcpg-jdk18on</artifactId>
+          <version>1.83</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>org.bouncycastle</groupId>
+          <artifactId>bcprov-jdk18on</artifactId>
+          <version>1.83</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>org.bouncycastle</groupId>
+          <artifactId>bcpkix-jdk18on</artifactId>
+          <version>1.83</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>org.bouncycastle</groupId>
+          <artifactId>bcutil-jdk18on</artifactId>
+          <version>1.83</version>
+          <type>jar</type>
+        </dependency>
+      </dependencies>
+    </location>
+    <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="assertj">
+      <dependencies>
+        <dependency>
+          <groupId>org.assertj</groupId>
+          <artifactId>assertj-core</artifactId>
+          <version>3.27.7</version>
+          <type>jar</type>
+        </dependency>
+      </dependencies>
+    </location>
+    <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="args4j">
+      <dependencies>
+        <dependency>
+          <groupId>args4j</groupId>
+          <artifactId>args4j</artifactId>
+          <version>2.37</version>
+          <type>jar</type>
+        </dependency>
+      </dependencies>
+    </location>
+    <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="apache">
+      <dependencies>
+        <dependency>
+          <groupId>commons-codec</groupId>
+          <artifactId>commons-codec</artifactId>
+          <version>1.20.0</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>org.apache.commons</groupId>
+          <artifactId>commons-compress</artifactId>
+          <version>1.28.0</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>org.apache.commons</groupId>
+          <artifactId>commons-lang3</artifactId>
+          <version>3.20.0</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>commons-io</groupId>
+          <artifactId>commons-io</artifactId>
+          <version>2.21.0</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>commons-logging</groupId>
+          <artifactId>commons-logging</artifactId>
+          <version>1.3.5</version>
+          <type>jar</type>
+        </dependency>
+      </dependencies>
+    </location>
+  </locations>
+</target>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.39.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.39.tpd
new file mode 100644
index 0000000..0b32b1b
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.39.tpd
@@ -0,0 +1,8 @@
+target "jgit-4.39" with source configurePhase
+
+include "orbit/orbit-4.39.tpd"
+include "maven/dependencies.tpd"
+
+location "https://download.eclipse.org/staging/2026-03/" {
+	org.eclipse.osgi lazy
+}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/maven/dependencies.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/maven/dependencies.tpd
index 04bf070..9ba7c1c 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/maven/dependencies.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/maven/dependencies.tpd
@@ -56,7 +56,7 @@
 	dependency {
 		groupId = "org.assertj"
 		artifactId = "assertj-core"
-		version = "3.27.6"
+		version = "3.27.7"
 	}
 }
 
@@ -97,12 +97,12 @@
 	dependency {
 		groupId = "net.bytebuddy"
 		artifactId = "byte-buddy"
-		version = "1.18.2"
+		version = "1.18.4"
 	}
 	dependency {
 		groupId = "net.bytebuddy"
 		artifactId = "byte-buddy-agent"
-		version = "1.18.2"
+		version = "1.18.4"
 	}
 }
 
@@ -235,7 +235,7 @@
 	dependency {
 		groupId = "org.mockito"
 		artifactId = "mockito-core"
-		version = "5.20.0"
+		version = "5.21.0"
 	}
 }
 
@@ -248,12 +248,12 @@
 	dependency {
 		groupId = "org.apache.sshd"
 		artifactId = "sshd-osgi"
-		version = "2.16.0"
+		version = "2.17.1"
 	}
 	dependency {
 		groupId = "org.apache.sshd"
 		artifactId = "sshd-sftp"
-		version = "2.16.0"
+		version = "2.17.1"
 	}
 }
 
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.39.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.39.tpd
new file mode 100644
index 0000000..48725ca
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.39.tpd
@@ -0,0 +1,29 @@
+target "orbit-4.39" with source configurePhase
+// see https://download.eclipse.org/tools/orbit/downloads/
+
+location "https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2026-03" {
+	com.jcraft.jsch [0.1.55.v20230916-1400,0.1.55.v20230916-1400]
+	com.jcraft.jsch.source [0.1.55.v20230916-1400,0.1.55.v20230916-1400]
+	com.jcraft.jzlib [1.1.3.v20230916-1400,1.1.3.v20230916-1400]
+	com.jcraft.jzlib.source [1.1.3.v20230916-1400,1.1.3.v20230916-1400]
+	org.apache.ant [1.10.15.v20240901-1000,1.10.15.v20240901-1000]
+	org.apache.ant.source [1.10.15.v20240901-1000,1.10.15.v20240901-1000]
+	org.apache.aries.spifly.dynamic.bundle [1.3.7,1.3.7]
+	org.apache.httpcomponents.httpclient [4.5.14,4.5.14]
+	org.apache.httpcomponents.httpclient.source [4.5.14,4.5.14]
+	org.apache.httpcomponents.httpcore [4.4.16,4.4.16]
+	org.apache.httpcomponents.httpcore.source [4.4.16,4.4.16]
+	org.hamcrest [3.0.0,3.0.0]
+	org.hamcrest.source [3.0.0,3.0.0]
+	org.junit [4.13.2.v20240929-1000,4.13.2.v20240929-1000]
+	org.junit.source [4.13.2.v20240929-1000,4.13.2.v20240929-1000]
+	org.objectweb.asm [9.9.1,9.9.1]
+	org.objectweb.asm.commons [9.9.1,9.9.1]
+	org.objectweb.asm.util [9.9.1,9.9.1]
+	org.objectweb.asm.tree [9.9.1,9.9.1]
+	org.objectweb.asm.tree.analysis [9.9.1,9.9.1]
+	org.objenesis [3.4,3.4]
+	org.objenesis.source [3.4,3.4]
+	org.osgi.service.cm [1.6.1.202109301733,1.6.1.202109301733]
+	org.osgi.service.cm.source [1.6.1.202109301733,1.6.1.202109301733]
+}
diff --git a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
index 606b29d..96ecf2a 100644
--- a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
+++ b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
@@ -284,6 +284,8 @@
 usage_DisplayTheVersionOfJgit=Display the version of jgit
 usage_Exclude=Do not consider tags matching the given glob(7) pattern, excluding the "refs/tags/" prefix
 usage_Gc=Cleanup unnecessary files and optimize the local repository
+usage_GcPackRefs=Pack all refs except symbolic refs, default can be configured by "gc.packRefs" which defaults to true
+usage_GcNoPackRefs=Do not pack refs
 usage_Glog=View commit history as a graph
 usage_DiffGuiTool=When git-difftool is invoked with the -g or --gui option the default diff tool will be read from the configured diff.guitool variable instead of diff.tool.
 usage_MergeGuiTool=When git-mergetool is invoked with the -g or --gui option the default merge tool will be read from the configured merge.guitool variable instead of merge.tool.
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Gc.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Gc.java
index 35ac7a1..f278e55 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Gc.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Gc.java
@@ -13,6 +13,8 @@
 import org.eclipse.jgit.api.GarbageCollectCommand;
 import org.eclipse.jgit.api.Git;
 import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.lib.GcConfig;
+import org.eclipse.jgit.lib.GcConfig.PackRefsMode;
 import org.eclipse.jgit.lib.TextProgressMonitor;
 import org.kohsuke.args4j.Option;
 
@@ -30,6 +32,16 @@ class Gc extends TextBuiltin {
 	@Option(name = "--pack-kept-objects", usage = "usage_PackKeptObjects")
 	private Boolean packKeptObjects;
 
+	@Option(name = "--pack-refs", forbids = {
+			"--no-pack-refs" }, usage = "usage_GcPackRefs")
+	private Boolean packRefs;
+
+	@Option(name = "--no-pack-refs", forbids = {
+			"--pack-refs" }, usage = "usage_GcNoPackRefs")
+	void noPackRefs(@SuppressWarnings("unused") final boolean ignored) {
+		packRefs = Boolean.FALSE;
+	}
+
 	/** {@inheritDoc} */
 	@Override
 	protected void run() {
@@ -46,6 +58,11 @@ protected void run() {
 			if (packKeptObjects != null) {
 				command.setPackKeptObjects(packKeptObjects.booleanValue());
 			}
+			if (packRefs != null) {
+				command.setGcConfig(
+						new GcConfig(packRefs.booleanValue() ? PackRefsMode.TRUE
+								: PackRefsMode.FALSE));
+			}
 			command.call();
 		} catch (GitAPIException e) {
 			throw die(e.getMessage(), e);
diff --git a/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF
index 21aa80f..d2bf5ae 100644
--- a/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF
@@ -8,24 +8,24 @@
 Bundle-Localization: plugin
 Bundle-RequiredExecutionEnvironment: JavaSE-17
 Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git
-Import-Package: org.apache.sshd.agent;version="[2.16.0,2.17.0)",
- org.apache.sshd.certificate;version="[2.16.0,2.17.0)",
- org.apache.sshd.client.config.hosts;version="[2.16.0,2.17.0)",
- org.apache.sshd.common;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.auth;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.cipher;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.config.keys;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.helpers;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.kex;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.keyprovider;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.session;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.signature;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.util.buffer;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.util.net;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.util.security;version="[2.16.0,2.17.0)",
- org.apache.sshd.core;version="[2.16.0,2.17.0)",
- org.apache.sshd.server;version="[2.16.0,2.17.0)",
- org.apache.sshd.server.forward;version="[2.16.0,2.17.0)",
+Import-Package: org.apache.sshd.agent;version="[2.17.1,2.18.0)",
+ org.apache.sshd.certificate;version="[2.17.1,2.18.0)",
+ org.apache.sshd.client.config.hosts;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.auth;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.cipher;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.config.keys;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.helpers;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.kex;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.keyprovider;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.session;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.signature;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.util.buffer;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.util.net;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.util.security;version="[2.17.1,2.18.0)",
+ org.apache.sshd.core;version="[2.17.1,2.18.0)",
+ org.apache.sshd.server;version="[2.17.1,2.18.0)",
+ org.apache.sshd.server.forward;version="[2.17.1,2.18.0)",
  org.eclipse.jgit.annotations;version="[7.6.0,7.7.0)",
  org.eclipse.jgit.api;version="[7.6.0,7.7.0)",
  org.eclipse.jgit.api.errors;version="[7.6.0,7.7.0)",
diff --git a/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF b/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF
index 97d5656..7a7d7e1 100644
--- a/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF
@@ -39,58 +39,58 @@
    org.apache.sshd.client.keyverifier",
  org.eclipse.jgit.transport.sshd.agent;version="7.6.0"
 Import-Package: org.bouncycastle.jce.provider;version="[1.80.0,2.0.0)",
- org.apache.sshd.agent;version="[2.16.0,2.17.0)",
- org.apache.sshd.client;version="[2.16.0,2.17.0)",
- org.apache.sshd.client.auth;version="[2.16.0,2.17.0)",
- org.apache.sshd.client.auth.keyboard;version="[2.16.0,2.17.0)",
- org.apache.sshd.client.auth.password;version="[2.16.0,2.17.0)",
- org.apache.sshd.client.auth.pubkey;version="[2.16.0,2.17.0)",
- org.apache.sshd.client.channel;version="[2.16.0,2.17.0)",
- org.apache.sshd.client.config.hosts;version="[2.16.0,2.17.0)",
- org.apache.sshd.client.config.keys;version="[2.16.0,2.17.0)",
- org.apache.sshd.client.future;version="[2.16.0,2.17.0)",
- org.apache.sshd.client.keyverifier;version="[2.16.0,2.17.0)",
- org.apache.sshd.client.session;version="[2.16.0,2.17.0)",
- org.apache.sshd.client.session.forward;version="[2.16.0,2.17.0)",
- org.apache.sshd.common;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.auth;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.channel;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.cipher;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.compression;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.config.keys;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.config.keys.loader;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.config.keys.loader.openssh.kdf;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.config.keys.u2f;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.digest;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.forward;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.future;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.helpers;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.io;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.kex;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.kex.extension;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.kex.extension.parser;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.keyprovider;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.mac;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.random;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.session;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.session.helpers;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.signature;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.util;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.util.buffer;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.util.buffer.keys;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.util.closeable;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.util.io;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.util.io.der;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.util.io.functors;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.util.io.resource;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.util.logging;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.util.net;version="[2.16.0,2.17.0)",
- org.apache.sshd.common.util.security;version="[2.16.0,2.17.0)",
- org.apache.sshd.core;version="[2.16.0,2.17.0)",
- org.apache.sshd.server.auth;version="[2.16.0,2.17.0)",
- org.apache.sshd.sftp;version="[2.16.0,2.17.0)",
- org.apache.sshd.sftp.client;version="[2.16.0,2.17.0)",
- org.apache.sshd.sftp.common;version="[2.16.0,2.17.0)",
+ org.apache.sshd.agent;version="[2.17.1,2.18.0)",
+ org.apache.sshd.client;version="[2.17.1,2.18.0)",
+ org.apache.sshd.client.auth;version="[2.17.1,2.18.0)",
+ org.apache.sshd.client.auth.keyboard;version="[2.17.1,2.18.0)",
+ org.apache.sshd.client.auth.password;version="[2.17.1,2.18.0)",
+ org.apache.sshd.client.auth.pubkey;version="[2.17.1,2.18.0)",
+ org.apache.sshd.client.channel;version="[2.17.1,2.18.0)",
+ org.apache.sshd.client.config.hosts;version="[2.17.1,2.18.0)",
+ org.apache.sshd.client.config.keys;version="[2.17.1,2.18.0)",
+ org.apache.sshd.client.future;version="[2.17.1,2.18.0)",
+ org.apache.sshd.client.keyverifier;version="[2.17.1,2.18.0)",
+ org.apache.sshd.client.session;version="[2.17.1,2.18.0)",
+ org.apache.sshd.client.session.forward;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.auth;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.channel;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.cipher;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.compression;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.config.keys;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.config.keys.loader;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.config.keys.loader.openssh.kdf;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.config.keys.u2f;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.digest;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.forward;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.future;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.helpers;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.io;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.kex;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.kex.extension;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.kex.extension.parser;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.keyprovider;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.mac;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.random;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.session;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.session.helpers;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.signature;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.util;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.util.buffer;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.util.buffer.keys;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.util.closeable;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.util.io;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.util.io.der;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.util.io.functors;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.util.io.resource;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.util.logging;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.util.net;version="[2.17.1,2.18.0)",
+ org.apache.sshd.common.util.security;version="[2.17.1,2.18.0)",
+ org.apache.sshd.core;version="[2.17.1,2.18.0)",
+ org.apache.sshd.server.auth;version="[2.17.1,2.18.0)",
+ org.apache.sshd.sftp;version="[2.17.1,2.18.0)",
+ org.apache.sshd.sftp.client;version="[2.17.1,2.18.0)",
+ org.apache.sshd.sftp.common;version="[2.17.1,2.18.0)",
  org.eclipse.jgit.annotations;version="[7.6.0,7.7.0)",
  org.eclipse.jgit.api.errors;version="[7.6.0,7.7.0)",
  org.eclipse.jgit.errors;version="[7.6.0,7.7.0)",
diff --git a/org.eclipse.jgit.test/src/org/eclipse/jgit/internal/storage/dfs/MidxTestUtils.java b/org.eclipse.jgit.test/src/org/eclipse/jgit/internal/storage/dfs/MidxTestUtils.java
new file mode 100644
index 0000000..c5210c8
--- /dev/null
+++ b/org.eclipse.jgit.test/src/org/eclipse/jgit/internal/storage/dfs/MidxTestUtils.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2025, Google LLC.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.internal.storage.dfs;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.zip.Deflater;
+
+import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.lib.NullProgressMonitor;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.revwalk.RevBlob;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevTree;
+import org.eclipse.jgit.storage.pack.PackConfig;
+
+/**
+ * Helpers to write multipack indexes
+ */
+public class MidxTestUtils {
+	private MidxTestUtils() {
+	}
+
+	/**
+	 * Write a single pack into the repo with the blob as contents
+	 *
+	 * @param db
+	 *            repository
+	 * @param blob
+	 *            blob to write into the pack
+	 * @return object id of the blob written in the pack
+	 * @throws IOException
+	 *             a problem writing in the repo
+	 */
+	static ObjectId writePackWithBlob(DfsRepository db, String blob)
+			throws IOException {
+		return writePackWithBlobs(db, blob)[0];
+	}
+
+	/**
+	 * Write multiple blobs into a single pack in the repo
+	 *
+	 * @param db
+	 *            repository
+	 * @param blobs
+	 *            blobs to write into the pack
+	 * @return object ids of the blobs written in the pack, in the same order as
+	 *         the input parameters
+	 * @throws IOException
+	 *             a problem writing in the repo
+	 */
+	static ObjectId[] writePackWithBlobs(DfsRepository db, String... blobs)
+			throws IOException {
+		ObjectId[] oids = new ObjectId[blobs.length];
+
+		DfsInserter ins = (DfsInserter) db.newObjectInserter();
+		ins.setCompressionLevel(Deflater.NO_COMPRESSION);
+		for (int i = 0; i < blobs.length; i++) {
+			oids[i] = ins.insert(OBJ_BLOB, blobs[i].getBytes(UTF_8));
+		}
+		ins.flush();
+		return oids;
+	}
+
+	/**
+	 * Write a midx covering the only pack in the repo
+	 *
+	 * @param db
+	 *            a repository with a single pack
+	 * @return a midx covering that single pack
+	 * @throws IOException
+	 *             a problem writing in the repo
+	 */
+	static DfsPackFileMidx writeSinglePackMidx(DfsRepository db)
+			throws IOException {
+		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
+		assertEquals("More than one pack in db", 1, packs.length);
+		return writeSinglePackMidx(db, packs[0]);
+	}
+
+	/**
+	 * Write a midx covering a single pack
+	 *
+	 * @param db
+	 *            a repository to write the midx covering the pack
+	 * @param pack
+	 *            a pack in the repository that will be covered by a new midx
+	 * @return a midx covering that single pack
+	 * @throws IOException
+	 *             a problem writing in the repo
+	 */
+	static DfsPackFileMidx writeSinglePackMidx(DfsRepository db,
+			DfsPackFile pack) throws IOException {
+		return writeMultipackIndex(db, new DfsPackFile[] { pack }, null);
+	}
+
+	/**
+	 * Write a midx covering a single pack
+	 *
+	 * @param db
+	 *            a repository to write the midx covering the pack
+	 * @param pack
+	 *            a pack in the repository that will be covered by a new midx
+	 * @param base
+	 *            base of this midx (can be null)
+	 * @return a midx covering that single pack
+	 * @throws IOException
+	 *             a problem writing in the repo
+	 */
+	static DfsPackFileMidx writeSinglePackMidx(DfsRepository db,
+			DfsPackFile pack, @Nullable DfsPackFileMidx base)
+			throws IOException {
+		return writeMultipackIndex(db, new DfsPackFile[] { pack }, base);
+	}
+
+	/**
+	 * Write a midx in the repository
+	 *
+	 * @param db
+	 *            the repository
+	 * @param packs
+	 *            packs to be covered by this midx
+	 * @param base
+	 *            base of the newly created midx
+	 * @return the new midx instance
+	 * @throws IOException
+	 *             a problem writing in the repo
+	 */
+	static DfsPackFileMidx writeMultipackIndex(DfsRepository db,
+			DfsPackFile[] packs, DfsPackFileMidx base) throws IOException {
+		PackConfig packConfig = new PackConfig(db);
+		packConfig.setBitmapRecentCommitSpan(1); // bitmap every commit!
+		DfsPackDescription desc = DfsMidxWriter.writeMidx(
+				NullProgressMonitor.INSTANCE, db.getObjectDatabase(),
+				Arrays.asList(packs),
+				base != null ? base.getPackDescription() : null, packConfig);
+		db.getObjectDatabase().commitPack(List.of(desc), null);
+		return DfsPackFileMidx.create(DfsBlockCache.getInstance(), desc,
+				Arrays.asList(packs), base);
+	}
+
+	record CommitObjects(RevCommit commit, RevTree tree, RevBlob blob) {
+	}
+
+	private static int commitCounter = 1;
+
+	static List<CommitObjects> writeCommitChain(DfsRepository db,
+			String refname, int length) throws Exception {
+		List<CommitObjects> co = new ArrayList<>(length);
+		RevCommit tip = null;
+		Ref ref = db.getRefDatabase().findRef(refname);
+		if (ref != null) {
+			tip = db.parseCommit(ref.getObjectId());
+		}
+
+		try (TestRepository<InMemoryRepository> repository = new TestRepository<>(
+				(InMemoryRepository) db);
+				DfsInserter ins = (DfsInserter) db.getObjectDatabase()
+						.newInserter()) {
+			for (int i = 0; i < length; i++) {
+				RevBlob blob = repository.blob("blob" + commitCounter);
+
+				tip = repository.branch(refname).commit().parent(tip)
+						.add("blob" + commitCounter, blob).create();
+				commitCounter++;
+				co.add(new CommitObjects(tip, tip.getTree(), blob));
+			}
+		}
+		return co;
+	}
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/GarbageCollectCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/GarbageCollectCommandTest.java
index 6090d5e..2954570 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/GarbageCollectCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/GarbageCollectCommandTest.java
@@ -9,12 +9,16 @@
  */
 package org.eclipse.jgit.api;
 
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
+import java.io.IOException;
 import java.time.Instant;
 import java.util.Properties;
 
 import org.eclipse.jgit.junit.RepositoryTestCase;
+import org.eclipse.jgit.lib.GcConfig;
+import org.eclipse.jgit.lib.GcConfig.PackRefsMode;
 import org.eclipse.jgit.util.GitTimeParser;
 import org.junit.Before;
 import org.junit.Test;
@@ -34,6 +38,22 @@ public void setUp() throws Exception {
 	}
 
 	@Test
+	public void testPackRefs() throws Exception {
+		assertTrue(hasLooseRef(git));
+
+		// by default, refs should be packed
+		git.gc().call();
+		assertFalse(hasLooseRef(git));
+
+		// now create a loose ref again
+		git.branchCreate().setName("foo").call();
+		assertTrue(hasLooseRef(git));
+
+		git.gc().setGcConfig(new GcConfig(PackRefsMode.FALSE)).call();
+		assertTrue(hasLooseRef(git));
+	}
+
+	@Test
 	public void testGConeCommit() throws Exception {
 		Instant expireNow = GitTimeParser.parseInstant("now");
 		Properties res = git.gc().setExpire(expireNow).call();
@@ -54,4 +74,10 @@ public void testGCmoreCommits() throws Exception {
 		Properties res = git.gc().setExpire(expireNow).call();
 		assertTrue(res.size() == 8);
 	}
+
+	private static boolean hasLooseRef(Git git) throws IOException {
+		return git.getRepository().getRefDatabase().getRefs().stream()
+				.filter(r -> !r.isSymbolic())
+				.anyMatch(r -> r.getStorage().isLoose());
+	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollectorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollectorTest.java
index 0752cd5..c5acb95 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollectorTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollectorTest.java
@@ -1243,9 +1243,7 @@ public void midx_oneMidx_deleteMidxs_allObjectsOneGC() throws Exception {
 				.add("file.txt", git.blob("a blob")).parent(root).create();
 		assertEquals(3, countPacks(INSERT));
 
-		DfsPackDescription midx = DfsMidxWriter.writeMidx(
-				NullProgressMonitor.INSTANCE, odb,
-				Arrays.asList(odb.getPacks()), null);
+		DfsPackDescription midx = midx(Arrays.asList(odb.getPacks()), null);
 		odb.commitPack(List.of(midx), null);
 
 		gcNoTtl();
@@ -1279,13 +1277,11 @@ public void midx_chainedMidx_deleteMidxs_allObjsInOneGC() throws Exception {
 
 		List<DfsPackFile> basicPacks = Arrays.stream(odb.getPacks())
 				.collect(Collectors.toUnmodifiableList());
-		DfsPackDescription midx = DfsMidxWriter.writeMidx(NULL_PM, odb,
-				basicPacks.subList(0, 9), null);
-		odb.commitPack(List.of(midx), null);
+		DfsPackDescription baseMidx = midx(basicPacks.subList(0, 9), null);
+		odb.commitPack(List.of(baseMidx), null);
 
-		DfsPackDescription midx2 = DfsMidxWriter.writeMidx(NULL_PM, odb,
-				basicPacks.subList(9, 21), midx);
-		odb.commitPack(List.of(midx2), null);
+		DfsPackDescription tipMidx = midx(basicPacks.subList(9, 21), baseMidx);
+		odb.commitPack(List.of(tipMidx), null);
 
 		// Verify we got one pack that is an midx
 		// This is testing the test code
@@ -1294,7 +1290,7 @@ public void midx_chainedMidx_deleteMidxs_allObjsInOneGC() throws Exception {
 		DfsPackDescription theDesc = odb.getPacks()[0].getPackDescription();
 		assertTrue(theDesc.hasFileExt(MULTI_PACK_INDEX));
 		assertEquals(12, theDesc.getCoveredPacks().size());
-		assertEquals(theDesc.getMultiPackIndexBase(), midx);
+		assertEquals(theDesc.getMultiPackIndexBase(), baseMidx);
 		assertEquals(9,
 				theDesc.getMultiPackIndexBase().getCoveredPacks().size());
 		gcNoTtl();
@@ -1308,8 +1304,8 @@ public void midx_chainedMidx_deleteMidxs_allObjsInOneGC() throws Exception {
 		for (RevCommit c : knownCommits) {
 			assertTrue(isObjectInPack(c, pack));
 		}
-		assertFalse(odb.listPacks().contains(midx));
-		assertFalse(odb.listPacks().contains(midx2));
+		assertFalse(odb.listPacks().contains(baseMidx));
+		assertFalse(odb.listPacks().contains(tipMidx));
 	}
 
 	@Test
@@ -1323,8 +1319,7 @@ public void midx_packAndMidx_deleteMidxs_allObjectsOneGC()
 		assertEquals(3, countPacks(INSERT));
 
 		List<DfsPackFile> packs = Arrays.stream(odb.getPacks()).toList();
-		DfsPackDescription midx = DfsMidxWriter.writeMidx(NULL_PM, odb, packs,
-				null);
+		DfsPackDescription midx = midx(packs, null);
 		odb.commitPack(List.of(midx), null);
 
 		RevBlob blobOutOfMidx = git.blob("some content");
@@ -1500,6 +1495,15 @@ private static DfsPackFile findFirstBySource(DfsPackFile[] packs, PackSource sou
 				.findFirst().get();
 	}
 
+	private DfsPackDescription midx(List<DfsPackFile> coveredPacks,
+			DfsPackDescription base) throws IOException {
+		DfsPackDescription midx = DfsMidxWriter.writeMidx(NULL_PM, odb,
+				coveredPacks, base);
+		git.tick(1);
+		midx.setLastModified(git.getInstant().toEpochMilli());
+		return midx;
+	}
+
 	private TestRepository<InMemoryRepository>.CommitBuilder commit() {
 		return git.commit();
 	}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsMidxWriterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsMidxWriterTest.java
new file mode 100644
index 0000000..ac89baa
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsMidxWriterTest.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2026, Google LLC.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.internal.storage.dfs;
+
+import static org.eclipse.jgit.internal.storage.dfs.MidxTestUtils.writeMultipackIndex;
+import static org.eclipse.jgit.internal.storage.dfs.MidxTestUtils.writeSinglePackMidx;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_BITMAP_DISTANT_COMMIT_SPAN;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_PACK_SECTION;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.jgit.internal.storage.dfs.MidxTestUtils.CommitObjects;
+import org.eclipse.jgit.internal.storage.file.PackBitmapIndex;
+import org.eclipse.jgit.internal.storage.file.PackReverseIndex;
+import org.eclipse.jgit.lib.NullProgressMonitor;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import com.googlecode.javaewah.EWAHCompressedBitmap;
+
+@RunWith(Parameterized.class)
+public class DfsMidxWriterTest {
+
+	@Parameterized.Parameters(name = "{0}")
+	public static Iterable<TestInput> data() throws Exception {
+		return List.of(setupOneMidxOverOnePack(), setupOneMidxOverNPacks());
+	}
+
+	private record TestInput(String testDesc, DfsRepository db,
+			DfsPackFileMidx midx, List<CommitObjects> commitObjects,
+			Map<String, CommitObjects> tips, int expectedBitmaps) {
+		@Override
+		public String toString() {
+			return testDesc;
+		}
+	}
+
+	private TestInput ti;
+
+	public DfsMidxWriterTest(TestInput ti) {
+		this.ti = ti;
+	}
+
+	@Test
+	public void bitmapIndex_allObjectsHaveBitmapPosition() throws IOException {
+		try (DfsReader ctx = ti.db().getObjectDatabase().newReader()) {
+			PackBitmapIndex bi = ti.midx().getBitmapIndex(ctx);
+			for (int i = 0; i < ti.midx().getObjectCount(ctx); i++) {
+				PackReverseIndex reverseIdx = ti.midx().getReverseIdx(ctx);
+				// All objects in the bitmap
+				ObjectId oidByOffset = reverseIdx.findObjectByPosition(i);
+				assertEquals(i, bi.findPosition(oidByOffset));
+			}
+		}
+	}
+
+	@Test
+	public void bitmapIndex_bitmapHasRightObjects() throws IOException {
+		try (DfsReader ctx = ti.db().getObjectDatabase().newReader()) {
+			PackBitmapIndex bi = ti.midx().getBitmapIndex(ctx);
+
+			ObjectId mainTip = ti.tips().get("refs/heads/main").commit();
+			ObjectId devTip = ti.tips().get("refs/heads/dev").commit();
+			EWAHCompressedBitmap mainBitmap = bi.getBitmap(mainTip);
+			EWAHCompressedBitmap devBitmap = bi.getBitmap(devTip);
+
+			// main and dev commit chains do not have any commit in common
+			assertTrue(mainBitmap.and(devBitmap).isEmpty());
+			assertEquals(420, ti.midx().getObjectCount(ctx));
+
+			RevWalk rw = new RevWalk(ti.db());
+			rw.markStart(rw.parseCommit(mainTip));
+			for (RevCommit c; (c = rw.next()) != null;) {
+				int bitmapPos = bi.findPosition(c);
+				assertTrue(mainBitmap.get(bitmapPos));
+				assertFalse(devBitmap.get(bitmapPos));
+			}
+			rw.reset();
+
+			// dev is an independent chain of commits. None of them
+			// should be in the bitmap of "main"
+			rw.markStart(rw.parseCommit(devTip));
+			for (RevCommit c; (c = rw.next()) != null;) {
+				int bitmapPos = bi.findPosition(c);
+				assertTrue(devBitmap.get(bitmapPos));
+				assertFalse(mainBitmap.get(bitmapPos));
+			}
+		}
+	}
+
+	static TestInput setupOneMidxOverNPacks() throws Exception {
+		InMemoryRepository db = new InMemoryRepository(
+				new DfsRepositoryDescription("one_midx_n_packs"));
+		db.getObjectDatabase().getReaderOptions().setUseMidxBitmaps(true);
+
+		List<CommitObjects> mainObjs = MidxTestUtils.writeCommitChain(db,
+				"refs/heads/main", 100);
+		List<CommitObjects> devObjs = MidxTestUtils.writeCommitChain(db,
+				"refs/heads/dev", 40);
+
+		Map<String, CommitObjects> tips = new HashMap<>();
+		tips.put("refs/heads/main", last(mainObjs));
+		tips.put("refs/heads/dev", last(devObjs));
+
+		List<CommitObjects> commitObjects = new ArrayList<>(160);
+		commitObjects.addAll(mainObjs);
+		commitObjects.addAll(devObjs);
+
+		DfsPackFileMidx midx1 = writeMultipackIndex(db,
+				db.getObjectDatabase().getPacks(), null);
+		return new TestInput("one midx - n packs", db, midx1, commitObjects,
+				tips, tips.size());
+	}
+
+	static TestInput setupOneMidxOverOnePack() throws Exception {
+		InMemoryRepository db = new InMemoryRepository(
+				new DfsRepositoryDescription("one_midx_n_packs"));
+		// Mo midx bitmaps in midx over one pack. No need to set useMidxBitmaps.
+		enableMidxBitmaps(db);
+
+		List<CommitObjects> mainObjs = MidxTestUtils.writeCommitChain(db,
+				"refs/heads/main", 100);
+		List<CommitObjects> devObjs = MidxTestUtils.writeCommitChain(db,
+				"refs/heads/dev", 40);
+		runGc(db);
+
+		Map<String, CommitObjects> tips = new HashMap<>();
+		tips.put("refs/heads/main", last(mainObjs));
+		tips.put("refs/heads/dev", last(devObjs));
+
+		List<CommitObjects> commitObjects = new ArrayList<>(160);
+		commitObjects.addAll(mainObjs);
+		commitObjects.addAll(devObjs);
+
+		DfsPackFileMidx midx1 = writeSinglePackMidx(db);
+		return new TestInput("one midx - one pack", db, midx1, commitObjects,
+				tips, 0);
+	}
+
+	private static void enableMidxBitmaps(DfsRepository repo) {
+		repo.getConfig().setInt(CONFIG_PACK_SECTION, null,
+				CONFIG_KEY_BITMAP_DISTANT_COMMIT_SPAN, 1);
+	}
+
+	private static void runGc(DfsRepository db) throws IOException {
+		DfsGarbageCollector garbageCollector = new DfsGarbageCollector(db);
+		garbageCollector.pack(NullProgressMonitor.INSTANCE);
+		assertEquals(1, garbageCollector.getNewPacks().size());
+	}
+
+	private static CommitObjects last(List<CommitObjects> l) {
+		return l.get(l.size() - 1);
+	}
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidxIndexTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidxIndexTest.java
new file mode 100644
index 0000000..8574688
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidxIndexTest.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2025, Google LLC.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.internal.storage.dfs;
+
+import static org.eclipse.jgit.internal.storage.dfs.MidxTestUtils.writeMultipackIndex;
+import static org.eclipse.jgit.internal.storage.dfs.MidxTestUtils.writePackWithBlobs;
+import static org.eclipse.jgit.internal.storage.dfs.MidxTestUtils.writeSinglePackMidx;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.jgit.internal.storage.file.PackIndex;
+import org.eclipse.jgit.internal.storage.file.PackReverseIndex;
+import org.eclipse.jgit.lib.AbbreviatedObjectId;
+import org.eclipse.jgit.lib.ObjectId;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class DfsPackFileMidxIndexTest {
+
+	private static final ObjectId NOT_IN_PACK = ObjectId
+			.fromString("3f306cb3fcd5116919fecad615524bd6e6ea4ba7");
+
+	private static final List<String> BLOBS = List.of("blob one", "blob two",
+			"blob three", "blob four", "blob five", "blob six");
+
+	@Parameters(name = "{0}")
+	public static Iterable<TestInput> data() throws IOException {
+		return List.of(setupOneMidxOverOnePack(), setupOneMidxOverNPacks(),
+				setupMidxChainEachOverNPacks(),
+				setupMidxChainSingleAndNPacks());
+	}
+
+	private record TestInput(String testDesc, DfsRepository db,
+			DfsPackFileMidx midx, ObjectId[] oids) {
+		@Override
+		public String toString() {
+			return testDesc;
+		}
+
+	}
+
+	private TestInput ti;
+
+	public DfsPackFileMidxIndexTest(TestInput ti) {
+		this.ti = ti;
+	}
+
+	@Test
+	public void getPackIndex_getObjectCount() {
+		try (DfsReader ctx = ti.db().getObjectDatabase().newReader()) {
+			assertEquals(ti.oids().length,
+					ti.midx().getPackIndex(ctx).getObjectCount());
+		}
+	}
+
+	@Test
+	public void getPackIndex_position_findPosition_getObjectId() {
+		try (DfsReader ctx = ti.db.getObjectDatabase().newReader()) {
+			PackIndex idx = ti.midx().getPackIndex(ctx);
+			for (int i = 0; i < ti.oids().length; i++) {
+				ObjectId expected = ti.oids()[i];
+				int position = idx.findPosition(expected);
+				assertNotEquals(-1, position);
+				ObjectId actual = idx.getObjectId(position);
+				assertEquals(expected, actual);
+			}
+			assertEquals(-1, idx.findPosition(NOT_IN_PACK));
+		}
+	}
+
+	@Test
+	public void getPackIndex_offset_findOffset_getOffset() {
+		try (DfsReader ctx = ti.db.getObjectDatabase().newReader()) {
+			PackIndex idx = ti.midx().getPackIndex(ctx);
+			for (int i = 0; i < ti.oids().length; i++) {
+				ObjectId oid = ti.oids()[i];
+				int oidPosition = idx.findPosition(oid);
+
+				long offsetById = idx.findOffset(oid);
+				long offsetByPos = idx.getOffset(oidPosition);
+				assertEquals(offsetById, offsetByPos);
+			}
+			assertEquals(-1, idx.findOffset(NOT_IN_PACK));
+		}
+	}
+
+	@Test
+	public void getPackIndex_objects_contains_hasObjects() {
+		try (DfsReader ctx = ti.db.getObjectDatabase().newReader()) {
+			PackIndex idx = ti.midx().getPackIndex(ctx);
+			for (int i = 0; i < ti.oids().length; i++) {
+				ObjectId oid = ti.oids()[i];
+				assertTrue(idx.contains(oid));
+				assertTrue(idx.hasObject(oid));
+			}
+			assertFalse(idx.contains(NOT_IN_PACK));
+			assertFalse(idx.hasObject(NOT_IN_PACK));
+		}
+	}
+
+	@Test
+	public void getPackIndex_resolve() throws IOException {
+		try (DfsReader ctx = ti.db.getObjectDatabase().newReader()) {
+			PackIndex idx = ti.midx().getPackIndex(ctx);
+			Set<ObjectId> matches = new HashSet<>();
+			// Sha1 of "blob two" = ae4116e0972d85cd751b458fea94ca9eb84dd692
+			idx.resolve(matches, AbbreviatedObjectId.fromString("ae411"), 100);
+			assertEquals(1, matches.size());
+		}
+	}
+
+	@Test
+	public void getReverseIndex_findObject() throws IOException {
+		try (DfsReader ctx = ti.db.getObjectDatabase().newReader()) {
+			PackIndex idx = ti.midx().getPackIndex(ctx);
+			PackReverseIndex ridx = ti.midx().getReverseIdx(ctx);
+			for (ObjectId oid : ti.oids()) {
+				long offset = idx.findOffset(oid);
+				assertEquals(oid, ridx.findObject(offset));
+			}
+		}
+	}
+
+	@Test
+	public void getReverseIndex_findObjectByPosition() throws IOException {
+		try (DfsReader ctx = ti.db.getObjectDatabase().newReader()) {
+			PackIndex idx = ti.midx().getPackIndex(ctx);
+			ObjectId[] offsetOrder = ti.oids().clone();
+			Arrays.sort(offsetOrder, Comparator.comparingLong(idx::findOffset));
+
+			PackReverseIndex ridx = ti.midx().getReverseIdx(ctx);
+			for (int i = 0; i < offsetOrder.length; i++) {
+				assertEquals(offsetOrder[i], ridx.findObjectByPosition(i));
+			}
+		}
+	}
+
+	@Test
+	public void getReverseIndex_findPosition() throws IOException {
+		try (DfsReader ctx = ti.db.getObjectDatabase().newReader()) {
+			PackIndex idx = ti.midx().getPackIndex(ctx);
+			ObjectId[] offsetOrder = ti.oids().clone();
+			Arrays.sort(offsetOrder, Comparator.comparingLong(idx::findOffset));
+
+			PackReverseIndex ridx = ti.midx().getReverseIdx(ctx);
+			for (int i = 0; i < offsetOrder.length; i++) {
+				long offset = idx.findOffset(offsetOrder[i]);
+				int position = ridx.findPosition(offset);
+				assertEquals(i, position);
+			}
+		}
+	}
+	static TestInput setupOneMidxOverOnePack() throws IOException {
+		InMemoryRepository db = new InMemoryRepository(
+				new DfsRepositoryDescription("one_midx_one_pack"));
+		ObjectId[] objectIds = writePackWithBlobs(db,
+				BLOBS.toArray(String[]::new));
+		DfsPackFileMidx midx1 = writeSinglePackMidx(db);
+		return new TestInput("one midx - one pack", db, midx1, objectIds);
+	}
+
+	static TestInput setupOneMidxOverNPacks() throws IOException {
+		InMemoryRepository db = new InMemoryRepository(
+				new DfsRepositoryDescription("one_midx_n_packs"));
+
+		ObjectId[] objectIds = BLOBS.stream().map(s -> {
+			try {
+				return MidxTestUtils.writePackWithBlob(db, s);
+			} catch (IOException e) {
+				throw new RuntimeException(e);
+			}
+		}).toArray(ObjectId[]::new);
+		DfsPackFileMidx midx1 = writeMultipackIndex(db,
+				db.getObjectDatabase().getPacks(), null);
+		return new TestInput("one midx - n packs", db, midx1, objectIds);
+	}
+
+	static TestInput setupMidxChainEachOverNPacks() throws IOException {
+		InMemoryRepository db = new InMemoryRepository(
+				new DfsRepositoryDescription("two_midx_3_packs_each"));
+
+		ObjectId[] objectIds = BLOBS.stream().map(s -> {
+			try {
+				return MidxTestUtils.writePackWithBlob(db, s);
+			} catch (IOException e) {
+				throw new RuntimeException(e);
+			}
+		}).toArray(ObjectId[]::new);
+		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
+		// If the amount of blobs (i.e. packs), adjust the ranges covered by
+		// midx.
+		assertEquals(6, BLOBS.size());
+		DfsPackFileMidx midxBase = MidxTestUtils.writeMultipackIndex(db,
+				Arrays.copyOfRange(packs, 3, 6), null);
+		DfsPackFileMidx midxTip = MidxTestUtils.writeMultipackIndex(db,
+				Arrays.copyOfRange(packs, 0, 3), midxBase);
+		return new TestInput("two midx - 3 packs each", db, midxTip, objectIds);
+	}
+
+	static TestInput setupMidxChainSingleAndNPacks() throws IOException {
+		InMemoryRepository db = new InMemoryRepository(
+				new DfsRepositoryDescription("two_midx_3_packs_each"));
+
+		ObjectId[] objectIds = BLOBS.stream().map(s -> {
+			try {
+				return MidxTestUtils.writePackWithBlob(db, s);
+			} catch (IOException e) {
+				throw new RuntimeException(e);
+			}
+		}).toArray(ObjectId[]::new);
+		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
+		// If the amount of blobs (i.e. packs), adjust the ranges covered by
+		// midx.
+		assertEquals(6, BLOBS.size());
+		DfsPackFileMidx midxBase = MidxTestUtils.writeMultipackIndex(db,
+				Arrays.copyOfRange(packs, 1, 6), null);
+		DfsPackFileMidx midxTip = MidxTestUtils.writeMultipackIndex(db,
+				Arrays.copyOfRange(packs, 0, 1), midxBase);
+		return new TestInput("two midx - 1 pack, 5 packs", db, midxTip,
+				objectIds);
+	}
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidxNPacksTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidxNPacksTest.java
index 758ac1f..0f0e113 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidxNPacksTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidxNPacksTest.java
@@ -12,12 +12,15 @@
 import static java.nio.charset.StandardCharsets.UTF_8;
 import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.GC;
 import static org.eclipse.jgit.internal.storage.pack.PackExt.PACK;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_BITMAP_DISTANT_COMMIT_SPAN;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_PACK_SECTION;
 import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
 import static org.eclipse.jgit.lib.Constants.OBJ_COMMIT;
 import static org.eclipse.jgit.lib.Constants.OBJ_TREE;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertThrows;
@@ -27,11 +30,8 @@
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.util.Arrays;
-import java.util.HashMap;
 import java.util.HashSet;
-import java.util.LinkedHashMap;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 import java.util.zip.Deflater;
 
@@ -40,11 +40,8 @@
 import org.eclipse.jgit.internal.storage.dfs.DfsPackFileMidx.VOffsetCalculator;
 import org.eclipse.jgit.internal.storage.dfs.DfsPackFileMidxNPacks.VOffsetCalculatorNPacks;
 import org.eclipse.jgit.internal.storage.file.PackBitmapIndex;
-import org.eclipse.jgit.internal.storage.file.PackIndex;
 import org.eclipse.jgit.internal.storage.midx.MultiPackIndex.PackOffset;
-import org.eclipse.jgit.internal.storage.midx.MultiPackIndexWriter;
 import org.eclipse.jgit.internal.storage.pack.ObjectToPack;
-import org.eclipse.jgit.internal.storage.pack.PackExt;
 import org.eclipse.jgit.internal.storage.pack.PackOutputStream;
 import org.eclipse.jgit.internal.storage.pack.PackWriter;
 import org.eclipse.jgit.junit.JGitTestUtil;
@@ -55,6 +52,7 @@
 import org.eclipse.jgit.lib.ObjectInserter;
 import org.eclipse.jgit.lib.ObjectLoader;
 import org.eclipse.jgit.lib.ProgressMonitor;
+import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.revwalk.RevBlob;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevTree;
@@ -63,6 +61,8 @@
 import org.junit.Before;
 import org.junit.Test;
 
+import com.googlecode.javaewah.EWAHCompressedBitmap;
+
 public class DfsPackFileMidxNPacksTest {
 
 	private static final ObjectId NOT_IN_PACK = ObjectId
@@ -101,11 +101,11 @@ public void midx_findIdxPosition_withBase() throws IOException {
 		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
 
 		// Packs are in reverse insertion order
-		DfsPackFileMidx midxBase = writeMultipackIndex(
+		DfsPackFileMidx midxBase = MidxTestUtils.writeMultipackIndex(db,
 				Arrays.copyOfRange(packs, 4, 6), null);
-		DfsPackFileMidx midxMid = writeMultipackIndex(
+		DfsPackFileMidx midxMid = MidxTestUtils.writeMultipackIndex(db,
 				Arrays.copyOfRange(packs, 2, 4), midxBase);
-		DfsPackFileMidx midxTip = writeMultipackIndex(
+		DfsPackFileMidx midxTip = MidxTestUtils.writeMultipackIndex(db,
 				Arrays.copyOfRange(packs, 0, 2), midxMid);
 
 		try (DfsReader ctx = db.getObjectDatabase().newReader()) {
@@ -120,6 +120,49 @@ public void midx_findIdxPosition_withBase() throws IOException {
 	}
 
 	@Test
+	public void midx_getObjectAt() throws IOException {
+		ObjectId o1 = writePackWithBlob("something".getBytes(UTF_8));
+		ObjectId o2 = writePackWithBlob("something else".getBytes(UTF_8));
+		ObjectId o3 = writePackWithBlob("and more".getBytes(UTF_8));
+		DfsPackFileMidx midx = writeMultipackIndex();
+
+		try (DfsReader ctx = db.getObjectDatabase().newReader()) {
+			assertEquals(o1, midx.getObjectAt(ctx, 2));
+			assertEquals(o2, midx.getObjectAt(ctx, 0));
+			assertEquals(o3, midx.getObjectAt(ctx, 1));
+		}
+	}
+
+	@Test
+	public void midx_getObjectAt_withBase() throws IOException {
+		ObjectId o1 = writePackWithBlob("o1".getBytes(UTF_8));
+		ObjectId o2 = writePackWithBlob("o2".getBytes(UTF_8));
+		ObjectId o3 = writePackWithBlob("o3".getBytes(UTF_8));
+		ObjectId o4 = writePackWithBlob("o4".getBytes(UTF_8));
+		ObjectId o5 = writePackWithBlob("o5".getBytes(UTF_8));
+		ObjectId o6 = writePackWithBlob("o6".getBytes(UTF_8));
+		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
+
+		// Packs are in reverse insertion order
+		DfsPackFileMidx midxBase = MidxTestUtils.writeMultipackIndex(db,
+				Arrays.copyOfRange(packs, 4, 6), null);
+		DfsPackFileMidx midxMid = MidxTestUtils.writeMultipackIndex(db,
+				Arrays.copyOfRange(packs, 2, 4), midxBase);
+		DfsPackFileMidx midxTip = MidxTestUtils.writeMultipackIndex(db,
+				Arrays.copyOfRange(packs, 0, 2), midxMid);
+
+		try (DfsReader ctx = db.getObjectDatabase().newReader()) {
+			assertEquals(o1, midxTip.getObjectAt(ctx, 0));
+			assertEquals(o2, midxTip.getObjectAt(ctx, 1));
+			assertEquals(o3, midxTip.getObjectAt(ctx, 2));
+			assertEquals(o4, midxTip.getObjectAt(ctx, 3));
+			// In sha1 order
+			assertEquals(o5, midxTip.getObjectAt(ctx, 5));
+			assertEquals(o6, midxTip.getObjectAt(ctx, 4));
+		}
+	}
+
+	@Test
 	public void midx_hasObject() throws IOException {
 		ObjectId o1 = writePackWithRandomBlob(100);
 		ObjectId o2 = writePackWithRandomBlob(200);
@@ -146,9 +189,9 @@ public void midx_hasObject_withBase() throws IOException {
 		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
 
 		// Packs are in reverse insertion order
-		DfsPackFileMidx midxBase = writeMultipackIndex(
+		DfsPackFileMidx midxBase = MidxTestUtils.writeMultipackIndex(db,
 				Arrays.copyOfRange(packs, 3, 6), null);
-		DfsPackFileMidx midxTip = writeMultipackIndex(
+		DfsPackFileMidx midxTip = MidxTestUtils.writeMultipackIndex(db,
 				Arrays.copyOfRange(packs, 0, 3), midxBase);
 
 		try (DfsReader ctx = db.getObjectDatabase().newReader()) {
@@ -210,9 +253,9 @@ public void midx_get_withBase() throws IOException {
 
 		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
 		// Packs are in reverse insertion order
-		DfsPackFileMidx midxBase = writeMultipackIndex(
+		DfsPackFileMidx midxBase = MidxTestUtils.writeMultipackIndex(db,
 				Arrays.copyOfRange(packs, 3, 6), null);
-		DfsPackFileMidx midxTip = writeMultipackIndex(
+		DfsPackFileMidx midxTip = MidxTestUtils.writeMultipackIndex(db,
 				Arrays.copyOfRange(packs, 0, 3), midxBase);
 
 		try (DfsReader ctx = db.getObjectDatabase().newReader()) {
@@ -277,9 +320,9 @@ public void midx_load_withBase() throws IOException {
 
 		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
 		// Packs are in reverse insertion order
-		DfsPackFileMidx midxBase = writeMultipackIndex(
+		DfsPackFileMidx midxBase = MidxTestUtils.writeMultipackIndex(db,
 				Arrays.copyOfRange(packs, 3, 6), null);
-		DfsPackFileMidx midxTip = writeMultipackIndex(
+		DfsPackFileMidx midxTip = MidxTestUtils.writeMultipackIndex(db,
 				Arrays.copyOfRange(packs, 0, 3), midxBase);
 
 		try (DfsReader ctx = db.getObjectDatabase().newReader()) {
@@ -376,9 +419,9 @@ public void midx_resolve_withBase() throws Exception {
 
 		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
 		// Packs are in reverse insertion order
-		DfsPackFileMidx midxBase = writeMultipackIndex(
+		DfsPackFileMidx midxBase = MidxTestUtils.writeMultipackIndex(db,
 				Arrays.copyOfRange(packs, 3, 6), null);
-		DfsPackFileMidx midxTip = writeMultipackIndex(
+		DfsPackFileMidx midxTip = MidxTestUtils.writeMultipackIndex(db,
 				Arrays.copyOfRange(packs, 0, 3), midxBase);
 
 		try (DfsReader ctx = db.getObjectDatabase().newReader()) {
@@ -446,9 +489,9 @@ public void midx_findAllFromPack_withBase() throws Exception {
 
 		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
 		// Packs are in reverse insertion order (o6 -> o1)
-		DfsPackFileMidx midxBase = writeMultipackIndex(
+		DfsPackFileMidx midxBase = MidxTestUtils.writeMultipackIndex(db,
 				Arrays.copyOfRange(packs, 3, 6), null);
-		DfsPackFileMidx midxTip = writeMultipackIndex(
+		DfsPackFileMidx midxTip = MidxTestUtils.writeMultipackIndex(db,
 				Arrays.copyOfRange(packs, 0, 3), midxBase);
 
 		List<ObjectToPack> otps = List.of(new DfsObjectToPack(o1, OBJ_BLOB),
@@ -524,9 +567,9 @@ public void midx_copyPackAsIs_withBase() throws Exception {
 				.map(size -> size - 12 - 20) // remove header + CRC
 				.sum();
 
-		DfsPackFileMidx midxBase = writeMultipackIndex(
+		DfsPackFileMidx midxBase = MidxTestUtils.writeMultipackIndex(db,
 				Arrays.copyOfRange(packs, 3, 6), null);
-		DfsPackFileMidx midxTip = writeMultipackIndex(
+		DfsPackFileMidx midxTip = MidxTestUtils.writeMultipackIndex(db,
 				Arrays.copyOfRange(packs, 0, 3), midxBase);
 
 		try (DfsReader ctx = db.getObjectDatabase().newReader();
@@ -561,9 +604,9 @@ public void midx_copyAsIs_withBase() throws Exception {
 
 		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
 		// Packs are in reverse insertion order
-		DfsPackFileMidx midxBase = writeMultipackIndex(
+		DfsPackFileMidx midxBase = MidxTestUtils.writeMultipackIndex(db,
 				Arrays.copyOfRange(packs, 3, 6), null);
-		DfsPackFileMidx midxTip = writeMultipackIndex(
+		DfsPackFileMidx midxTip = MidxTestUtils.writeMultipackIndex(db,
 				Arrays.copyOfRange(packs, 0, 3), midxBase);
 
 		assertEquals(213, copyAsIs(midxTip, baseObject).length);
@@ -626,16 +669,15 @@ public void midx_getObjectType_withBase() throws Exception {
 		ObjectId commit = writePackWithCommit();
 		ObjectId blob = writePackWithRandomBlob(200);
 		writePackWithCommit();
-
 		writePackWithCommit();
 		writePackWithRandomBlob(300);
 		ObjectId newCommit = writePackWithCommit();
 
 		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
 		// Packs are in reverse insertion order
-		DfsPackFileMidx midxBase = writeMultipackIndex(
+		DfsPackFileMidx midxBase = MidxTestUtils.writeMultipackIndex(db,
 				Arrays.copyOfRange(packs, 4, 7), null);
-		DfsPackFileMidx midxTip = writeMultipackIndex(
+		DfsPackFileMidx midxTip = MidxTestUtils.writeMultipackIndex(db,
 				Arrays.copyOfRange(packs, 0, 4), midxBase);
 
 		try (RevWalk rw = new RevWalk(db);
@@ -687,14 +729,12 @@ public void midx_getObjectSize_byId_withBase() throws Exception {
 
 		writePackWithRandomBlob(300);
 		ObjectId blobTwo = writePackWithRandomBlob(100);
-		System.out.println(
-				"pack count: " + db.getObjectDatabase().getPacks().length);
 
 		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
 		// Packs are in reverse insertion order
-		DfsPackFileMidx midxBase = writeMultipackIndex(
+		DfsPackFileMidx midxBase = MidxTestUtils.writeMultipackIndex(db,
 				Arrays.copyOfRange(packs, 3, 5), null);
-		DfsPackFileMidx midxTip = writeMultipackIndex(
+		DfsPackFileMidx midxTip = MidxTestUtils.writeMultipackIndex(db,
 				Arrays.copyOfRange(packs, 0, 3), midxBase);
 
 		try (RevWalk rw = new RevWalk(db);
@@ -744,9 +784,9 @@ public void midx_getObjectSize_byOffset_withBase() throws Exception {
 
 		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
 		// Packs are in reverse insertion order
-		DfsPackFileMidx midxBase = writeMultipackIndex(
+		DfsPackFileMidx midxBase = MidxTestUtils.writeMultipackIndex(db,
 				Arrays.copyOfRange(packs, 3, 5), null);
-		DfsPackFileMidx midxTip = writeMultipackIndex(
+		DfsPackFileMidx midxTip = MidxTestUtils.writeMultipackIndex(db,
 				Arrays.copyOfRange(packs, 0, 3), midxBase);
 
 		try (RevWalk rw = new RevWalk(db);
@@ -815,9 +855,9 @@ public void midx_fillRepresentation_withBase() throws Exception {
 
 		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
 		assertEquals(6, packs.length);
-		DfsPackFileMidx midxBase = writeMultipackIndex(
+		DfsPackFileMidx midxBase = MidxTestUtils.writeMultipackIndex(db,
 				Arrays.copyOfRange(packs, 3, 6), null);
-		DfsPackFileMidx midxTip = writeMultipackIndex(
+		DfsPackFileMidx midxTip = MidxTestUtils.writeMultipackIndex(db,
 				Arrays.copyOfRange(packs, 0, 3), midxBase);
 
 		try (DfsReader ctx = db.getObjectDatabase().newReader()) {
@@ -827,7 +867,7 @@ public void midx_fillRepresentation_withBase() throws Exception {
 			assertEquals(midxTip.getPackDescription(),
 					rep.pack.getPackDescription());
 			assertEquals(midxTip.findOffset(ctx, commitInTip), rep.offset);
-			assertEquals(150, rep.length);
+			assertEquals(151, rep.length);
 
 			// Commit in base midx
 			rep = fillRepresentation(midxTip, commitInBase, OBJ_COMMIT);
@@ -846,7 +886,7 @@ public void midx_fillRepresentation_withBase() throws Exception {
 	}
 
 	@Test
-	public void midx_getBitmapIndex() throws Exception {
+	public void midx_getBitmapIndex_gc() throws Exception {
 		RevCommit c1 = writePackWithCommit();
 		RevCommit c2 = writePackWithCommit();
 		gcWithBitmaps();
@@ -865,6 +905,32 @@ public void midx_getBitmapIndex() throws Exception {
 	}
 
 	@Test
+	public void midx_getBitmapIndex_midx() throws Exception {
+		RevCommit c1 = writePackWithCommit();
+		RevCommit c2 = writePackWithCommit();
+		gcWithBitmaps();
+
+		RevCommit c3 = writePackWithCommit();
+		DfsPackFileMidx dfsPackFileMidx = writeMultipackIndexWithBitmaps();
+		try (DfsReader ctx = db.getObjectDatabase().newReader()) {
+			ctx.getOptions().setUseMidxBitmaps(true);
+			PackBitmapIndex bitmapIndex = dfsPackFileMidx.getBitmapIndex(ctx);
+			assertNotNull(bitmapIndex);
+			assertEquals(3, bitmapIndex.getBitmapCount());
+			// Both commits have same tree and blob
+			assertEquals(5, bitmapIndex.getObjectCount());
+
+			assertNotNull(bitmapIndex.getBitmap(c3));
+			assertNotNull(bitmapIndex.getBitmap(c2));
+			assertNotNull(bitmapIndex.getBitmap(c1));
+
+			EWAHCompressedBitmap bitmapC3 = bitmapIndex.getBitmap(c3);
+			EWAHCompressedBitmap bitmapC2 = bitmapIndex.getBitmap(c2);
+			assertEquals(1, bitmapC3.andNot(bitmapC2).cardinality());
+		}
+	}
+
+	@Test
 	public void midx_getAllCoveredPacks() throws Exception {
 		writePackWithCommit();
 		writePackWithRandomBlob(300);
@@ -872,11 +938,12 @@ public void midx_getAllCoveredPacks() throws Exception {
 
 		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
 		assertEquals(4, packs.length);
-		DfsPackFileMidx midx = writeMultipackIndex(packs, null);
+		DfsPackFileMidx midx = MidxTestUtils.writeMultipackIndex(db, packs,
+				null);
 
 		assertEquals(4, midx.getAllCoveredPacks().size());
 		List<DfsPackDescription> expected = Arrays.stream(packs)
-				.map(p -> p.getPackDescription()).toList();
+				.map(DfsPackFile::getPackDescription).toList();
 		List<DfsPackDescription> actual = midx.getAllCoveredPacks().stream()
 				.map(DfsPackFile::getPackDescription).toList();
 		assertEquals(expected, actual);
@@ -892,11 +959,11 @@ public void midx_getAllCoveredPacks_withBase() throws Exception {
 
 		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
 		assertEquals(6, packs.length);
-		DfsPackFileMidx midxBase = writeMultipackIndex(
+		DfsPackFileMidx midxBase = MidxTestUtils.writeMultipackIndex(db,
 				Arrays.copyOfRange(packs, 4, 6), null);
-		DfsPackFileMidx midxMiddle = writeMultipackIndex(
+		DfsPackFileMidx midxMiddle = MidxTestUtils.writeMultipackIndex(db,
 				Arrays.copyOfRange(packs, 2, 4), midxBase);
-		DfsPackFileMidx midxTip = writeMultipackIndex(
+		DfsPackFileMidx midxTip = MidxTestUtils.writeMultipackIndex(db,
 				Arrays.copyOfRange(packs, 0, 2), midxMiddle);
 
 		assertEquals(6, midxTip.getAllCoveredPacks().size());
@@ -917,9 +984,9 @@ public void midx_getCoveredPacks_withBase_onlyTopMidx() throws Exception {
 
 		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
 		assertEquals(6, packs.length);
-		DfsPackFileMidx midxBase = writeMultipackIndex(
+		DfsPackFileMidx midxBase = MidxTestUtils.writeMultipackIndex(db,
 				Arrays.copyOfRange(packs, 3, 6), null);
-		DfsPackFileMidx midxTip = writeMultipackIndex(
+		DfsPackFileMidx midxTip = MidxTestUtils.writeMultipackIndex(db,
 				Arrays.copyOfRange(packs, 0, 3), midxBase);
 
 		assertEquals(3, midxTip.getCoveredPacks().size());
@@ -977,6 +1044,24 @@ public void packwriter_via_midx() throws Exception {
 	}
 
 	@Test
+	public void getChecksum() throws Exception {
+		MidxTestUtils.writePackWithBlob(db, "something");
+		MidxTestUtils.writePackWithBlob(db, "something else");
+		MidxTestUtils.writePackWithBlob(db, "and more");
+		DfsPackFileMidx midx = writeMultipackIndex();
+
+		try (DfsReader ctx = db.getObjectDatabase().newReader()) {
+			byte[] checksum = midx.getChecksum(ctx);
+			assertNotNull(checksum);
+			assertEquals(20, checksum.length);
+			assertNotEquals('M', checksum[0]);
+			assertNotEquals('I', checksum[1]);
+			assertNotEquals('D', checksum[2]);
+			assertNotEquals('X', checksum[3]);
+		}
+	}
+
+	@Test
 	public void voffsetcalculator_encode() {
 		DfsPackFile one = createDfsPackFile(800);
 		DfsPackFile two = createDfsPackFile(1200);
@@ -1154,7 +1239,21 @@ private static DfsPackFile createDfsPackFile(int size) {
 	}
 
 	private DfsPackFileMidx writeMultipackIndex() throws IOException {
-		return writeMultipackIndex(db.getObjectDatabase().getPacks(), null);
+		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
+		return MidxTestUtils.writeMultipackIndex(db, packs, null);
+	}
+
+	private DfsPackFileMidx writeMultipackIndexWithBitmaps()
+			throws IOException {
+		enableMidxBitmaps(db);
+		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
+		return MidxTestUtils.writeMultipackIndex(db, packs,
+				null);
+	}
+
+	private static void enableMidxBitmaps(DfsRepository repo) {
+		repo.getConfig().setInt(CONFIG_PACK_SECTION, null,
+				CONFIG_KEY_BITMAP_DISTANT_COMMIT_SPAN, 1);
 	}
 
 	private void gcWithBitmaps() throws IOException {
@@ -1162,39 +1261,15 @@ private void gcWithBitmaps() throws IOException {
 		garbageCollector.pack(NullProgressMonitor.INSTANCE);
 	}
 
-	private DfsPackFileMidx writeMultipackIndex(DfsPackFile[] packs,
-			DfsPackFileMidx base) throws IOException {
-		LinkedHashMap<String, PackIndex> forMidx = new LinkedHashMap<>(
-				packs.length);
-		Map<String, DfsPackDescription> descByName = new HashMap<>(
-				packs.length);
-		try (DfsReader ctx = db.getObjectDatabase().newReader()) {
-			for (DfsPackFile pack : packs) {
-				forMidx.put(pack.getPackDescription().getPackName(),
-						pack.getPackIndex(ctx));
-				descByName.put(pack.getPackDescription().getPackName(),
-						pack.getPackDescription());
-			}
-		}
-		MultiPackIndexWriter w = new MultiPackIndexWriter();
-		DfsPackDescription desc = db.getObjectDatabase().newPack(GC);
-		try (DfsOutputStream out = db.getObjectDatabase().writeFile(desc,
-				PackExt.MULTI_PACK_INDEX)) {
-			MultiPackIndexWriter.Result midxStats = w
-					.write(NullProgressMonitor.INSTANCE, out, forMidx);
-			desc.setCoveredPacks(midxStats.packNames().stream()
-					.map(descByName::get).toList());
-			desc.addFileExt(PackExt.MULTI_PACK_INDEX);
-		}
-		db.getObjectDatabase().commitPack(List.of(desc), null);
-		return DfsPackFileMidx.create(DfsBlockCache.getInstance(), desc,
-				Arrays.asList(packs), base);
-	}
-
 	private RevCommit writePackWithCommit() throws Exception {
 		try (TestRepository<InMemoryRepository> repository = new TestRepository<>(
 				db)) {
-			return repository.branch("/refs/heads/main").commit()
+			Ref ref = repository.getRepository().getRefDatabase()
+					.findRef("refs/heads/main");
+			RevWalk rw = repository.getRevWalk();
+			RevCommit parent = ref != null ? rw.parseCommit(ref.getObjectId())
+					: null;
+			return repository.branch("refs/heads/main").commit().parent(parent)
 					.add("blob1", "blob1").create();
 		}
 	}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidxSingleTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidxSingleTest.java
new file mode 100644
index 0000000..aa2ddca
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidxSingleTest.java
@@ -0,0 +1,1246 @@
+/*
+ * Copyright (C) 2025, Google LLC.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.internal.storage.dfs;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.GC;
+import static org.eclipse.jgit.internal.storage.dfs.MidxTestUtils.writePackWithBlobs;
+import static org.eclipse.jgit.internal.storage.dfs.MidxTestUtils.writeSinglePackMidx;
+import static org.eclipse.jgit.internal.storage.pack.PackExt.PACK;
+import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
+import static org.eclipse.jgit.lib.Constants.OBJ_COMMIT;
+import static org.eclipse.jgit.lib.Constants.OBJ_TREE;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.internal.storage.dfs.DfsPackFileMidx.DfsPackOffset;
+import org.eclipse.jgit.internal.storage.dfs.DfsPackFileMidxSingle.SingleVOffsetCalculator;
+import org.eclipse.jgit.internal.storage.file.PackBitmapIndex;
+import org.eclipse.jgit.internal.storage.midx.MultiPackIndex.PackOffset;
+import org.eclipse.jgit.internal.storage.pack.ObjectToPack;
+import org.eclipse.jgit.internal.storage.pack.PackOutputStream;
+import org.eclipse.jgit.internal.storage.pack.PackWriter;
+import org.eclipse.jgit.junit.JGitTestUtil;
+import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.junit.TestRng;
+import org.eclipse.jgit.lib.NullProgressMonitor;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectInserter;
+import org.eclipse.jgit.lib.ObjectLoader;
+import org.eclipse.jgit.lib.ProgressMonitor;
+import org.eclipse.jgit.revwalk.RevBlob;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevTree;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.storage.pack.PackConfig;
+import org.junit.Before;
+import org.junit.Test;
+
+public class DfsPackFileMidxSingleTest {
+
+	private static final ObjectId NOT_IN_PACK = ObjectId
+			.fromString("3f306cb3fcd5116919fecad615524bd6e6ea4ba7");
+
+	InMemoryRepository db;
+
+	@Before
+	public void setUp() {
+		db = new InMemoryRepository(new DfsRepositoryDescription("test"));
+	}
+
+	@Test
+	public void findIdxPosition() throws IOException {
+		ObjectId[] oids = writePackWithBlobs(db, "something",
+				"something else", "and more");
+		// oids = [a4..., 33..., 64...]
+		DfsPackFileMidx midx = writeSinglePackMidx(db);
+
+		try (DfsReader ctx = db.getObjectDatabase().newReader()) {
+			assertEquals(2, midx.findIdxPosition(ctx, oids[0]));
+			assertEquals(0, midx.findIdxPosition(ctx, oids[1]));
+			assertEquals(1, midx.findIdxPosition(ctx, oids[2]));
+			assertEquals(-1, midx.findIdxPosition(ctx, NOT_IN_PACK));
+		}
+	}
+
+	@Test
+	public void findIdxPosition_withBase() throws IOException {
+		ObjectId o1 = MidxTestUtils.writePackWithBlob(db, "o1"); // 38
+		ObjectId o2 = MidxTestUtils.writePackWithBlob(db, "o2"); // 4a
+		ObjectId o3 = MidxTestUtils.writePackWithBlob(db, "o3"); // 45
+		ObjectId o4 = MidxTestUtils.writePackWithBlob(db, "o4"); // 4b
+		ObjectId o5 = MidxTestUtils.writePackWithBlob(db, "o5"); // 68
+		ObjectId o6 = MidxTestUtils.writePackWithBlob(db, "o6"); // 4d
+		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
+
+		// Packs are in reverse insertion order
+		DfsPackFileMidx midxBase = MidxTestUtils.writeMultipackIndex(db,
+				Arrays.copyOfRange(packs, 3, 6), null);
+		DfsPackFileMidx midxMid = writeSinglePackMidx(db,
+				packs[2], midxBase);
+		DfsPackFileMidx midxTip = MidxTestUtils.writeMultipackIndex(db,
+				Arrays.copyOfRange(packs, 0, 2), midxMid);
+
+		try (DfsReader ctx = db.getObjectDatabase().newReader()) {
+			assertEquals(0, midxTip.findIdxPosition(ctx, o1));
+			assertEquals(1, midxTip.findIdxPosition(ctx, o3));
+			assertEquals(2, midxTip.findIdxPosition(ctx, o2));
+			assertEquals(3, midxTip.findIdxPosition(ctx, o4));
+			assertEquals(4, midxTip.findIdxPosition(ctx, o6));
+			assertEquals(5, midxTip.findIdxPosition(ctx, o5));
+		}
+	}
+
+	@Test
+	public void getObjectAt() throws IOException {
+		ObjectId[] oids = writePackWithBlobs(db, "something",
+				"something else", "and more");
+		// oids = [a4..., 33..., 64...]
+		DfsPackFileMidx midx = writeSinglePackMidx(db);
+
+		try (DfsReader ctx = db.getObjectDatabase().newReader()) {
+			assertEquals(oids[0], midx.getObjectAt(ctx, 2));
+			assertEquals(oids[1], midx.getObjectAt(ctx, 0));
+			assertEquals(oids[2], midx.getObjectAt(ctx, 1));
+		}
+	}
+
+	@Test
+	public void getObjectAt_withBase() throws IOException {
+		ObjectId o1 = MidxTestUtils.writePackWithBlob(db, "o1");
+		ObjectId o2 = MidxTestUtils.writePackWithBlob(db, "o2");
+		ObjectId o3 = MidxTestUtils.writePackWithBlob(db, "o3");
+		ObjectId o4 = MidxTestUtils.writePackWithBlob(db, "o4");
+		ObjectId o5 = MidxTestUtils.writePackWithBlob(db, "o5");
+		ObjectId o6 = MidxTestUtils.writePackWithBlob(db, "o6");
+		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
+
+		// Packs are in reverse insertion order
+		DfsPackFileMidx midxBase = MidxTestUtils.writeMultipackIndex(db,
+				Arrays.copyOfRange(packs, 3, 6), null);
+		DfsPackFileMidx midxMid = writeSinglePackMidx(db,
+				packs[2], midxBase);
+		DfsPackFileMidx midxTip = MidxTestUtils.writeMultipackIndex(db,
+				Arrays.copyOfRange(packs, 0, 2), midxMid);
+
+		try (DfsReader ctx = db.getObjectDatabase().newReader()) {
+			assertEquals(o1, midxTip.getObjectAt(ctx, 0));
+			assertEquals(o3, midxTip.getObjectAt(ctx, 1));
+			assertEquals(o2, midxTip.getObjectAt(ctx, 2));
+			assertEquals(o4, midxTip.getObjectAt(ctx, 3));
+			// In sha1 order
+			assertEquals(o6, midxTip.getObjectAt(ctx, 4));
+			assertEquals(o5, midxTip.getObjectAt(ctx, 5));
+		}
+	}
+
+	@Test
+	public void hasObject() throws IOException {
+		ObjectId[] oids = writePackWithBlobs(db, "aaaa", "bbbb",
+				"cccc");
+		DfsPackFile midx = writeSinglePackMidx(db);
+
+		// DfsPackFile midx = readDfsPackFileMidx();
+		try (DfsReader ctx = db.getObjectDatabase().newReader()) {
+			assertTrue(midx.hasObject(ctx, oids[0]));
+			assertTrue(midx.hasObject(ctx, oids[1]));
+			assertTrue(midx.hasObject(ctx, oids[2]));
+			assertFalse(midx.hasObject(ctx, NOT_IN_PACK));
+		}
+	}
+
+	@Test
+	public void hasObject_withBase() throws IOException {
+		ObjectId o1 = writePackWithRandomBlob(100);
+		ObjectId o2 = writePackWithRandomBlob(200);
+		ObjectId o3 = writePackWithRandomBlob(150);
+		ObjectId o4 = writePackWithRandomBlob(400);
+		ObjectId o5 = writePackWithRandomBlob(500);
+		ObjectId o6 = writePackWithRandomBlob(600);
+		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
+
+		// Packs are in reverse insertion order
+		DfsPackFileMidx midxBase = MidxTestUtils.writeMultipackIndex(db,
+				Arrays.copyOfRange(packs, 1, 6), null);
+		DfsPackFileMidx midxTip = writeSinglePackMidx(db,
+				packs[0], midxBase);
+
+		try (DfsReader ctx = db.getObjectDatabase().newReader()) {
+			assertTrue(midxBase.hasObject(ctx, o1));
+			assertTrue(midxBase.hasObject(ctx, o2));
+			assertTrue(midxBase.hasObject(ctx, o3));
+			assertTrue(midxBase.hasObject(ctx, o4));
+			assertTrue(midxBase.hasObject(ctx, o5));
+			// This is not in base
+			assertFalse(midxBase.hasObject(ctx, o6));
+
+			// Top midx has all objects
+			assertTrue(midxTip.hasObject(ctx, o1));
+			assertTrue(midxTip.hasObject(ctx, o2));
+			assertTrue(midxTip.hasObject(ctx, o3));
+			assertTrue(midxTip.hasObject(ctx, o4));
+			assertTrue(midxTip.hasObject(ctx, o5));
+			assertTrue(midxTip.hasObject(ctx, o6));
+
+			assertFalse(midxTip.hasObject(ctx, NOT_IN_PACK));
+		}
+	}
+
+	@Test
+	public void get() throws IOException {
+		byte[] contentOne = "ONE".getBytes(UTF_8);
+		byte[] contentTwo = "TWO".getBytes(UTF_8);
+		byte[] contentThree = "THREE".getBytes(UTF_8);
+
+		ObjectId[] oids = writePackWithBlobs(db, "ONE", "TWO",
+				"THREE");
+		DfsPackFile midx = writeSinglePackMidx(db);
+
+		try (DfsReader ctx = db.getObjectDatabase().newReader()) {
+			ObjectLoader objectLoader = midx.get(ctx, oids[0]);
+			assertArrayEquals(contentOne, safeGetBytes(objectLoader));
+			objectLoader = midx.get(ctx, oids[1]);
+			assertArrayEquals(contentTwo, safeGetBytes(objectLoader));
+			objectLoader = midx.get(ctx, oids[2]);
+			assertArrayEquals(contentThree, safeGetBytes(objectLoader));
+			assertNull(midx.get(ctx, NOT_IN_PACK));
+		}
+	}
+
+	@Test
+	public void get_withBase() throws IOException {
+		byte[] contentOne = "ONE".getBytes(UTF_8);
+		byte[] contentTwo = "TWO".getBytes(UTF_8);
+		byte[] contentThree = "THREE".getBytes(UTF_8);
+		byte[] contentFour = "FOUR".getBytes(UTF_8);
+		byte[] contentFive = "FIVE".getBytes(UTF_8);
+		byte[] contentSix = "SIX".getBytes(UTF_8);
+
+		ObjectId o1 = writePackWithBlob(contentOne);
+		ObjectId o2 = writePackWithBlob(contentTwo);
+		ObjectId o3 = writePackWithBlob(contentThree);
+		ObjectId o4 = writePackWithBlob(contentFour);
+		ObjectId o5 = writePackWithBlob(contentFive);
+		ObjectId o6 = writePackWithBlob(contentSix);
+
+		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
+		// Packs are in reverse insertion order
+		DfsPackFileMidx midxBase = MidxTestUtils.writeMultipackIndex(db,
+				Arrays.copyOfRange(packs, 1, 6), null);
+		DfsPackFileMidx midxTip = writeSinglePackMidx(db,
+				packs[0], midxBase);
+
+		try (DfsReader ctx = db.getObjectDatabase().newReader()) {
+			ObjectLoader objectLoader = midxTip.get(ctx, o1);
+			assertArrayEquals(contentOne, safeGetBytes(objectLoader));
+			objectLoader = midxTip.get(ctx, o2);
+			assertArrayEquals(contentTwo, safeGetBytes(objectLoader));
+			objectLoader = midxTip.get(ctx, o3);
+			assertArrayEquals(contentThree, safeGetBytes(objectLoader));
+			objectLoader = midxTip.get(ctx, o4);
+			assertArrayEquals(contentFour, safeGetBytes(objectLoader));
+			objectLoader = midxTip.get(ctx, o5);
+			assertArrayEquals(contentFive, safeGetBytes(objectLoader));
+			objectLoader = midxTip.get(ctx, o6);
+			assertArrayEquals(contentSix, safeGetBytes(objectLoader));
+
+			assertNull(midxTip.get(ctx, NOT_IN_PACK));
+		}
+	}
+
+	@Test
+	public void load() throws IOException {
+		byte[] contentOne = "ONE".getBytes(UTF_8);
+		byte[] contentTwo = "TWO".getBytes(UTF_8);
+		byte[] contentThree = "THREE".getBytes(UTF_8);
+
+		ObjectId[] oids = writePackWithBlobs(db, "ONE", "TWO",
+				"THREE");
+		DfsPackFile midx = writeSinglePackMidx(db);
+
+		try (DfsReader ctx = db.getObjectDatabase().newReader()) {
+			ObjectLoader objectLoader = midx.load(ctx,
+					midx.findOffset(ctx, oids[0]));
+			assertArrayEquals(contentOne, safeGetBytes(objectLoader));
+			objectLoader = midx.load(ctx, midx.findOffset(ctx, oids[1]));
+			assertArrayEquals(contentTwo, safeGetBytes(objectLoader));
+			objectLoader = midx.load(ctx, midx.findOffset(ctx, oids[2]));
+			assertArrayEquals(contentThree, safeGetBytes(objectLoader));
+
+			assertThrows(IllegalArgumentException.class,
+					() -> midx.load(ctx, 500));
+			assertNull(midx.load(ctx, -1));
+		}
+	}
+
+	@Test
+	public void load_withBase() throws IOException {
+		byte[] contentOne = "ONE".getBytes(UTF_8);
+		byte[] contentTwo = "TWO".getBytes(UTF_8);
+		byte[] contentThree = "THREE".getBytes(UTF_8);
+		byte[] contentFour = "FOUR".getBytes(UTF_8);
+		byte[] contentFive = "FIVE".getBytes(UTF_8);
+		byte[] contentSix = "SIX".getBytes(UTF_8);
+
+		ObjectId o1 = writePackWithBlob(contentOne);
+		ObjectId o2 = writePackWithBlob(contentTwo);
+		ObjectId o3 = writePackWithBlob(contentThree);
+		ObjectId o4 = writePackWithBlob(contentFour);
+		ObjectId o5 = writePackWithBlob(contentFive);
+		ObjectId o6 = writePackWithBlob(contentSix);
+
+		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
+		// Packs are in reverse insertion order
+		DfsPackFileMidx midxBase = MidxTestUtils.writeMultipackIndex(db,
+				Arrays.copyOfRange(packs, 1, 6), null);
+		DfsPackFileMidx midxTip = writeSinglePackMidx(db,
+				packs[0], midxBase);
+
+		try (DfsReader ctx = db.getObjectDatabase().newReader()) {
+			ObjectLoader objectLoader = midxTip.load(ctx,
+					midxTip.findOffset(ctx, o1));
+			assertArrayEquals(contentOne, safeGetBytes(objectLoader));
+			objectLoader = midxTip.load(ctx, midxTip.findOffset(ctx, o2));
+			assertArrayEquals(contentTwo, safeGetBytes(objectLoader));
+			objectLoader = midxTip.load(ctx, midxTip.findOffset(ctx, o3));
+			assertArrayEquals(contentThree, safeGetBytes(objectLoader));
+			objectLoader = midxTip.load(ctx, midxTip.findOffset(ctx, o4));
+			assertArrayEquals(contentFour, safeGetBytes(objectLoader));
+			objectLoader = midxTip.load(ctx, midxTip.findOffset(ctx, o5));
+			assertArrayEquals(contentFive, safeGetBytes(objectLoader));
+			objectLoader = midxTip.load(ctx, midxTip.findOffset(ctx, o6));
+			assertArrayEquals(contentSix, safeGetBytes(objectLoader));
+
+			assertNull(midxTip.load(ctx, midxTip.findOffset(ctx, NOT_IN_PACK)));
+		}
+	}
+
+	@Test
+	public void findOffset() throws IOException {
+		ObjectId[] oids = writePackWithBlobs(db, "ONE", "TWO",
+				"THREE");
+		DfsPackFileMidx midx = writeSinglePackMidx(db);
+		DfsPackFile realPack = findPack(oids[0]);
+
+		try (DfsReader ctx = db.getObjectDatabase().newReader()) {
+			assertEquals(realPack.findOffset(ctx, oids[0]),
+					midx.findOffset(ctx, oids[0]));
+			assertEquals(realPack.findOffset(ctx, oids[1]),
+					midx.findOffset(ctx, oids[1]));
+			assertEquals(realPack.findOffset(ctx, oids[2]),
+					midx.findOffset(ctx, oids[2]));
+
+			long posNon = midx.findOffset(ctx, NOT_IN_PACK);
+			assertEquals(-1, posNon);
+		}
+	}
+
+	@Test
+	public void findOffset_withBase() throws IOException {
+		byte[] contentOne = "ONE".getBytes(UTF_8);
+		byte[] contentTwo = "TWO".getBytes(UTF_8);
+		byte[] contentThree = "THREE".getBytes(UTF_8);
+		byte[] contentFour = "FOUR".getBytes(UTF_8);
+		byte[] contentFive = "FIVE".getBytes(UTF_8);
+		byte[] contentSix = "SIX".getBytes(UTF_8);
+
+		ObjectId o1 = writePackWithBlob(contentOne);
+		ObjectId o2 = writePackWithBlob(contentTwo);
+		ObjectId o3 = writePackWithBlob(contentThree);
+		ObjectId o4 = writePackWithBlob(contentFour);
+		ObjectId o5 = writePackWithBlob(contentFive);
+		ObjectId o6 = writePackWithBlob(contentSix);
+
+		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
+		// Packs are in reverse insertion order
+		DfsPackFileMidx midxBase = MidxTestUtils.writeMultipackIndex(db,
+				Arrays.copyOfRange(packs, 1, 6), null);
+		DfsPackFileMidx midxTip = writeSinglePackMidx(db,
+				packs[0], midxBase);
+		DfsPackFile coveredPack = findPack(o6);
+
+		try (DfsReader ctx = db.getObjectDatabase().newReader()) {
+			assertEquals(coveredPack.findOffset(ctx, o6) + midxBase.length,
+					midxTip.findOffset(ctx, o6));
+			assertEquals(findPack(o5).findOffset(ctx, o5),
+					midxTip.findOffset(ctx, o5));
+
+			// WE just check the offsets are in incremental order.
+			// midx orders first by pack, and we passed the most recent first,
+			// so in midx-offset order, o6 > o1 > o2 > o3 > o4 > o5
+			assertTrue(
+					midxTip.findOffset(ctx, o4) > midxTip.findOffset(ctx, o5));
+			assertTrue(
+					midxTip.findOffset(ctx, o3) > midxTip.findOffset(ctx, o4));
+
+			assertTrue(
+					midxTip.findOffset(ctx, o2) > midxTip.findOffset(ctx, o3));
+
+			assertTrue(
+					midxTip.findOffset(ctx, o1) > midxTip.findOffset(ctx, o2));
+			assertTrue(
+					midxTip.findOffset(ctx, o6) > midxTip.findOffset(ctx, o1));
+
+			long posNon = midxTip.findOffset(ctx, NOT_IN_PACK);
+			assertEquals(-1, posNon);
+		}
+	}
+
+	@Test
+	public void resolve() throws Exception {
+		// These oids do NOT have same prefix
+		ObjectId[] oids = writePackWithBlobs(db, "AAAAAA",
+				"BBBBBB", "CCCCCCC");
+		DfsPackFile midx = writeSinglePackMidx(db);
+
+		try (DfsReader ctx = db.getObjectDatabase().newReader()) {
+			Set<ObjectId> matches = new HashSet<>();
+			midx.resolve(ctx, matches, oids[0].abbreviate(6), 100);
+			assertEquals(1, matches.size());
+
+			matches.clear();
+			midx.resolve(ctx, matches, oids[1].abbreviate(6), 100);
+			assertEquals(1, matches.size());
+
+			matches = new HashSet<>();
+			midx.resolve(ctx, matches, NOT_IN_PACK.abbreviate(8), 100);
+			assertEquals(0, matches.size());
+		}
+	}
+
+	@Test
+	public void resolve_withBase() throws Exception {
+		ObjectId o1 = writePackWithRandomBlob(100);
+		ObjectId o2 = writePackWithRandomBlob(200);
+		writePackWithRandomBlob(150);
+		ObjectId o4 = writePackWithRandomBlob(400);
+		writePackWithRandomBlob(500);
+		writePackWithRandomBlob(600);
+
+		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
+		// Packs are in reverse insertion order
+		DfsPackFileMidx midxBase = MidxTestUtils.writeMultipackIndex(db,
+				Arrays.copyOfRange(packs, 1, 6), null);
+		DfsPackFileMidx midxTip = writeSinglePackMidx(db,
+				packs[0], midxBase);
+
+		try (DfsReader ctx = db.getObjectDatabase().newReader()) {
+			Set<ObjectId> matches = new HashSet<>();
+			// Test with an ID that exists in the base
+			assertTrue(midxTip.hasObject(ctx, o1));
+			midxTip.resolve(ctx, matches, o1.abbreviate(6), 100);
+			assertEquals(1, matches.size());
+			assertTrue(matches.contains(o1));
+
+			matches.clear();
+			// Test with an ID that exists in the tip
+			midxTip.resolve(ctx, matches, o4.abbreviate(6), 100);
+			assertTrue(matches.contains(o4));
+			assertEquals(1, matches.size());
+
+			matches.clear();
+			midxTip.resolve(ctx, matches, o2.abbreviate(6), 1);
+			assertTrue(matches.contains(o2));
+			assertEquals(1, matches.size());
+
+			matches.clear();
+			midxTip.resolve(ctx, matches, NOT_IN_PACK.abbreviate(8), 100);
+			assertEquals(0, matches.size());
+		}
+	}
+
+	@Test
+	public void findAllFromPack() throws Exception {
+		ObjectId[] objectIds = writePackWithBlobs(db, "aaaaaaaa",
+				"bbbbbbbbb", "cccccccccc");
+		DfsPackFile midx = writeMultipackIndex();
+
+		List<ObjectToPack> otps = List.of(
+				new DfsObjectToPack(objectIds[0], OBJ_BLOB),
+				new DfsObjectToPack(objectIds[1], OBJ_BLOB),
+				new DfsObjectToPack(objectIds[2], OBJ_BLOB),
+				new DfsObjectToPack(NOT_IN_PACK, OBJ_BLOB));
+
+		try (DfsReader ctx = db.getObjectDatabase().newReader()) {
+			List<DfsObjectToPack> allFromPack = midx.findAllFromPack(ctx, otps,
+					true);
+			assertEquals(3, allFromPack.size());
+
+			DfsObjectToPack oneToPack = allFromPack.get(0);
+			assertEquals(midx.findOffset(ctx, objectIds[0]),
+					oneToPack.getOffset());
+
+			DfsObjectToPack twoToPack = allFromPack.get(1);
+			assertEquals(midx.findOffset(ctx, objectIds[1]),
+					twoToPack.getOffset());
+
+			DfsObjectToPack threeToPack = allFromPack.get(2);
+			assertEquals(midx.findOffset(ctx, objectIds[2]),
+					threeToPack.getOffset());
+		}
+	}
+
+	@Test
+	public void findAllFromPack_withBase() throws Exception {
+		ObjectId o1 = writePackWithRandomBlob(100);
+		ObjectId o2 = writePackWithRandomBlob(200);
+		ObjectId o3 = writePackWithRandomBlob(150);
+		ObjectId o4 = writePackWithRandomBlob(400);
+		ObjectId o5 = writePackWithRandomBlob(500);
+		ObjectId o6 = writePackWithRandomBlob(600);
+
+		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
+		// Packs are in reverse insertion order (o6 -> o1)
+		DfsPackFileMidx midxBase = MidxTestUtils.writeMultipackIndex(db,
+				Arrays.copyOfRange(packs, 1, 6), null);
+		DfsPackFileMidx midxTip = writeSinglePackMidx(db,
+				packs[0], midxBase);
+
+		List<ObjectToPack> otps = List.of(new DfsObjectToPack(o1, OBJ_BLOB),
+				new DfsObjectToPack(o4, OBJ_BLOB),
+				new DfsObjectToPack(o2, OBJ_BLOB),
+				new DfsObjectToPack(o5, OBJ_BLOB),
+				new DfsObjectToPack(NOT_IN_PACK, OBJ_BLOB),
+				new DfsObjectToPack(o3, OBJ_BLOB),
+				new DfsObjectToPack(o6, OBJ_BLOB));
+
+		try (DfsReader ctx = db.getObjectDatabase().newReader()) {
+			List<DfsObjectToPack> allFromPack = midxTip.findAllFromPack(ctx,
+					otps, true);
+			assertEquals(6, allFromPack.size());
+
+			// Objects are in midx-offset order which is:
+			// base(o5< o4 < o3 < o2 < o1) -> tip (06)
+			DfsObjectToPack oneToPack = allFromPack.get(0);
+			assertEquals(midxTip.findOffset(ctx, o5), oneToPack.getOffset());
+
+			DfsObjectToPack twoToPack = allFromPack.get(1);
+			assertEquals(midxTip.findOffset(ctx, o4), twoToPack.getOffset());
+
+			DfsObjectToPack threeToPack = allFromPack.get(2);
+			assertEquals(midxTip.findOffset(ctx, o3), threeToPack.getOffset());
+
+			DfsObjectToPack fourToPack = allFromPack.get(3);
+			assertEquals(midxTip.findOffset(ctx, o2), fourToPack.getOffset());
+
+			DfsObjectToPack fiveToPack = allFromPack.get(4);
+			assertEquals(midxTip.findOffset(ctx, o1), fiveToPack.getOffset());
+
+			DfsObjectToPack sixToPack = allFromPack.get(5);
+			assertEquals(midxTip.findOffset(ctx, o6), sixToPack.getOffset());
+		}
+	}
+
+	@Test
+	public void copyPackAsIs() throws Exception {
+		ObjectId[] objectIds = writePackWithBlobs(db, "aaaaaa",
+				"bbbbbbbb", "ccccccccc");
+		DfsPackFileMidx midx = writeSinglePackMidx(db);
+		DfsPackFile pack = findPack(objectIds[0]);
+		assertArrayEquals(copyPackAsIs(pack), copyPackAsIs(midx));
+	}
+
+	@Test
+	public void copyPackAsIs_withBase() throws Exception {
+		writePackWithRandomBlob(100);
+		writePackWithRandomBlob(200);
+		writePackWithRandomBlob(150);
+		writePackWithRandomBlob(400);
+		writePackWithRandomBlob(500);
+		writePackWithRandomBlob(600);
+
+		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
+		long expectedPackSize = Arrays.stream(packs)
+				.mapToLong(pack -> pack.getPackDescription().getFileSize(PACK))
+				.map(size -> size - 12 - 20) // remove header + CRC
+				.sum();
+
+		DfsPackFileMidx midxBase = MidxTestUtils.writeMultipackIndex(db,
+				Arrays.copyOfRange(packs, 1, 6), null);
+		DfsPackFileMidx midxTip = writeSinglePackMidx(db,
+				packs[0], midxBase);
+
+		try (DfsReader ctx = db.getObjectDatabase().newReader();
+				PackWriter pw = new PackWriter(new PackConfig(), ctx);
+				ByteArrayOutputStream os = new ByteArrayOutputStream();
+				PackOutputStream out = new PackOutputStream(
+						NullProgressMonitor.INSTANCE, os, pw)) {
+			midxTip.copyPackAsIs(out, ctx);
+			out.flush();
+			assertEquals(expectedPackSize, os.size());
+		}
+	}
+
+	private byte[] copyPackAsIs(DfsPackFile source) throws IOException {
+		try (DfsReader ctx = db.getObjectDatabase().newReader();
+				PackWriter pw = new PackWriter(new PackConfig(), ctx)) {
+			ByteArrayOutputStream os = new ByteArrayOutputStream();
+			PackOutputStream out = new PackOutputStream(
+					NullProgressMonitor.INSTANCE, os, pw);
+			source.copyPackAsIs(out, ctx);
+			out.flush();
+			return os.toByteArray();
+		}
+	}
+
+	@Test
+	public void copyAsIs() throws Exception {
+		ObjectId blob = writePackWithRandomBlob(200);
+		DfsPackFileMidx midx = writeSinglePackMidx(db);
+
+		assertEquals(213, copyAsIs(midx, blob).length);
+	}
+
+	@Test
+	public void copyAsIs_withBase() throws Exception {
+		writePackWithRandomBlob(100);
+		ObjectId baseObject = writePackWithRandomBlob(200);
+		writePackWithRandomBlob(150);
+		writePackWithRandomBlob(400);
+		MidxTestUtils.writePackWithBlob(db, "woohooABCxxxxx11111");
+		ObjectId tipObject = writePackWithRandomBlob(600);
+
+		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
+		// Packs are in reverse insertion order
+		DfsPackFileMidx midxBase = MidxTestUtils.writeMultipackIndex(db,
+				Arrays.copyOfRange(packs, 1, 6), null);
+		DfsPackFileMidx midxTip = writeSinglePackMidx(db,
+				packs[0], midxBase);
+
+		assertEquals(213, copyAsIs(midxTip, baseObject).length);
+
+		DfsPackFile pack = findPack(tipObject);
+		byte[] fromPack = copyAsIs(pack, tipObject);
+		// Reparsing produces the same id
+		byte[] fromMidx = copyAsIs(midxTip, tipObject);
+		assertArrayEquals(fromPack, fromMidx);
+	}
+
+	private byte[] copyAsIs(DfsPackFile pack, ObjectId oid) throws Exception {
+		try (DfsReader ctx = db.getObjectDatabase().newReader();
+				PackWriter pw = new PackWriter(new PackConfig(), ctx);
+				ByteArrayOutputStream os = new ByteArrayOutputStream();
+				PackOutputStream out = new PackOutputStream(
+						NullProgressMonitor.INSTANCE, os, pw)) {
+			// Object in the base
+			ObjectToPack otp = new DfsObjectToPack(oid, OBJ_BLOB);
+			DfsObjectToPack inPack = pack
+					.findAllFromPack(ctx, List.of(otp), false).get(0);
+			DfsObjectRepresentation r = new DfsObjectRepresentation(pack);
+			pack.fillRepresentation(r, inPack.getOffset(), ctx);
+			inPack.select(r);
+			pack.copyAsIs(out, inPack, false, ctx);
+			out.flush();
+			return os.toByteArray();
+		}
+	}
+
+	@Test
+	public void getDeltaHeader() {
+		// TODO(ifrade): Implement
+	}
+
+	@Test
+	public void getObjectType() throws Exception {
+		CommitObjects commitObjects = writePackWithOneCommit();
+		gcWithBitmaps();
+		DfsPackFile midx = writeSinglePackMidx(db);
+
+		try (DfsReader ctx = db.getObjectDatabase().newReader()) {
+			long commitPos = midx.findOffset(ctx, commitObjects.commit());
+			assertEquals(OBJ_COMMIT, midx.getObjectType(ctx, commitPos));
+
+			long treePos = midx.findOffset(ctx, commitObjects.tree());
+			assertEquals(OBJ_TREE, midx.getObjectType(ctx, treePos));
+
+			long blobPos = midx.findOffset(ctx, commitObjects.blob());
+			assertEquals(OBJ_BLOB, midx.getObjectType(ctx, blobPos));
+
+			assertThrows(IllegalArgumentException.class,
+					() -> midx.getObjectType(ctx, 12000));
+		}
+	}
+
+	@Test
+	public void getObjectType_withBase() throws Exception {
+		// This first commit creates two packs
+		CommitObjects objs = writePackWithOneCommit();
+		writePackWithCommit();
+
+		writePackWithCommit();
+		writePackWithRandomBlob(300);
+		ObjectId newCommit = writePackWithCommit();
+
+		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
+		// Packs are in reverse insertion order
+		DfsPackFileMidx midxBase = MidxTestUtils.writeMultipackIndex(db,
+				Arrays.copyOfRange(packs, 1, 7), null);
+		DfsPackFileMidx midxTip = writeSinglePackMidx(db,
+				packs[0], midxBase);
+
+		try (DfsReader ctx = db.getObjectDatabase().newReader()) {
+			long commitPos = midxTip.findOffset(ctx, objs.commit());
+			assertEquals(OBJ_COMMIT, midxTip.getObjectType(ctx, commitPos));
+
+			long treePos = midxTip.findOffset(ctx, objs.tree());
+			assertEquals(OBJ_TREE, midxTip.getObjectType(ctx, treePos));
+
+			long blobPos = midxTip.findOffset(ctx, objs.blob());
+			assertEquals(OBJ_BLOB, midxTip.getObjectType(ctx, blobPos));
+
+			long commitPosTip = midxTip.findOffset(ctx, newCommit);
+			assertEquals(OBJ_COMMIT, midxTip.getObjectType(ctx, commitPosTip));
+
+			assertThrows(IllegalArgumentException.class,
+					() -> midxTip.getObjectType(ctx, 12000));
+		}
+	}
+
+	@Test
+	public void getObjectSize_byId() throws Exception {
+		CommitObjects objs = writePackWithOneCommit();
+		gcWithBitmaps();
+		DfsPackFile midx = writeSinglePackMidx(db);
+
+		try (DfsReader ctx = db.getObjectDatabase().newReader()) {
+			assertEquals(168, midx.getObjectSize(ctx, objs.commit()));
+			assertEquals(33, midx.getObjectSize(ctx, objs.tree()));
+			assertEquals(5, midx.getObjectSize(ctx, objs.blob()));
+
+			assertEquals(-1, midx.getObjectSize(ctx, NOT_IN_PACK));
+		}
+	}
+
+	@Test
+	public void getObjectSize_byId_withBase() throws Exception {
+		ObjectId commit = writePackWithCommit();
+		ObjectId blob = writePackWithRandomBlob(200);
+
+		writePackWithRandomBlob(300);
+		ObjectId blobTwo = writePackWithRandomBlob(100);
+
+		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
+		// Packs are in reverse insertion order
+		DfsPackFileMidx midxBase = MidxTestUtils.writeMultipackIndex(db,
+				Arrays.copyOfRange(packs, 1, 5), null);
+		DfsPackFileMidx midxTip = writeSinglePackMidx(db,
+				packs[0], midxBase);
+
+		try (RevWalk rw = new RevWalk(db);
+				DfsReader ctx = db.getObjectDatabase().newReader()) {
+			RevCommit aCommit = rw.parseCommit(commit);
+			RevTree aTree = rw.parseTree(aCommit.getTree());
+
+			assertEquals(168, midxTip.getObjectSize(ctx, aCommit));
+			assertEquals(33, midxTip.getObjectSize(ctx, aTree));
+			assertEquals(200, midxTip.getObjectSize(ctx, blob));
+			assertEquals(100, midxTip.getObjectSize(ctx, blobTwo));
+
+			assertEquals(-1, midxTip.getObjectSize(ctx, NOT_IN_PACK));
+		}
+	}
+
+	@Test
+	public void getObjectSize_byOffset() throws Exception {
+		ObjectId commit = writePackWithCommit();
+		gcWithBitmaps();
+		DfsPackFile midx = writeSinglePackMidx(db);
+
+		try (RevWalk rw = new RevWalk(db);
+				DfsReader ctx = db.getObjectDatabase().newReader()) {
+			RevCommit aCommit = rw.parseCommit(commit);
+			RevTree aTree = rw.parseTree(aCommit.getTree());
+
+			assertEquals(168,
+					midx.getObjectSize(ctx, midx.findOffset(ctx, aCommit)));
+			assertEquals(33,
+					midx.getObjectSize(ctx, midx.findOffset(ctx, aTree)));
+
+			assertEquals(-1, midx.getObjectSize(ctx, -1));
+		}
+	}
+
+	@Test
+	public void getObjectSize_byOffset_withBase() throws Exception {
+		ObjectId commit = writePackWithCommit();
+		ObjectId blob = writePackWithRandomBlob(200);
+
+		writePackWithRandomBlob(300);
+		ObjectId blobTwo = writePackWithRandomBlob(100);
+
+		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
+		// Packs are in reverse insertion order
+		DfsPackFileMidx midxBase = MidxTestUtils.writeMultipackIndex(db,
+				Arrays.copyOfRange(packs, 1, 5), null);
+		DfsPackFileMidx midxTip = writeSinglePackMidx(db,
+				packs[0], midxBase);
+
+		try (RevWalk rw = new RevWalk(db);
+				DfsReader ctx = db.getObjectDatabase().newReader()) {
+			RevCommit aCommit = rw.parseCommit(commit);
+			RevTree aTree = rw.parseTree(aCommit.getTree());
+
+			assertEquals(168, midxTip.getObjectSize(ctx,
+					midxTip.findOffset(ctx, aCommit)));
+			assertEquals(33,
+					midxTip.getObjectSize(ctx, midxTip.findOffset(ctx, aTree)));
+			assertEquals(200,
+					midxTip.getObjectSize(ctx, midxTip.findOffset(ctx, blob)));
+			assertEquals(100, midxTip.getObjectSize(ctx,
+					midxTip.findOffset(ctx, blobTwo)));
+
+			assertEquals(-1, midxTip.getObjectSize(ctx, -1));
+			assertEquals(-1, midxTip.getObjectSize(ctx,
+					midxTip.findOffset(ctx, NOT_IN_PACK)));
+		}
+	}
+
+	@Test
+	public void objectSizeIndex_disabled() throws Exception {
+		writePackWithRandomBlob(200);
+		DfsPackFile midx = writeSinglePackMidx(db);
+
+		try (DfsReader ctx = db.getObjectDatabase().newReader()) {
+			assertFalse(midx.hasObjectSizeIndex(ctx));
+		}
+	}
+
+	@Test
+	public void fillRepresentation() throws Exception {
+		RevCommit commit = writePackWithCommit();
+		gcWithBitmaps();
+		DfsPackFile midx = writeSinglePackMidx(db);
+
+		DfsObjectRepresentation rep = fillRepresentation(midx, commit,
+				OBJ_COMMIT);
+		assertEquals(midx, rep.pack);
+		assertEquals(12, rep.offset);
+		assertEquals(120, rep.length);
+	}
+
+	DfsObjectRepresentation fillRepresentation(DfsPackFile midx,
+			ObjectId commit, int typeHint) throws Exception {
+		try (DfsReader ctx = db.getObjectDatabase().newReader()) {
+			ObjectToPack otp = new DfsObjectToPack(commit, typeHint);
+			DfsObjectToPack inPack = midx
+					.findAllFromPack(ctx, List.of(otp), true).get(0);
+			DfsObjectRepresentation rep = new DfsObjectRepresentation(midx);
+			midx.fillRepresentation(rep, inPack.getOffset(), ctx);
+			return rep;
+		}
+	}
+
+	@Test
+	public void fillRepresentation_withBase() throws Exception {
+		RevCommit commitInBase = writePackWithCommit();
+		ObjectId blob = writePackWithRandomBlob(300);
+		writePackWithRandomBlob(500);
+		writePackWithRandomBlob(100);
+		RevCommit commitInTip = writePackWithCommit();
+
+		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
+		assertEquals(6, packs.length);
+		DfsPackFileMidx midxBase = MidxTestUtils.writeMultipackIndex(db,
+				Arrays.copyOfRange(packs, 1, 6), null);
+		DfsPackFileMidx midxTip = writeSinglePackMidx(db,
+				packs[0], midxBase);
+
+		try (DfsReader ctx = db.getObjectDatabase().newReader()) {
+			// Commit in tip midx
+			DfsObjectRepresentation rep = fillRepresentation(midxTip,
+					commitInTip, OBJ_COMMIT);
+			assertEquals(midxTip.getPackDescription(),
+					rep.pack.getPackDescription());
+			assertEquals(midxTip.findOffset(ctx, commitInTip), rep.offset);
+			assertEquals(148, rep.length);
+
+			// Commit in base midx
+			rep = fillRepresentation(midxTip, commitInBase, OBJ_COMMIT);
+			assertEquals(midxTip.getPackDescription(),
+					rep.pack.getPackDescription());
+			assertEquals(midxTip.findOffset(ctx, commitInBase), rep.offset);
+			assertEquals(120, rep.length);
+
+			// Blob in base
+			rep = fillRepresentation(midxTip, blob, OBJ_COMMIT);
+			assertEquals(midxTip.getPackDescription(),
+					rep.pack.getPackDescription());
+			assertEquals(midxTip.findOffset(ctx, blob), rep.offset);
+			assertEquals(281, rep.length);
+		}
+	}
+
+	@Test
+	public void getBitmapIndex() throws Exception {
+		RevCommit c1 = writePackWithCommit();
+		RevCommit c2 = writePackWithCommit();
+		gcWithBitmaps();
+
+		DfsPackFileMidx midx = writeSinglePackMidx(db);
+		try (DfsReader ctx = db.getObjectDatabase().newReader()) {
+			PackBitmapIndex bitmapIndex = midx.getBitmapIndex(ctx);
+			assertNotNull(bitmapIndex);
+			assertEquals(4, bitmapIndex.getObjectCount());
+			assertEquals(1, bitmapIndex.findPosition(c1));
+			assertEquals(0, bitmapIndex.findPosition(c2));
+		}
+	}
+
+	@Test
+	public void getAllCoveredPacks() throws Exception {
+		ObjectId[] objectIds = writePackWithBlobs(db, "aaaaaaaa",
+				"bbbbbbb", "ccccccc");
+		DfsPackFileMidx midx = writeSinglePackMidx(db);
+		DfsPackFile realPack = findPack(objectIds[0]);
+
+		assertEquals(1, midx.getAllCoveredPacks().size());
+		assertEquals(realPack.getPackDescription(),
+				midx.getAllCoveredPacks().get(0).getPackDescription());
+	}
+
+	@Test
+	public void getAllCoveredPacks_withBase() throws Exception {
+		writePackWithCommit();
+		writePackWithRandomBlob(300);
+		writePackWithRandomBlob(500);
+		writePackWithRandomBlob(100);
+
+		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
+		assertEquals(5, packs.length);
+		DfsPackFileMidx midxBase = MidxTestUtils.writeMultipackIndex(db,
+				Arrays.copyOfRange(packs, 1, 5), null);
+		DfsPackFileMidx midxTip = writeSinglePackMidx(db,
+				packs[0], midxBase);
+
+		assertEquals(5, midxTip.getAllCoveredPacks().size());
+		List<DfsPackDescription> expected = Arrays.stream(packs)
+				.map(DfsPackFile::getPackDescription).toList();
+		List<DfsPackDescription> actual = midxTip.getAllCoveredPacks().stream()
+				.map(DfsPackFile::getPackDescription).toList();
+		assertEquals(expected, actual);
+	}
+
+	@Test
+	public void getCoveredPacks_withBase_onlyTopMidx() throws Exception {
+		writePackWithCommit();
+		writePackWithRandomBlob(300);
+		writePackWithRandomBlob(500);
+		writePackWithRandomBlob(100);
+
+		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
+		assertEquals(5, packs.length);
+		DfsPackFileMidx midxBase = MidxTestUtils.writeMultipackIndex(db,
+				Arrays.copyOfRange(packs, 1, 5), null);
+		DfsPackFileMidx midxTip = writeSinglePackMidx(db,
+				packs[0], midxBase);
+
+		assertEquals(1, midxTip.getCoveredPacks().size());
+		assertEquals(packs[0].getPackDescription(),
+				midxTip.getAllCoveredPacks().get(0).getPackDescription());
+	}
+
+	@Test
+	public void corrupt() throws Exception {
+		RevCommit commit = writePackWithCommit();
+		DfsPackFile pack = findPack(commit);
+		DfsPackFileMidx midx = writeSinglePackMidx(db, pack);
+		try (DfsReader ctx = db.getObjectDatabase().newReader()) {
+			assertFalse(midx.isCorrupt(midx.findOffset(ctx, commit)));
+		}
+	}
+
+	@Test
+	public void packwriter_via_midx() throws Exception {
+		ObjectId[] oids = writePackWithBlobs(db, "xxxxxxxyyyy",
+				"booooohooooo", "baaaaahaaaaaa");
+		ObjectId blob = oids[0];
+		ObjectId blobTwo = oids[1];
+		ObjectId notPacked = oids[2];
+
+		writeSinglePackMidx(db);
+
+		db.getObjectDatabase().setUseMultipackIndex(true);
+		byte[] writtenPack;
+		try (DfsReader ctx = db.getObjectDatabase().newReader();
+				RevWalk rw = new RevWalk(ctx);
+				PackWriter pw = new PackWriter(db, ctx)) {
+			pw.addObject(rw.lookupBlob(blob));
+			pw.addObject(rw.lookupBlob(blobTwo));
+
+			try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
+				CounterProgressMonitor cpm = new CounterProgressMonitor();
+				pw.writePack(NullProgressMonitor.INSTANCE, cpm, out);
+				out.flush();
+				assertEquals(79, out.size());
+				assertEquals(2, cpm.objectsPacked);
+				writtenPack = out.toByteArray();
+			}
+		}
+
+		try (InMemoryRepository dest = new InMemoryRepository(
+				new DfsRepositoryDescription("test"));
+				ObjectInserter ins = dest.getObjectDatabase().newInserter()) {
+			ins.newPackParser(new ByteArrayInputStream(writtenPack))
+					.parse(NullProgressMonitor.INSTANCE);
+			assertTrue(dest.getObjectDatabase().has(blob));
+			assertTrue(dest.getObjectDatabase().has(blobTwo));
+			assertFalse(dest.getObjectDatabase().has(notPacked));
+		}
+	}
+
+	@Test
+	public void getChecksum() throws Exception {
+		writePackWithBlobs(db, "something", "something else", "and more");
+		DfsPackFileMidx midx = writeSinglePackMidx(db);
+		try (DfsReader ctx = db.getObjectDatabase().newReader()) {
+			// The checksum includes packnames and can
+			// change between runs (e.g. running this test alone, or locally vs
+			// jenkins).
+			// Check at least that we don't get an empty checksum or the first
+			// bytes of the midx.
+			byte[] checksum = midx.getChecksum(ctx);
+			assertNotNull(checksum);
+			assertEquals(20, checksum.length);
+			assertNotEquals('M', checksum[0]);
+			assertNotEquals('I', checksum[1]);
+			assertNotEquals('D', checksum[2]);
+			assertNotEquals('X', checksum[3]);
+		}
+	}
+
+	@Test
+	public void voffsetcalculator_encode() {
+		DfsPackFile pack = createDfsPackFile(900);
+		SingleVOffsetCalculator calc = new SingleVOffsetCalculator(pack, null);
+
+		PackOffset po = PackOffset.create(0, 12);
+		assertEquals(12, calc.encode(po));
+		po = PackOffset.create(0, 800);
+		assertEquals(800, calc.encode(po));
+
+		// Invalid packId
+		assertThrows(IllegalArgumentException.class,
+				() -> calc.encode(PackOffset.create(1, 12)));
+	}
+
+	@Test
+	public void voffsetcalculator_decode() {
+		DfsPackFile pack = createDfsPackFile(800);
+		SingleVOffsetCalculator calc = new SingleVOffsetCalculator(pack, null);
+
+		DfsPackOffset decoded = calc.decode(130);
+		assertEquals(pack.getPackDescription(),
+				decoded.getPack().getPackDescription());
+		assertEquals(130, decoded.getPackOffset());
+		assertEquals(0, decoded.getPackStart());
+
+		decoded = calc.decode(0);
+		assertEquals(pack.getPackDescription(),
+				decoded.getPack().getPackDescription());
+		assertEquals(0, decoded.getPackOffset());
+		assertEquals(0, decoded.getPackStart());
+
+		assertThrows("too big", IllegalArgumentException.class,
+				() -> calc.decode(900));
+	}
+
+	@Test
+	public void voffsetcalculator_notFound() {
+		DfsPackFile pack = createDfsPackFile(800);
+		SingleVOffsetCalculator calc = new SingleVOffsetCalculator(pack, null);
+
+		assertEquals(-1, calc.encode(null));
+		assertNull(calc.decode(-1));
+	}
+
+	@Test
+	public void voffsetcalculator_maxOffset() {
+		DfsPackFile pack = createDfsPackFile(800);
+		SingleVOffsetCalculator calc = new SingleVOffsetCalculator(pack, null);
+		assertEquals(800, calc.getMaxOffset());
+	}
+
+	@Test
+	public void voffsetcalculator_withBase_encode() {
+		DfsPackFile one = createDfsPackFile(800);
+		SingleVOffsetCalculator calcOne = new SingleVOffsetCalculator(one,
+				null);
+		DfsPackFile two = createDfsPackFile(1200);
+		SingleVOffsetCalculator calcTwo = new SingleVOffsetCalculator(two,
+				calcOne);
+
+		PackOffset po = PackOffset.create(0, 12);
+		assertEquals(12 + 800, calcTwo.encode(po));
+	}
+
+	@Test
+	public void voffsetcalculator_withBase_decode() {
+		DfsPackFile one = createDfsPackFile(800);
+		SingleVOffsetCalculator calcOne = new SingleVOffsetCalculator(one,
+				null);
+		DfsPackFile two = createDfsPackFile(1200);
+		SingleVOffsetCalculator calcTwo = new SingleVOffsetCalculator(two,
+				calcOne);
+
+		// In top pack
+		DfsPackOffset decoded = calcTwo.decode(900);
+		assertEquals(two.getPackDescription(),
+				decoded.getPack().getPackDescription());
+		assertEquals(100, decoded.getPackOffset());
+		assertEquals(800, decoded.getPackStart());
+
+		// In parent pack
+		decoded = calcTwo.decode(700);
+		assertEquals(one.getPackDescription(),
+				decoded.getPack().getPackDescription());
+		assertEquals(700, decoded.getPackOffset());
+		assertEquals(0, decoded.getPackStart());
+	}
+
+	@Test
+	public void voffsetcalculator_withBase_maxOffset() {
+		DfsPackFile one = createDfsPackFile(800);
+		SingleVOffsetCalculator calcOne = new SingleVOffsetCalculator(one,
+				null);
+		DfsPackFile two = createDfsPackFile(1200);
+		SingleVOffsetCalculator calcTwo = new SingleVOffsetCalculator(two,
+				calcOne);
+
+		assertEquals(2000, calcTwo.getMaxOffset());
+	}
+
+	private static DfsPackFile createDfsPackFile(int size) {
+		DfsPackDescription desc = new DfsPackDescription(
+				new DfsRepositoryDescription("the_repo"), "pack_blabla", GC);
+		desc.addFileExt(PACK);
+		desc.setFileSize(PACK, size);
+		desc.setObjectCount(1);
+		return new DfsPackFile(null, desc);
+	}
+
+	private DfsPackFileMidx writeMultipackIndex() throws IOException {
+		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
+		return MidxTestUtils.writeMultipackIndex(db, packs, null);
+	}
+
+	private void gcWithBitmaps() throws IOException {
+		DfsGarbageCollector garbageCollector = new DfsGarbageCollector(db);
+		garbageCollector.pack(NullProgressMonitor.INSTANCE);
+	}
+
+	private RevCommit writePackWithCommit() throws Exception {
+		try (TestRepository<InMemoryRepository> repository = new TestRepository<>(
+				db)) {
+			// commitCounter++;
+			return repository.branch("/refs/heads/main").commit()
+					.add("blob" + commitCounter, "blob" + commitCounter)
+					.create();
+		}
+	}
+
+	record CommitObjects(RevCommit commit, RevTree tree, RevBlob blob) {
+	}
+
+	private static int commitCounter = 1;
+
+	private CommitObjects writePackWithOneCommit() throws Exception {
+		try (TestRepository<InMemoryRepository> repository = new TestRepository<>(
+				db)) {
+			RevBlob blob = repository.blob("blob" + commitCounter);
+			RevCommit revCommit = repository.branch("/refs/heads/main").commit()
+					.add("blob" + commitCounter, blob).create();
+			commitCounter++;
+			return new CommitObjects(revCommit, revCommit.getTree(), blob);
+		}
+	}
+
+	private ObjectId writePackWithRandomBlob(int size) throws IOException {
+		byte[] data = new TestRng(JGitTestUtil.getName()).nextBytes(size);
+		return writePackWithBlob(data);
+	}
+
+	private ObjectId writePackWithBlob(byte[] data) throws IOException {
+		DfsInserter ins = (DfsInserter) db.newObjectInserter();
+
+		ObjectId blobId = ins.insert(OBJ_BLOB, data);
+		ins.flush();
+		return blobId;
+	}
+
+	private DfsPackFile findPack(ObjectId oid) throws IOException {
+		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
+		try (DfsReader ctx = db.getObjectDatabase().newReader()) {
+			for (DfsPackFile pack : packs) {
+				if (pack.hasObject(ctx, oid)) {
+					return pack;
+				}
+			}
+		}
+		throw new IllegalArgumentException("Object not in any pack");
+	}
+
+	private static final class CounterProgressMonitor
+			implements ProgressMonitor {
+
+		int objectsPacked = 0;
+
+		@Override
+		public void start(int totalTasks) {
+			// empty
+		}
+
+		@Override
+		public void beginTask(String title, int totalWork) {
+			System.out.println("Starting " + title);
+		}
+
+		@Override
+		public void update(int completed) {
+			objectsPacked += 1;
+		}
+
+		@Override
+		public void endTask() {
+			// empty
+		}
+
+		@Override
+		public boolean isCancelled() {
+			return false;
+		}
+
+		@Override
+		public void showDuration(boolean enabled) {
+			// empty
+		}
+	}
+
+	private byte[] safeGetBytes(@Nullable ObjectLoader ol) {
+		assertNotNull(ol);
+		byte[] data = ol.getBytes();
+		assertNotNull(data);
+		return data;
+	}
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/MidxPackFilterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/MidxPackFilterTest.java
index 584bab1..68aacba 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/MidxPackFilterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/MidxPackFilterTest.java
@@ -130,6 +130,81 @@ public void useMidx_nestedMidxAndOnePack_topMidxAndPack() {
 	}
 
 	@Test
+	public void useMidx_unconnectedValidMidx_onlyTop() {
+
+		DfsPackDescription gc = pack("aaaa", GC, PACK);
+		DfsPackDescription compact = pack("cccc", COMPACT, PACK);
+		DfsPackDescription firstMidx = pack("midx1", GC, MULTI_PACK_INDEX);
+		firstMidx.setCoveredPacks(List.of(gc, compact));
+
+		DfsPackDescription unconnectedValid = pack("randoMidx", GC,
+				MULTI_PACK_INDEX);
+		unconnectedValid.setCoveredPacks(List.of(gc));
+
+		DfsPackDescription compact2 = pack("dddd", COMPACT, PACK);
+		DfsPackDescription compact3 = pack("eeee", COMPACT, PACK);
+		DfsPackDescription topMidx = pack("midx2", GC, MULTI_PACK_INDEX);
+		topMidx.setCoveredPacks(List.of(compact2, compact3));
+		topMidx.setMultiPackIndexBase(firstMidx);
+
+		List<DfsPackDescription> reorgPacks = MidxPackFilter
+				.useMidx(List.of(gc, compact, firstMidx, unconnectedValid,
+						compact2, compact3, topMidx));
+		assertEquals(1, reorgPacks.size());
+		assertTrue(reorgPacks.contains(topMidx));
+	}
+
+	@Test
+	public void useMidx_unconnectedInvalidMidx_onlyTop() {
+		DfsPackDescription gc = pack("aaaa", GC, PACK);
+		DfsPackDescription compact = pack("cccc", COMPACT, PACK);
+		DfsPackDescription firstMidx = pack("midx1", GC, MULTI_PACK_INDEX);
+		firstMidx.setCoveredPacks(List.of(gc, compact));
+
+		DfsPackDescription notCommitted = pack("not-in-db", GC, PACK);
+		DfsPackDescription unconnectedInvalid = pack("randoMidx", GC,
+				MULTI_PACK_INDEX);
+		unconnectedInvalid.setCoveredPacks(List.of(notCommitted));
+
+		DfsPackDescription compact2 = pack("dddd", COMPACT, PACK);
+		DfsPackDescription compact3 = pack("eeee", COMPACT, PACK);
+		DfsPackDescription topMidx = pack("midx2", GC, MULTI_PACK_INDEX);
+		topMidx.setCoveredPacks(List.of(compact2, compact3));
+		topMidx.setMultiPackIndexBase(firstMidx);
+
+		List<DfsPackDescription> reorgPacks = MidxPackFilter
+				.useMidx(List.of(gc, compact, firstMidx, unconnectedInvalid,
+						compact2, compact3, topMidx));
+		assertEquals(1, reorgPacks.size());
+		assertTrue(reorgPacks.contains(topMidx));
+	}
+
+	@Test
+	public void useMidx_latestMidxInvalid_takeNext() {
+		DfsPackDescription gc = pack("aaaa", GC, PACK);
+		DfsPackDescription compact = pack("cccc", COMPACT, PACK);
+		DfsPackDescription firstMidx = pack("midx1", GC, MULTI_PACK_INDEX);
+		firstMidx.setCoveredPacks(List.of(gc, compact));
+
+		DfsPackDescription compact2 = pack("dddd", COMPACT, PACK);
+		DfsPackDescription compact3 = pack("eeee", COMPACT, PACK);
+		DfsPackDescription topMidx = pack("midx2", GC, MULTI_PACK_INDEX);
+		topMidx.setCoveredPacks(List.of(compact2, compact3));
+		topMidx.setMultiPackIndexBase(firstMidx);
+
+		DfsPackDescription notCommitted = pack("not-in-db", GC, PACK);
+		DfsPackDescription unconnectedInvalid = pack("randoMidx", GC,
+				MULTI_PACK_INDEX);
+		unconnectedInvalid.setCoveredPacks(List.of(notCommitted));
+
+		List<DfsPackDescription> reorgPacks = MidxPackFilter
+				.useMidx(List.of(gc, compact, firstMidx, unconnectedInvalid,
+						compact2, compact3, topMidx));
+		assertEquals(1, reorgPacks.size());
+		assertTrue(reorgPacks.contains(topMidx));
+	}
+
+	@Test
 	public void skipMidx_oneMidxCoversAll_allPacks() {
 		DfsPackDescription gc = pack("aaaa", GC, PACK);
 		DfsPackDescription compact = pack("cccc", COMPACT, PACK);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/RefAdvancerWalkTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/RefAdvancerWalkTest.java
new file mode 100644
index 0000000..321ea01
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/RefAdvancerWalkTest.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2026, Google LLC.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.internal.storage.dfs;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.junit.Before;
+import org.junit.Test;
+
+public class RefAdvancerWalkTest {
+	private static final String MAIN = "refs/heads/main";
+
+	private InMemoryRepository db;
+
+	private TestRepository<InMemoryRepository> git;
+
+	private Set<RevCommit> commitsInMidx;
+
+	private Map<String, RevCommit> commitByLetter;
+
+	@Before
+	public void setUp() throws Exception {
+		db = new InMemoryRepository(
+				new DfsRepositoryDescription("ref advance"));
+		git = new TestRepository<>(db);
+		setupRepo();
+	}
+
+	/**
+	 * <pre>
+	 *  tipMergeBeforeMidx -> H
+	 *                        |
+	 *                        |
+	 *                        F  G <- tipStraight
+	 *                        |\ |
+	 *                        | \|
+	 * tipMergeMidxCommits -> D  E
+	 *                        |\ |
+	 *                      +--------+
+	 *                      | B  C <-- tipIn
+	 *                      | | /    |
+	 *                      | |/     |
+	 *                      | A      |
+	 *                      |    midx|
+	 *                      +--------+
+	 * </pre>
+	 */
+	private void setupRepo() throws Exception {
+		RevCommit a = commitToMain();
+		RevCommit b = commitToMain();
+		RevCommit c = commit(a);
+		RevCommit d = commitToMain(c);
+		RevCommit e = commit(c);
+		/* unused */ commitToMain();
+		RevCommit g = commit(e);
+		RevCommit h = commitToMain();
+
+		commitsInMidx = new HashSet<>();
+		commitsInMidx.add(a);
+		commitsInMidx.add(b);
+		commitsInMidx.add(c);
+
+		commitByLetter = Map.of("a", a, "b", b, "c", c, "d", d, "e", e, "g", g,
+				"h", h);
+
+	}
+
+	@Test
+	public void singleWant_linearHistory() throws Exception {
+		runTest("g", Set.of("c"));
+	}
+
+	@Test
+	public void singleWant_alreadyInMidx() throws Exception {
+		runTest("c", Set.of("c"));
+	}
+
+	@Test
+	public void singleWant_mergeCommitsInMidx() throws Exception {
+		runTest("d", Set.of("b", "c"));
+	}
+
+	@Test
+	public void singleWant_mergeBeforeMidx() throws Exception {
+		runTest("h", Set.of("b", "c"));
+	}
+
+	@Test
+	public void manyWant_mergeBeforeMidx() throws Exception {
+		runTest(Set.of("h", "c", "d", "g"), Set.of("b", "c"));
+	}
+
+	private void runTest(String want, Set<String> expectedTips)
+			throws IOException {
+		runTest(Set.of(want), expectedTips);
+	}
+
+	private void runTest(Set<String> want, Set<String> expectedTips)
+			throws IOException {
+		RefAdvancerWalk advancer = new RefAdvancerWalk(db,
+				commitsInMidx::contains);
+		List<ObjectId> wants = want.stream().map(commitByLetter::get)
+				.collect(Collectors.toUnmodifiableList());
+		Set<RevCommit> tipsInMidx = advancer.advance(wants);
+
+		Set<RevCommit> expected = expectedTips.stream().map(commitByLetter::get)
+				.collect(Collectors.toUnmodifiableSet());
+		assertEquals(expected.size(), tipsInMidx.size());
+		assertTrue(tipsInMidx.containsAll(expected));
+	}
+
+	private static int commitCounter = 0;
+
+	private RevCommit commitToMain() throws Exception {
+		int i = commitCounter++;
+		return git.branch(MAIN).commit()
+				.add("xx" + i, git.blob("content #" + i)).create();
+	}
+
+	private RevCommit commitToMain(RevCommit... extraParent) throws Exception {
+		int i = commitCounter++;
+		TestRepository<InMemoryRepository>.CommitBuilder commit = git
+				.branch(MAIN).commit();
+		for (RevCommit p : extraParent) {
+			commit.parent(p);
+		}
+
+		return commit.add("xx" + i, git.blob("content #" + i)).create();
+	}
+
+	private RevCommit commit(RevCommit parent) throws Exception {
+		int i = commitCounter++;
+		return git.commit().parent(parent)
+				.add("cc" + i, git.blob("out of main content #" + i)).create();
+	}
+
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcBasicPackingTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcBasicPackingTest.java
index 434f7e4..101feec 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcBasicPackingTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcBasicPackingTest.java
@@ -21,8 +21,11 @@
 import java.util.Collection;
 import java.util.List;
 
+import org.eclipse.jgit.api.Git;
 import org.eclipse.jgit.junit.TestRepository.BranchBuilder;
 import org.eclipse.jgit.lib.ConfigConstants;
+import org.eclipse.jgit.lib.GcConfig;
+import org.eclipse.jgit.lib.GcConfig.PackRefsMode;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.RefUpdate;
 import org.eclipse.jgit.revwalk.RevCommit;
@@ -376,4 +379,106 @@ private PackConfig configureGc(GC myGc, boolean aggressive) {
 		myGc.setPackConfig(pconfig);
 		return pconfig;
 	}
+
+	@Test
+	public void testPackRefs() throws Exception {
+		tr.branch("refs/heads/master").commit().add("A", "A").add("B", "B")
+				.create();
+		assertHasLooseRef(repo);
+
+		// by default, refs should be packed
+		gc.gc().get();
+		assertHasNoLooseRef(repo);
+
+		// now create a loose ref again
+		tr.branch("refs/heads/foo").commit().add("C", "C").create();
+		assertHasLooseRef(repo);
+		// and disable packing of refs
+		gc.setGcConfig(new GcConfig(PackRefsMode.FALSE));
+		gc.gc().get();
+		assertHasLooseRef(repo);
+	}
+
+	@Test
+	public void testPackRefsWithConfig() throws Exception {
+		tr.branch("refs/heads/master").commit().add("A", "A").add("B", "B")
+				.create();
+		assertHasLooseRef(repo);
+
+		// disable packing of refs via config
+		FileBasedConfig config = repo.getConfig();
+		config.setEnum(ConfigConstants.CONFIG_GC_SECTION, null,
+				ConfigConstants.CONFIG_KEY_PACK_REFS, PackRefsMode.FALSE);
+		config.save();
+		reloadGcFromRepoConfig();
+
+		gc.gc().get();
+		assertHasLooseRef(repo);
+
+		// now enable packing of refs via API
+		gc.setGcConfig(new GcConfig(PackRefsMode.TRUE));
+		gc.gc().get();
+		assertHasNoLooseRef(repo);
+	}
+
+	@Test
+	public void testPackRefsWithNotBareConfig() throws Exception {
+		// non-bare repo
+		tr.branch("refs/heads/master").commit().add("A", "A").add("B", "B")
+				.create();
+		assertHasLooseRef(repo);
+
+		// configure packing of refs only for non-bare repositories
+		FileBasedConfig config = repo.getConfig();
+		config.setEnum(ConfigConstants.CONFIG_GC_SECTION, null,
+				ConfigConstants.CONFIG_KEY_PACK_REFS, PackRefsMode.NOTBARE);
+		config.save();
+		reloadGcFromRepoConfig();
+
+		gc.gc().get();
+		assertHasNoLooseRef(repo);
+
+		// bare repo
+		String repoUri = repo.getDirectory().toURI().toString();
+		File dir = createUniqueTestGitDir(true);
+		try (FileRepository bareRepo = (FileRepository) Git.cloneRepository()
+				.setBare(true).setURI(repoUri).setDirectory(dir).call()
+				.getRepository(); Git git = new Git(bareRepo)) {
+			git.branchCreate().setName("refs/heads/branch-in-bare-repo")
+					.setStartPoint("refs/heads/master").call();
+			assertHasLooseRef(bareRepo);
+
+			// configure packing of refs only for non-bare repositories
+			FileBasedConfig bareConfig = bareRepo.getConfig();
+			bareConfig.setEnum(ConfigConstants.CONFIG_GC_SECTION, null,
+					ConfigConstants.CONFIG_KEY_PACK_REFS, PackRefsMode.NOTBARE);
+			bareConfig.save();
+			// create a new GC instance to reread the config
+			gc = new GC(bareRepo);
+
+			gc.gc().get();
+			assertHasLooseRef(bareRepo);
+		}
+	}
+
+	private static boolean hasLooseRef(FileRepository repository)
+			throws IOException {
+		return repository.getRefDatabase().getRefs().stream()
+				.filter(r -> !r.isSymbolic())
+				.anyMatch(r -> r.getStorage().isLoose());
+	}
+
+	private void reloadGcFromRepoConfig() {
+		gc = new GC(repo);
+	}
+
+	private static void assertHasLooseRef(FileRepository repository)
+			throws IOException {
+		assertTrue("should have loose ref", hasLooseRef(repository));
+	}
+
+	private static void assertHasNoLooseRef(FileRepository repository)
+			throws IOException {
+		assertFalse("should have no loose ref", hasLooseRef(repository));
+	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackBitmapIndexBuilderTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackBitmapIndexBuilderTest.java
new file mode 100644
index 0000000..10d9c2e
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackBitmapIndexBuilderTest.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright (C) 2026, Google LLC.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.internal.storage.file;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.jgit.internal.storage.pack.BitmapCommit;
+import org.eclipse.jgit.internal.storage.pack.ObjectToPack;
+import org.eclipse.jgit.lib.BitmapIndex;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectIdOwnerMap;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import com.googlecode.javaewah.EWAHCompressedBitmap;
+
+@RunWith(Parameterized.class)
+public class PackBitmapIndexBuilderTest {
+
+	/**
+	 * Numbers are oids
+	 *
+	 * <pre>
+	 *     tip
+	 *     10 (commit) -> 9 (tree) -> 8 (blob)
+	 *      |
+	 *      7 (commit) -> 6 (tree) -> 5,4  (blobs)
+	 *      |
+	 *      3 (commit) -> 2 (tree) ->  1 (blob)
+	 * </pre>
+	 */
+	private static final List<ObjectToPack> opts = List.of(
+			otp(10, 400, Constants.OBJ_COMMIT), otp(9, 900, Constants.OBJ_TREE),
+			otp(8, 280, Constants.OBJ_BLOB), otp(7, 200, Constants.OBJ_COMMIT),
+			otp(6, 410, Constants.OBJ_TREE), otp(5, 500, Constants.OBJ_BLOB),
+			otp(4, 450, Constants.OBJ_BLOB), otp(3, 470, Constants.OBJ_COMMIT),
+			otp(2, 700, Constants.OBJ_TREE), otp(1, 240, Constants.OBJ_BLOB));
+
+	public enum TestSetup {
+		SINGLE_BUILDER
+	}
+
+	@Parameterized.Parameters(name = "{0}")
+	public static Iterable<TestSetup> data() {
+		return Arrays.stream(TestSetup.values()).toList();
+	}
+
+	private final TestSetup currentSetup;
+
+	public PackBitmapIndexBuilderTest(TestSetup ts) {
+		this.currentSetup = ts;
+	}
+
+	@Test
+	public void getObjectSet() {
+		ObjectIdOwnerMap<ObjectIdOwnerMap.Entry> objectSet = createBuilder()
+				.getObjectSet();
+		for (int i = 1; i <= 10; i++) {
+			assertTrue(objectSet.contains(oid(i)));
+		}
+	}
+
+	@Test
+	public void addBitmap_getBitmap() {
+		EWAHCompressedBitmap added = EWAHCompressedBitmap.bitmapOf(1, 3, 5);
+		PackBitmapIndexBuilder pbi = createBuilder();
+		pbi.addBitmap(oid(11), added, 10);
+
+		EWAHCompressedBitmap retrieved = pbi.getBitmap(oid(11));
+		assertEquals(added, retrieved);
+	}
+
+	@Test
+	public void ofObjectType() {
+		PackBitmapIndexBuilder pbi = createBuilder();
+		BitmapIndexImpl bii = new BitmapIndexImpl(pbi);
+		BitmapIndex.BitmapBuilder bb = bii.newBitmapBuilder();
+		bb.addObject(oid(10), Constants.OBJ_COMMIT);
+		bb.addObject(oid(9), Constants.OBJ_TREE);
+		bb.addObject(oid(8), Constants.OBJ_BLOB);
+		BitmapIndex.Bitmap b = bb.build();
+
+		EWAHCompressedBitmap commits = pbi.ofObjectType(b.retrieveCompressed(),
+				Constants.OBJ_COMMIT);
+		assertInBitmap(pbi, commits, 10);
+		assertNotInBitmap(pbi, commits, 9);
+		assertNotInBitmap(pbi, commits, 8);
+
+		EWAHCompressedBitmap trees = pbi.ofObjectType(b.retrieveCompressed(),
+				Constants.OBJ_TREE);
+		assertNotInBitmap(pbi, trees, 10);
+		assertInBitmap(pbi, trees, 9);
+		assertNotInBitmap(pbi, trees, 8);
+
+		EWAHCompressedBitmap blobs = pbi.ofObjectType(b.retrieveCompressed(),
+				Constants.OBJ_BLOB);
+		assertNotInBitmap(pbi, blobs, 10);
+		assertNotInBitmap(pbi, blobs, 9);
+		assertInBitmap(pbi, blobs, 8);
+	}
+
+	@Test
+	public void findPosition() {
+		PackBitmapIndexBuilder pbi = createBuilder();
+		// All valid, non-repeating positions
+		Set<Integer> seen = new HashSet<>();
+		for (int oidAsInt = 1; oidAsInt <= 10; oidAsInt++) {
+			int p = pbi.findPosition(oid(oidAsInt));
+			assertTrue(p >= 0);
+			assertTrue(p < 10);
+			assertFalse(seen.contains(p));
+			seen.add(p);
+		}
+	}
+
+	@Test
+	public void getObject() {
+		PackBitmapIndexBuilder pbi = createBuilder();
+		for (int oidAsInt = 1; oidAsInt <= 10; oidAsInt++) {
+			ObjectId expected = oid(oidAsInt);
+			int p = pbi.findPosition(expected);
+			ObjectId actual = pbi.getObject(p);
+			assertEquals(expected, actual);
+		}
+	}
+
+	@Test
+	public void commits() {
+		PackBitmapIndexBuilder pbi = createBuilder();
+		EWAHCompressedBitmap commits = pbi.getCommits();
+		assertInBitmap(pbi, commits, 10);
+		assertInBitmap(pbi, commits, 7);
+		assertInBitmap(pbi, commits, 3);
+
+		assertNotInBitmap(pbi, commits, 9);
+		assertNotInBitmap(pbi, commits, 8);
+	}
+
+	@Test
+	public void trees() {
+		PackBitmapIndexBuilder pbi = createBuilder();
+		EWAHCompressedBitmap trees = pbi.getTrees();
+		assertInBitmap(pbi, trees, 9);
+		assertInBitmap(pbi, trees, 6);
+		assertInBitmap(pbi, trees, 2);
+
+		assertNotInBitmap(pbi, trees, 10);
+		assertNotInBitmap(pbi, trees, 8);
+	}
+
+	@Test
+	public void blobs() {
+		PackBitmapIndexBuilder pbi = createBuilder();
+		EWAHCompressedBitmap blobs = pbi.getBlobs();
+		assertInBitmap(pbi, blobs, 8);
+		assertInBitmap(pbi, blobs, 5);
+		assertInBitmap(pbi, blobs, 4);
+		assertInBitmap(pbi, blobs, 1);
+
+		assertNotInBitmap(pbi, blobs, 10);
+		assertNotInBitmap(pbi, blobs, 9);
+	}
+
+	@Test
+	public void getBitmapCount() {
+		// The builder only counts bitmaps "in progress" (in xor queue or ready
+		// to write)
+		assertEquals(0, createBuilder().getBitmapCount());
+	}
+
+	@Test
+	public void getBitmapCount_newBitmaps() {
+
+	}
+
+	@Test
+	public void reachableObjects_setInBitmap() {
+		PackBitmapIndexBuilder builder = createBuilder();
+		EWAHCompressedBitmap bitmapTen = builder.getBitmap(oid(10));
+		assertNotNull(bitmapTen);
+		for (int oidAsInt = 10; oidAsInt > 0; oidAsInt--) {
+			assertInBitmap(builder, bitmapTen, oidAsInt);
+		}
+
+		EWAHCompressedBitmap bitmapSeven = builder.getBitmap(oid(7));
+		assertNotNull(bitmapSeven);
+		assertNotInBitmap(builder, bitmapSeven, 10);
+		assertNotInBitmap(builder, bitmapSeven, 9);
+		assertNotInBitmap(builder, bitmapSeven, 8);
+		for (int i = 7; i > 0; i--) {
+			assertInBitmap(builder, bitmapSeven, i);
+		}
+	}
+
+	@Test
+	public void processBitmapForWrite() {
+		// processBitmapForWrite keeps the bitmaps in the builder instead of in
+		// the superclass, to calculate the XORs
+		PackBitmapIndexBuilder builder = createBuilder();
+		BitmapIndex bb = new BitmapIndexImpl(builder);
+		BitmapIndex.BitmapBuilder oneBitmap = bb.newBitmapBuilder();
+		oneBitmap.addObject(oid(10), Constants.OBJ_COMMIT);
+		oneBitmap.addObject(oid(9), Constants.OBJ_TREE);
+		oneBitmap.addObject(oid(8), Constants.OBJ_BLOB);
+		oneBitmap.addObject(oid(7), Constants.OBJ_COMMIT);
+		oneBitmap.addObject(oid(6), Constants.OBJ_TREE);
+		oneBitmap.addObject(oid(5), Constants.OBJ_BLOB);
+
+		BitmapIndex.BitmapBuilder anotherBitmap = bb.newBitmapBuilder();
+		anotherBitmap.addObject(oid(7), Constants.OBJ_COMMIT);
+		anotherBitmap.addObject(oid(6), Constants.OBJ_TREE);
+		anotherBitmap.addObject(oid(5), Constants.OBJ_BLOB);
+
+		builder.processBitmapForWrite(
+				new BitmapCommit(oid(10), false, 0, false), oneBitmap, 0);
+		builder.processBitmapForWrite(new BitmapCommit(oid(7), false, 0, false),
+				oneBitmap, 0);
+		assertEquals(2, builder.getBitmapCount());
+
+		List<PackBitmapIndexBuilder.StoredEntry> ses = builder
+				.getCompressedBitmaps();
+		assertEquals(2, ses.size());
+		assertEquals(oid(7), ses.get(0).getObjectId());
+		assertEquals(6, ses.get(0).getIdxPosition());
+
+		assertEquals(oid(10), ses.get(1).getObjectId());
+		assertEquals(9, ses.get(1).getIdxPosition());
+	}
+
+	@Test
+	public void getObjectCount() {
+		assertEquals(10, createBuilder().getObjectCount());
+	}
+
+	private static void assertInBitmap(PackBitmapIndexBuilder builder,
+			EWAHCompressedBitmap bitmap, int oidAsInt) {
+		ObjectId oid = oid(oidAsInt);
+		int pos = builder.findPosition(oid);
+		assertTrue(pos >= 0);
+		assertTrue(bitmap.get(pos));
+	}
+
+	private static void assertNotInBitmap(PackBitmapIndexBuilder builder,
+			EWAHCompressedBitmap bitmap, int oidAsInt) {
+		ObjectId oid = oid(oidAsInt);
+		int pos = builder.findPosition(oid);
+		assertTrue(pos >= 0);
+		assertFalse(bitmap.get(pos));
+	}
+
+	private PackBitmapIndexBuilder createBuilder() {
+		ArrayList<ObjectToPack> objectsToPack = new ArrayList<>(opts);
+		Collections.reverse(objectsToPack);
+		return switch (currentSetup) {
+		case SINGLE_BUILDER -> setupSinglePackBitmapIndex(objectsToPack);
+		};
+	}
+
+	static PackBitmapIndexBuilder setupSinglePackBitmapIndex(
+			List<ObjectToPack> objectsToPack) {
+		PackBitmapIndexBuilder b = new PackBitmapIndexBuilder(objectsToPack);
+
+		BitmapIndex bi = new BitmapIndexImpl(b);
+		// Base commit (3, 2, 1)
+		BitmapIndex.BitmapBuilder bitmapOne = bi.newBitmapBuilder();
+		bitmapOne.addObject(oid(3), Constants.OBJ_COMMIT);
+		bitmapOne.addObject(oid(2), Constants.OBJ_TREE);
+		bitmapOne.addObject(oid(1), Constants.OBJ_BLOB);
+		b.addBitmap(oid(3), bitmapOne.build(), 0);
+
+		// Middle commit (7, 6, 5, 4) with base commit as parent
+		BitmapIndex.BitmapBuilder middleBitmap = bi.newBitmapBuilder();
+		middleBitmap.addObject(oid(7), Constants.OBJ_COMMIT);
+		middleBitmap.addObject(oid(6), Constants.OBJ_TREE);
+		middleBitmap.addObject(oid(5), Constants.OBJ_BLOB);
+		middleBitmap.addObject(oid(4), Constants.OBJ_BLOB);
+		middleBitmap.or(bitmapOne);
+		b.addBitmap(oid(7), middleBitmap, 0);
+
+		BitmapIndex.BitmapBuilder tipBitmap = bi.newBitmapBuilder();
+		tipBitmap.addObject(oid(10), Constants.OBJ_COMMIT);
+		tipBitmap.addObject(oid(9), Constants.OBJ_TREE);
+		tipBitmap.addObject(oid(8), Constants.OBJ_BLOB);
+		tipBitmap.or(middleBitmap);
+		b.addBitmap(oid(10), tipBitmap, 0);
+
+		return b;
+	}
+
+	private static ObjectToPack otp(int oid, long offset, int type) {
+		ObjectToPack otp = new ObjectToPack(oid(oid), type);
+		otp.setOffset(offset);
+		return otp;
+	}
+
+	private static ObjectId oid(int n) {
+		return ObjectId.fromRaw(new int[] { 0, 0, 0, 0, n });
+	}
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java
index baa0182..6552bac 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java
@@ -37,6 +37,7 @@
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
 
+import org.eclipse.jgit.api.PackRefsCommand;
 import org.eclipse.jgit.errors.LockFailedException;
 import org.eclipse.jgit.events.ListenerHandle;
 import org.eclipse.jgit.events.RefsChangedEvent;
@@ -44,6 +45,7 @@
 import org.eclipse.jgit.junit.Repeat;
 import org.eclipse.jgit.junit.TestRepository;
 import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.Ref.Storage;
 import org.eclipse.jgit.lib.RefDatabase;
@@ -1062,6 +1064,60 @@ public void test_repack() throws Exception {
 	}
 
 	@Test
+	public void testPackedRefsHeaderWithSorted() throws Exception {
+		writeLooseRef("refs/heads/master", A);
+		writeLooseRef("refs/heads/other", B);
+		writeLooseRef("refs/tags/v1.0", v1_0);
+
+		PackRefsCommand packRefsCommand = new PackRefsCommand(diskRepo);
+		packRefsCommand.setAll(true);
+		packRefsCommand.call();
+
+		File packedRefsFile = new File(diskRepo.getCommonDirectory(), Constants.PACKED_REFS);
+		assertTrue("packed-refs should exist", packedRefsFile.exists());
+
+		String content = read(packedRefsFile);
+		String firstLine = content.split("\n")[0];
+		assertTrue("packed-refs should have header with sorted",
+				firstLine.contains(" sorted"));
+
+		int masterIndex = content.indexOf(A.name() + " refs/heads/master");
+		int otherIndex = content.indexOf(B.name() + " refs/heads/other");
+		int tagIndex = content.indexOf(v1_0.name() + " refs/tags/v1.0");
+		assertTrue("packed-refs should be sorted",
+				masterIndex < otherIndex && otherIndex < tagIndex);
+	}
+
+	@Test
+	public void testPackedRefsUnsortedGetsSorted() throws Exception {
+		writePackedRefs("# pack-refs with: peeled \n" + //
+				B.name() + " refs/heads/other\n" + //
+				v1_0.name() + " refs/tags/v1.0\n" + //
+				"^" + v1_0.getObject().name() + "\n" + //
+				A.name() + " refs/heads/master\n");
+
+		// extra loose-ref to trigger packing
+		writeLooseRef("refs/heads/loose", A);
+
+		PackRefsCommand packRefsCommand = new PackRefsCommand(diskRepo);
+		packRefsCommand.setAll(true);
+		packRefsCommand.call();
+
+		File packedRefsFile = new File(diskRepo.getCommonDirectory(), Constants.PACKED_REFS);
+		String content = read(packedRefsFile);
+		int looseIndex = content.indexOf(v1_0.name() + " refs/tags/loose");
+		int masterIndex = content.indexOf(A.name() + " refs/heads/master");
+		int otherIndex = content.indexOf(B.name() + " refs/heads/other");
+		int tagIndex = content.indexOf(v1_0.name() + " refs/tags/v1.0");
+		assertTrue(
+				"packed-refs should be sorted",
+				looseIndex < masterIndex &&
+						masterIndex < otherIndex &&
+						otherIndex < tagIndex
+		);
+	}
+
+	@Test
 	public void testFindRef_EmptyDatabase() throws IOException {
 		Ref r;
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MultiPackIndexTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MultiPackIndexTest.java
index 6436e31..a2c86f3 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MultiPackIndexTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MultiPackIndexTest.java
@@ -11,6 +11,7 @@
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
@@ -20,6 +21,7 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Set;
@@ -81,36 +83,7 @@ public void basic_upstream() throws IOException {
 
 	@Test
 	public void basicMidx() throws IOException {
-		PackIndex idxOne = FakeIndexFactory.indexOf(List.of(
-				new FakeIndexFactory.IndexObject(
-						"0000000000000000000000000000000000000001", 500),
-				new FakeIndexFactory.IndexObject(
-						"0000000000000000000000000000000000000005", 12),
-				new FakeIndexFactory.IndexObject(
-						"0000000000000000000000000000000000000010", 1500)));
-		PackIndex idxTwo = FakeIndexFactory.indexOf(List.of(
-				new FakeIndexFactory.IndexObject(
-						"0000000000000000000000000000000000000002", 501),
-				new FakeIndexFactory.IndexObject(
-						"0000000000000000000000000000000000000003", 13),
-				new FakeIndexFactory.IndexObject(
-						"0000000000000000000000000000000000000015", 1501)));
-		PackIndex idxThree = FakeIndexFactory.indexOf(List.of(
-				new FakeIndexFactory.IndexObject(
-						"0000000000000000000000000000000000000004", 502),
-				new FakeIndexFactory.IndexObject(
-						"0000000000000000000000000000000000000007", 14),
-				new FakeIndexFactory.IndexObject(
-						"0000000000000000000000000000000000000012", 1502)));
-
-		LinkedHashMap<String, PackIndex> packs = orderedMapOf("p1", idxOne,
-				"p2", idxTwo, "p3", idxThree);
-		MultiPackIndexWriter writer = new MultiPackIndexWriter();
-		ByteArrayOutputStream out = new ByteArrayOutputStream();
-		writer.write(NullProgressMonitor.INSTANCE, out, packs);
-
-		MultiPackIndex midx = MultiPackIndexLoader
-				.read(new ByteArrayInputStream(out.toByteArray()));
+		MultiPackIndex midx = createMultiPackIndex();
 		assertEquals(3, midx.getPackNames().length);
 		assertInIndex(midx, 0, "0000000000000000000000000000000000000001", 500);
 		assertInIndex(midx, 0, "0000000000000000000000000000000000000005", 12);
@@ -126,6 +99,7 @@ public void basicMidx() throws IOException {
 				1502);
 
 		assertNull(midx.find(ObjectId.zeroId()));
+		assertNotNull(midx.getChecksum());
 	}
 
 	@Test
@@ -252,8 +226,8 @@ public void jgit_resolve_matchLimit() throws IOException {
 				// Match
 				"32fe829a1c000000000000000000000000000010");
 
-		LinkedHashMap<String, PackIndex> packs = orderedMapOf("p1", idxOne,
-				"p2", idxTwo);
+		LinkedHashMap<String, PackIndex> packs = orderedMapOf("r1", idxOne,
+				"r2", idxTwo);
 		MultiPackIndexWriter writer = new MultiPackIndexWriter();
 		ByteArrayOutputStream out = new ByteArrayOutputStream();
 		writer.write(NullProgressMonitor.INSTANCE, out, packs);
@@ -356,61 +330,31 @@ public void jgit_resolve_empty() throws IOException {
 
 	@Test
 	public void jgit_findPosition() throws IOException {
-		PackIndex idxOne = FakeIndexFactory.indexOf(List.of(
-				new FakeIndexFactory.IndexObject(
-						"0000000000000000000000000000000000000001", 500),
-				new FakeIndexFactory.IndexObject(
-						"0000000000000000000000000000000000000005", 12),
-				new FakeIndexFactory.IndexObject(
-						"0000000000000000000000000000000000000010", 1500)));
-		PackIndex idxTwo = FakeIndexFactory.indexOf(List.of(
-				new FakeIndexFactory.IndexObject(
-						"0000000000000000000000000000000000000002", 501),
-				new FakeIndexFactory.IndexObject(
-						"0000000000000000000000000000000000000003", 13),
-				new FakeIndexFactory.IndexObject(
-						"0000000000000000000000000000000000000015", 1501)));
-		PackIndex idxThree = FakeIndexFactory.indexOf(List.of(
-				new FakeIndexFactory.IndexObject(
-						"0000000000000000000000000000000000000004", 502),
-				new FakeIndexFactory.IndexObject(
-						"0000000000000000000000000000000000000007", 14),
-				new FakeIndexFactory.IndexObject(
-						"0000000000000000000000000000000000000012", 1502)));
-
-		LinkedHashMap<String, PackIndex> packs = orderedMapOf("p1", idxOne,
-				"p2", idxTwo, "p3", idxThree);
-		MultiPackIndexWriter writer = new MultiPackIndexWriter();
-		ByteArrayOutputStream out = new ByteArrayOutputStream();
-		writer.write(NullProgressMonitor.INSTANCE, out, packs);
-
-		MultiPackIndex midx = MultiPackIndexLoader
-				.read(new ByteArrayInputStream(out.toByteArray()));
+		MultiPackIndex midx = createMultiPackIndex();
 		assertEquals(3, midx.getPackNames().length);
-		assertEquals(0, midx.findPosition(ObjectId
-				.fromString("0000000000000000000000000000000000000001")));
-		assertEquals(1, midx.findPosition(ObjectId
-				.fromString("0000000000000000000000000000000000000002")));
-		assertEquals(2, midx.findPosition(ObjectId
-				.fromString("0000000000000000000000000000000000000003")));
-		assertEquals(3, midx.findPosition(ObjectId
-				.fromString("0000000000000000000000000000000000000004")));
-		assertEquals(4, midx.findPosition(ObjectId
-				.fromString("0000000000000000000000000000000000000005")));
-		assertEquals(5, midx.findPosition(ObjectId
-				.fromString("0000000000000000000000000000000000000007")));
-		assertEquals(6, midx.findPosition(ObjectId
-				.fromString("0000000000000000000000000000000000000010")));
-		assertEquals(7, midx.findPosition(ObjectId
-				.fromString("0000000000000000000000000000000000000012")));
-		assertEquals(8, midx.findPosition(ObjectId
-				.fromString("0000000000000000000000000000000000000015")));
+		assertEquals(0, midx.findPosition(oid("001")));
+		assertEquals(oid("001"), midx.getObjectAt(0));
+		assertEquals(1, midx.findPosition(oid("002")));
+		assertEquals(oid("002"), midx.getObjectAt(1));
+		assertEquals(2, midx.findPosition(oid("003")));
+		assertEquals(oid("003"), midx.getObjectAt(2));
+		assertEquals(3, midx.findPosition(oid("004")));
+		assertEquals(oid("004"), midx.getObjectAt(3));
+		assertEquals(4, midx.findPosition(oid("005")));
+		assertEquals(oid("005"), midx.getObjectAt(4));
+		assertEquals(5, midx.findPosition(oid("007")));
+		assertEquals(oid("007"), midx.getObjectAt(5));
+		assertEquals(6, midx.findPosition(oid("010")));
+		assertEquals(oid("010"), midx.getObjectAt(6));
+		assertEquals(7, midx.findPosition(oid("012")));
+		assertEquals(oid("012"), midx.getObjectAt(7));
+		assertEquals(8, midx.findPosition(oid("015")));
+		assertEquals(oid("015"), midx.getObjectAt(8));
 
 		assertNull(midx.find(ObjectId.zeroId()));
 	}
 
-	@Test
-	public void jgit_getObjectCount() throws IOException {
+	private static MultiPackIndex createMultiPackIndex() throws IOException {
 		PackIndex idxOne = FakeIndexFactory.indexOf(List.of(
 				new FakeIndexFactory.IndexObject(
 						"0000000000000000000000000000000000000001", 500),
@@ -439,8 +383,13 @@ public void jgit_getObjectCount() throws IOException {
 		ByteArrayOutputStream out = new ByteArrayOutputStream();
 		writer.write(NullProgressMonitor.INSTANCE, out, packs);
 
-		MultiPackIndex midx = MultiPackIndexLoader
+		return MultiPackIndexLoader
 				.read(new ByteArrayInputStream(out.toByteArray()));
+	}
+
+	@Test
+	public void jgit_getObjectCount() throws IOException {
+		MultiPackIndex midx = createMultiPackIndex();
 		assertEquals(9, midx.getObjectCount());
 	}
 
@@ -460,6 +409,224 @@ public void jgit_getObjectCount_emtpy() throws IOException {
 		assertEquals(0, midx.getObjectCount());
 	}
 
+	@Test
+	public void jgit_findBitmapPosition() throws IOException {
+		PackIndex idxOne = FakeIndexFactory.indexOf(List.of(
+				new FakeIndexFactory.IndexObject(
+						"0000000000000000000000000000000000000001", 500),
+				new FakeIndexFactory.IndexObject(
+						"0000000000000000000000000000000000000005", 12),
+				new FakeIndexFactory.IndexObject(
+						"0000000000000000000000000000000000000010", 1500)));
+		PackIndex idxTwo = FakeIndexFactory.indexOf(List.of(
+				new FakeIndexFactory.IndexObject(
+						"0000000000000000000000000000000000000002", 501),
+				new FakeIndexFactory.IndexObject(
+						"0000000000000000000000000000000000000003", 13),
+				new FakeIndexFactory.IndexObject(
+						"0000000000000000000000000000000000000015", 1501)));
+		PackIndex idxThree = FakeIndexFactory.indexOf(List.of(
+				new FakeIndexFactory.IndexObject(
+						"0000000000000000000000000000000000000004", 502),
+				new FakeIndexFactory.IndexObject(
+						"0000000000000000000000000000000000000007", 14),
+				new FakeIndexFactory.IndexObject(
+						"0000000000000000000000000000000000000012", 1502)));
+
+		LinkedHashMap<String, PackIndex> packs = orderedMapOf("p1", idxOne,
+				"p2", idxTwo, "p3", idxThree);
+		MultiPackIndexWriter writer = new MultiPackIndexWriter();
+		ByteArrayOutputStream out = new ByteArrayOutputStream();
+		writer.write(NullProgressMonitor.INSTANCE, out, packs);
+
+		MultiPackIndex midx = MultiPackIndexLoader
+				.read(new ByteArrayInputStream(out.toByteArray()));
+		MultiPackIndex.PackOffset packOffset;
+		packOffset = midx.find(ObjectId
+				.fromString("0000000000000000000000000000000000000005"));
+		assertEquals(0, midx.findBitmapPosition(packOffset));
+		packOffset = midx.find(ObjectId
+				.fromString("0000000000000000000000000000000000000001"));
+		assertEquals(1, midx.findBitmapPosition(packOffset));
+		packOffset = midx.find(ObjectId
+				.fromString("0000000000000000000000000000000000000010"));
+		assertEquals(2, midx.findBitmapPosition(packOffset));
+		packOffset = midx.find(ObjectId
+				.fromString("0000000000000000000000000000000000000003"));
+		assertEquals(3, midx.findBitmapPosition(packOffset));
+		packOffset = midx.find(ObjectId
+				.fromString("0000000000000000000000000000000000000002"));
+		assertEquals(4, midx.findBitmapPosition(packOffset));
+		packOffset = midx.find(ObjectId
+				.fromString("0000000000000000000000000000000000000015"));
+		assertEquals(5, midx.findBitmapPosition(packOffset));
+		packOffset = midx.find(ObjectId
+				.fromString("0000000000000000000000000000000000000007"));
+		assertEquals(6, midx.findBitmapPosition(packOffset));
+		packOffset = midx.find(ObjectId
+				.fromString("0000000000000000000000000000000000000004"));
+		assertEquals(7, midx.findBitmapPosition(packOffset));
+		packOffset = midx.find(ObjectId
+				.fromString("0000000000000000000000000000000000000012"));
+		assertEquals(8, midx.findBitmapPosition(packOffset));
+	}
+
+	@Test
+	public void jgit_getObjectAtBitmapPosition() throws IOException {
+		PackIndex idxOne = FakeIndexFactory.indexOf(List.of(
+				new FakeIndexFactory.IndexObject(
+						"0000000000000000000000000000000000000001", 500),
+				new FakeIndexFactory.IndexObject(
+						"0000000000000000000000000000000000000005", 12),
+				new FakeIndexFactory.IndexObject(
+						"0000000000000000000000000000000000000010", 1500)));
+		PackIndex idxTwo = FakeIndexFactory.indexOf(List.of(
+				new FakeIndexFactory.IndexObject(
+						"0000000000000000000000000000000000000002", 501),
+				new FakeIndexFactory.IndexObject(
+						"0000000000000000000000000000000000000003", 13),
+				new FakeIndexFactory.IndexObject(
+						"0000000000000000000000000000000000000015", 1501)));
+		PackIndex idxThree = FakeIndexFactory.indexOf(List.of(
+				new FakeIndexFactory.IndexObject(
+						"0000000000000000000000000000000000000004", 502),
+				new FakeIndexFactory.IndexObject(
+						"0000000000000000000000000000000000000007", 14),
+				new FakeIndexFactory.IndexObject(
+						"0000000000000000000000000000000000000012", 1502)));
+
+		LinkedHashMap<String, PackIndex> packs = orderedMapOf("p1", idxOne,
+				"p2", idxTwo, "p3", idxThree);
+		MultiPackIndexWriter writer = new MultiPackIndexWriter();
+		ByteArrayOutputStream out = new ByteArrayOutputStream();
+		writer.write(NullProgressMonitor.INSTANCE, out, packs);
+
+		MultiPackIndex midx = MultiPackIndexLoader
+				.read(new ByteArrayInputStream(out.toByteArray()));
+		assertEquals(
+				ObjectId.fromString("0000000000000000000000000000000000000005"),
+				midx.getObjectAtBitmapPosition(0));
+		assertEquals(
+				ObjectId.fromString("0000000000000000000000000000000000000001"),
+				midx.getObjectAtBitmapPosition(1));
+		assertEquals(
+				ObjectId.fromString("0000000000000000000000000000000000000010"),
+				midx.getObjectAtBitmapPosition(2));
+		assertEquals(
+				ObjectId.fromString("0000000000000000000000000000000000000003"),
+				midx.getObjectAtBitmapPosition(3));
+		assertEquals(
+				ObjectId.fromString("0000000000000000000000000000000000000002"),
+				midx.getObjectAtBitmapPosition(4));
+		assertEquals(
+				ObjectId.fromString("0000000000000000000000000000000000000015"),
+				midx.getObjectAtBitmapPosition(5));
+		assertEquals(
+				ObjectId.fromString("0000000000000000000000000000000000000007"),
+				midx.getObjectAtBitmapPosition(6));
+		assertEquals(
+				ObjectId.fromString("0000000000000000000000000000000000000004"),
+				midx.getObjectAtBitmapPosition(7));
+		assertEquals(
+				ObjectId.fromString("0000000000000000000000000000000000000012"),
+				midx.getObjectAtBitmapPosition(8));
+	}
+
+	@Test
+	public void jgit_iterator() throws IOException {
+		MultiPackIndex midx = createMultiPackIndex();
+		assertEquals(3, midx.getPackNames().length);
+		Iterator<MultiPackIndex.MutableEntry> iterator = midx.iterator();
+		assertNextEntry(iterator, "0000000000000000000000000000000000000001", 0,
+				500);
+		assertNextEntry(iterator, "0000000000000000000000000000000000000002", 1,
+				501);
+		assertNextEntry(iterator, "0000000000000000000000000000000000000003", 1,
+				13);
+		assertNextEntry(iterator, "0000000000000000000000000000000000000004", 2,
+				502);
+		assertNextEntry(iterator, "0000000000000000000000000000000000000005", 0,
+				12);
+		assertNextEntry(iterator, "0000000000000000000000000000000000000007", 2,
+				14);
+		assertNextEntry(iterator, "0000000000000000000000000000000000000010", 0,
+				1500);
+		assertNextEntry(iterator, "0000000000000000000000000000000000000012", 2,
+				1502);
+		assertNextEntry(iterator, "0000000000000000000000000000000000000015", 1,
+				1501);
+		assertFalse(iterator.hasNext());
+	}
+
+	@Test
+	public void jgit_iterator_emtpy() throws IOException {
+		PackIndex idxOne = FakeIndexFactory.indexOf(List.of());
+		PackIndex idxTwo = FakeIndexFactory.indexOf(List.of());
+
+		LinkedHashMap<String, PackIndex> packs = orderedMapOf("p1", idxOne,
+				"p2", idxTwo);
+		MultiPackIndexWriter writer = new MultiPackIndexWriter();
+		ByteArrayOutputStream out = new ByteArrayOutputStream();
+		writer.write(NullProgressMonitor.INSTANCE, out, packs);
+		MultiPackIndex midx = MultiPackIndexLoader
+				.read(new ByteArrayInputStream(out.toByteArray()));
+
+		assertFalse(midx.iterator().hasNext());
+	}
+
+	@Test
+	public void jgit_iterator_peek() throws IOException {
+		PackIndex idxOne = FakeIndexFactory.indexOf(List.of(
+				new FakeIndexFactory.IndexObject(
+						"0000000000000000000000000000000000000001", 500),
+				new FakeIndexFactory.IndexObject(
+						"0000000000000000000000000000000000000005", 12),
+				new FakeIndexFactory.IndexObject(
+						"0000000000000000000000000000000000000010", 1500)));
+		PackIndex idxTwo = FakeIndexFactory.indexOf(List.of(
+				new FakeIndexFactory.IndexObject(
+						"0000000000000000000000000000000000000002", 501),
+				new FakeIndexFactory.IndexObject(
+						"0000000000000000000000000000000000000003", 13),
+				new FakeIndexFactory.IndexObject(
+						"0000000000000000000000000000000000000015", 1501)));
+
+		LinkedHashMap<String, PackIndex> packs = orderedMapOf("p1", idxOne,
+				"p2", idxTwo);
+		MultiPackIndexWriter writer = new MultiPackIndexWriter();
+		ByteArrayOutputStream out = new ByteArrayOutputStream();
+		writer.write(NullProgressMonitor.INSTANCE, out, packs);
+
+		MultiPackIndex midx = MultiPackIndexLoader
+				.read(new ByteArrayInputStream(out.toByteArray()));
+		assertEquals(2, midx.getPackNames().length);
+		MultiPackIndex.MidxIterator iterator = midx.iterator();
+		assertNextEntry(iterator, "0000000000000000000000000000000000000001", 0,
+				500);
+		assertNextEntry(iterator, "0000000000000000000000000000000000000002", 1,
+				501);
+		assertTrue(iterator.hasNext());
+		assertEntry(iterator.peek(), "0000000000000000000000000000000000000003",
+				1, 13);
+		assertEntry(iterator.peek(), "0000000000000000000000000000000000000003",
+				1, 13);
+		assertNextEntry(iterator, "0000000000000000000000000000000000000003", 1,
+				13);
+		assertNextEntry(iterator, "0000000000000000000000000000000000000005", 0,
+				12);
+		assertNextEntry(iterator, "0000000000000000000000000000000000000010", 0,
+				1500);
+		assertNextEntry(iterator, "0000000000000000000000000000000000000015", 1,
+				1501);
+		assertFalse(iterator.hasNext());
+	}
+
+	@Test
+	public void jgit_iterator_getPackNames() throws IOException {
+		MultiPackIndex midx = createMultiPackIndex();
+		assertEquals(3, midx.iterator().getPackNames().size());
+	}
+
 	private static PackIndex indexWith(String... oids) {
 		List<FakeIndexFactory.IndexObject> idxObjs = new ArrayList<>(
 				oids.length);
@@ -481,6 +648,20 @@ private static void assertInIndex(MultiPackIndex midx, int expectedPackId,
 		assertEquals(expectedOffset, packOffset.getOffset());
 	}
 
+	private static void assertNextEntry(
+			Iterator<MultiPackIndex.MutableEntry> it, String oid,
+			int expectedPackId, long expectedOffset) {
+		assertTrue(it.hasNext());
+		assertEntry(it.next(), oid, expectedPackId, expectedOffset);
+	}
+
+	private static void assertEntry(MultiPackIndex.MutableEntry e, String oid,
+			int expectedPackId, long expectedOffset) {
+		assertEquals(oid, e.oid.name());
+		assertEquals(expectedPackId, e.packOffset.getPackId());
+		assertEquals(expectedOffset, e.packOffset.getOffset());
+	}
+
 	private static LinkedHashMap<String, PackIndex> orderedMapOf(String s1,
 			PackIndex pi1, String s2, PackIndex pi2) {
 		LinkedHashMap<String, PackIndex> map = new LinkedHashMap<>(2);
@@ -491,10 +672,16 @@ private static LinkedHashMap<String, PackIndex> orderedMapOf(String s1,
 
 	private static LinkedHashMap<String, PackIndex> orderedMapOf(String s1,
 			PackIndex pi1, String s2, PackIndex pi2, String s3, PackIndex pi3) {
-		LinkedHashMap<String, PackIndex> map = new LinkedHashMap<>(2);
+		LinkedHashMap<String, PackIndex> map = new LinkedHashMap<>(3);
 		map.put(s1, pi1);
 		map.put(s2, pi2);
 		map.put(s3, pi3);
 		return map;
 	}
+
+	private static ObjectId oid(String last3chars) {
+		assertEquals(3, last3chars.length());
+		return ObjectId.fromString(
+				"0000000000000000000000000000000000000" + last3chars);
+	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MultiPackIndexWriterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MultiPackIndexWriterTest.java
index 9b085a3..5971dceb 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MultiPackIndexWriterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MultiPackIndexWriterTest.java
@@ -10,6 +10,7 @@
 package org.eclipse.jgit.internal.storage.midx;
 
 import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.CHUNK_LOOKUP_WIDTH;
+import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.MIDX_CHUNKID_BITMAPPEDPACKS;
 import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.MIDX_CHUNKID_LARGEOFFSETS;
 import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.MIDX_CHUNKID_OBJECTOFFSETS;
 import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.MIDX_CHUNKID_OIDFANOUT;
@@ -54,21 +55,23 @@ public void write_allSmallOffsets() throws IOException {
 		ByteArrayOutputStream out = new ByteArrayOutputStream();
 		writer.write(NullProgressMonitor.INSTANCE, out, data);
 		// header (12 bytes)
-		// + chunkHeader (6 * 12 bytes)
+		// + chunkHeader (7 * 12 bytes)
 		// + fanout table (256 * 4 bytes)
 		// + OIDs (6 * 20 bytes)
 		// + (pack, offset) pairs (6 * 8)
 		// + RIDX (6 * 4 bytes)
+		// + bitmap pack segments (2 * 8)
 		// + packfile names (2 * 10)
 		// + checksum (20)
-		assertEquals(1340, out.size());
+		assertEquals(1368, out.size());
 		List<Integer> chunkIds = readChunkIds(out);
-		assertEquals(5, chunkIds.size());
+		assertEquals(6, chunkIds.size());
 		assertEquals(0, chunkIds.indexOf(MIDX_CHUNKID_OIDFANOUT));
 		assertEquals(1, chunkIds.indexOf(MIDX_CHUNKID_OIDLOOKUP));
 		assertEquals(2, chunkIds.indexOf(MIDX_CHUNKID_OBJECTOFFSETS));
 		assertEquals(3, chunkIds.indexOf(MIDX_CHUNKID_REVINDEX));
-		assertEquals(4, chunkIds.indexOf(MIDX_CHUNKID_PACKNAMES));
+		assertEquals(4, chunkIds.indexOf(MIDX_CHUNKID_BITMAPPEDPACKS));
+		assertEquals(5, chunkIds.indexOf(MIDX_CHUNKID_PACKNAMES));
 	}
 
 	@Test
@@ -90,21 +93,23 @@ public void write_smallOffset_limit() throws IOException {
 		ByteArrayOutputStream out = new ByteArrayOutputStream();
 		writer.write(NullProgressMonitor.INSTANCE, out, data);
 		// header (12 bytes)
-		// + chunkHeader (6 * 12 bytes)
+		// + chunkHeader (7 * 12 bytes)
 		// + fanout table (256 * 4 bytes)
 		// + OIDs (6 * 20 bytes)
 		// + (pack, offset) pairs (6 * 8)
 		// + RIDX (6 * 4 bytes)
+		// + bitmap pack segments (2 * 8)
 		// + packfile names (2 * 10)
 		// + checksum (20)
-		assertEquals(1340, out.size());
+		assertEquals(1368, out.size());
 		List<Integer> chunkIds = readChunkIds(out);
-		assertEquals(5, chunkIds.size());
+		assertEquals(6, chunkIds.size());
 		assertEquals(0, chunkIds.indexOf(MIDX_CHUNKID_OIDFANOUT));
 		assertEquals(1, chunkIds.indexOf(MIDX_CHUNKID_OIDLOOKUP));
 		assertEquals(2, chunkIds.indexOf(MIDX_CHUNKID_OBJECTOFFSETS));
 		assertEquals(3, chunkIds.indexOf(MIDX_CHUNKID_REVINDEX));
-		assertEquals(4, chunkIds.indexOf(MIDX_CHUNKID_PACKNAMES));
+		assertEquals(4, chunkIds.indexOf(MIDX_CHUNKID_BITMAPPEDPACKS));
+		assertEquals(5, chunkIds.indexOf(MIDX_CHUNKID_PACKNAMES));
 	}
 
 	@Test
@@ -126,23 +131,25 @@ public void write_largeOffset() throws IOException {
 		MultiPackIndexWriter.Result result = writer
 				.write(NullProgressMonitor.INSTANCE, out, data);
 		// header (12 bytes)
-		// + chunkHeader (7 * 12 bytes)
+		// + chunkHeader (8 * 12 bytes)
 		// + fanout table (256 * 4 bytes)
 		// + OIDs (6 * 20 bytes)
 		// + (pack, offset) pairs (6 * 8)
 		// + (large-offset) (1 * 8)
 		// + RIDX (6 * 4 bytes)
+		// + bitmap pack segments (2 * 8)
 		// + packfile names (2 * 10)
 		// + checksum (20)
-		assertEquals(1360, out.size());
+		assertEquals(1388, out.size());
 		List<Integer> chunkIds = readChunkIds(out);
-		assertEquals(6, chunkIds.size());
+		assertEquals(7, chunkIds.size());
 		assertEquals(0, chunkIds.indexOf(MIDX_CHUNKID_OIDFANOUT));
 		assertEquals(1, chunkIds.indexOf(MIDX_CHUNKID_OIDLOOKUP));
 		assertEquals(2, chunkIds.indexOf(MIDX_CHUNKID_OBJECTOFFSETS));
 		assertEquals(3, chunkIds.indexOf(MIDX_CHUNKID_LARGEOFFSETS));
 		assertEquals(4, chunkIds.indexOf(MIDX_CHUNKID_REVINDEX));
-		assertEquals(5, chunkIds.indexOf(MIDX_CHUNKID_PACKNAMES));
+		assertEquals(5, chunkIds.indexOf(MIDX_CHUNKID_BITMAPPEDPACKS));
+		assertEquals(6, chunkIds.indexOf(MIDX_CHUNKID_PACKNAMES));
 
 		assertEquals("bbbbbbbbb", result.packNames().get(0));
 		assertEquals("aaaaaaaaa", result.packNames().get(1));
@@ -159,13 +166,14 @@ public void jgit_emptyMidx() throws IOException {
 		ByteArrayOutputStream out = new ByteArrayOutputStream();
 		writer.write(NullProgressMonitor.INSTANCE, out, packs);
 		List<Integer> chunkIds = readChunkIds(out);
-		assertEquals(1134, out.size());
-		assertEquals(5, chunkIds.size());
+		assertEquals(1162, out.size());
+		assertEquals(6, chunkIds.size());
 		assertEquals(0, chunkIds.indexOf(MIDX_CHUNKID_OIDFANOUT));
 		assertEquals(1, chunkIds.indexOf(MIDX_CHUNKID_OIDLOOKUP));
 		assertEquals(2, chunkIds.indexOf(MIDX_CHUNKID_OBJECTOFFSETS));
 		assertEquals(3, chunkIds.indexOf(MIDX_CHUNKID_REVINDEX));
-		assertEquals(4, chunkIds.indexOf(MIDX_CHUNKID_PACKNAMES));
+		assertEquals(4, chunkIds.indexOf(MIDX_CHUNKID_BITMAPPEDPACKS));
+		assertEquals(5, chunkIds.indexOf(MIDX_CHUNKID_PACKNAMES));
 	}
 
 	private List<Integer> readChunkIds(ByteArrayOutputStream out) {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/PackIndexMergerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/PackIndexMergerTest.java
index 0eafdaf..a43992d 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/PackIndexMergerTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/PackIndexMergerTest.java
@@ -9,6 +9,7 @@
  */
 package org.eclipse.jgit.internal.storage.midx;
 
+import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -254,6 +255,65 @@ public void bySha1Iterator_largeOffsets_noChunk() {
 		assertEquals(3, merger.getUniqueObjectCount());
 	}
 
+	@Test
+	public void getObjectsPerPack_noDuplicates() {
+		PackIndex idxOne = indexOf(
+				oidOffset("0000000000000000000000000000000000000001", 500),
+				oidOffset("0000000000000000000000000000000000000005", 12),
+				oidOffset("0000000000000000000000000000000000000010", 1500));
+		PackIndex idxTwo = indexOf(
+				oidOffset("0000000000000000000000000000000000000002", 501),
+				oidOffset("0000000000000000000000000000000000000003", 13),
+				oidOffset("0000000000000000000000000000000000000015", 1501));
+		PackIndex idxThree = indexOf(
+				oidOffset("0000000000000000000000000000000000000004", 502),
+				oidOffset("0000000000000000000000000000000000000007", 14),
+				oidOffset("0000000000000000000000000000000000000012", 1502));
+		PackIndexMerger merger = new PackIndexMerger(
+				orderedMapOf("p1", idxOne, "p2", idxTwo, "p3", idxThree));
+		assertArrayEquals(new int[] { 3, 3, 3 }, merger.getObjectsPerPack());
+	}
+
+	@Test
+	public void getObjectsPerPack_differentIndexSizes() {
+		PackIndex idxOne = indexOf(
+				oidOffset("0000000000000000000000000000000000000010", 1500));
+		PackIndex idxTwo = indexOf(
+				oidOffset("0000000000000000000000000000000000000002", 500),
+				oidOffset("0000000000000000000000000000000000000003", 12));
+		PackIndex idxThree = indexOf(
+				oidOffset("0000000000000000000000000000000000000004", 500),
+				oidOffset("0000000000000000000000000000000000000007", 12),
+				oidOffset("0000000000000000000000000000000000000012", 1500));
+		PackIndexMerger merger = new PackIndexMerger(
+				orderedMapOf("p1", idxOne, "p2", idxTwo, "p3", idxThree));
+		assertArrayEquals(new int[] { 1, 2, 3 }, merger.getObjectsPerPack());
+	}
+
+	@Test
+	public void getObjectsPerPack_allDuplicates() {
+		PackIndex idxOne = indexOf(
+				oidOffset("0000000000000000000000000000000000000001", 500),
+				oidOffset("0000000000000000000000000000000000000005", 12),
+				oidOffset("0000000000000000000000000000000000000010", 1500));
+		PackIndexMerger merger = new PackIndexMerger(
+				orderedMapOf("p1", idxOne, "p2", idxOne, "p3", idxOne));
+		assertArrayEquals(new int[] { 3, 0, 0 }, merger.getObjectsPerPack());
+	}
+
+	@Test
+	public void getObjectsPerPack_noIndexes() {
+		PackIndexMerger merger = new PackIndexMerger(new LinkedHashMap<>());
+		assertArrayEquals(new int[] {}, merger.getObjectsPerPack());
+	}
+
+	@Test
+	public void getObjectsPerPack_emptyIndexes() {
+		PackIndexMerger merger = new PackIndexMerger(
+				orderedMapOf("p1", indexOf(), "p2", indexOf()));
+		assertArrayEquals(new int[] { 0, 0 }, merger.getObjectsPerPack());
+	}
+
 	private static void assertNextEntry(
 			Iterator<PackIndexMerger.MidxMutableEntry> it, String oid,
 			int packId, long offset) {
diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
index e0f593a..8889d75 100644
--- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
+++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
@@ -788,6 +788,7 @@
 tagAlreadyExists=tag ''{0}'' already exists
 tagNameInvalid=tag name {0} is invalid
 tagOnRepoWithoutHEADCurrentlyNotSupported=Tag on repository without HEAD currently not supported
+temporaryBufferIsDestroyed=The TemporaryBuffer was destroyed and can't be used anymore.
 theFactoryMustNotBeNull=The factory must not be null
 threadInterruptedWhileRunning="Current thread interrupted while running {0}"
 timeIsUncertain=Time is uncertain
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/GarbageCollectCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/GarbageCollectCommand.java
index f6935e1..a16be79 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/GarbageCollectCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/GarbageCollectCommand.java
@@ -26,6 +26,7 @@
 import org.eclipse.jgit.internal.storage.file.GC;
 import org.eclipse.jgit.internal.storage.file.GC.RepoStatistics;
 import org.eclipse.jgit.lib.ConfigConstants;
+import org.eclipse.jgit.lib.GcConfig;
 import org.eclipse.jgit.lib.ProgressMonitor;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.lib.StoredConfig;
@@ -66,6 +67,8 @@ public class GarbageCollectCommand extends GitCommand<Properties> {
 
 	private Boolean packKeptObjects;
 
+	private GcConfig gcConfig;
+
 	/**
 	 * Constructor for GarbageCollectCommand.
 	 *
@@ -75,6 +78,7 @@ public class GarbageCollectCommand extends GitCommand<Properties> {
 	protected GarbageCollectCommand(Repository repo) {
 		super(repo);
 		pconfig = new PackConfig(repo);
+		gcConfig = repo.getConfig().get(GcConfig.KEY);
 	}
 
 	/**
@@ -200,6 +204,19 @@ public GarbageCollectCommand setPrunePreserved(boolean prunePreserved) {
 		return this;
 	}
 
+	/**
+	 * Set the gc configuration
+	 *
+	 * @param gcConfig
+	 *            the gc configuration
+	 * @return {@code this}
+	 * @since 7.6
+	 */
+	public GarbageCollectCommand setGcConfig(GcConfig gcConfig) {
+		this.gcConfig = gcConfig;
+		return this;
+	}
+
 	@Override
 	public Properties call() throws GitAPIException {
 		checkCallable();
@@ -214,6 +231,7 @@ public Properties call() throws GitAPIException {
 				if (this.packKeptObjects != null) {
 					gc.setPackKeptObjects(packKeptObjects.booleanValue());
 				}
+				gc.setGcConfig(gcConfig);
 				try {
 					gc.gc().get();
 					return toProperties(gc.getStatistics());
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
index 539d00e..1f49629 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
@@ -818,6 +818,7 @@ public static JGitText get() {
 	/***/ public String tagAlreadyExists;
 	/***/ public String tagNameInvalid;
 	/***/ public String tagOnRepoWithoutHEADCurrentlyNotSupported;
+	/***/ public String temporaryBufferIsDestroyed;
 	/***/ public String timeoutMeasureFsTimestampResolution;
 	/***/ public String transactionAborted;
 	/***/ public String theFactoryMustNotBeNull;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsMidxWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsMidxWriter.java
index 28ef98d..654bc30 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsMidxWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsMidxWriter.java
@@ -15,15 +15,27 @@
 import static org.eclipse.jgit.internal.storage.pack.PackExt.MULTI_PACK_INDEX;
 
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
 import java.util.function.Function;
 
 import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.internal.storage.file.PackBitmapIndexBuilder;
 import org.eclipse.jgit.internal.storage.file.PackIndex;
 import org.eclipse.jgit.internal.storage.midx.MultiPackIndexWriter;
+import org.eclipse.jgit.internal.storage.pack.PackBitmapCalculator;
+import org.eclipse.jgit.internal.storage.pack.PackBitmapIndexWriter;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.NullProgressMonitor;
+import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ProgressMonitor;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.storage.pack.PackConfig;
 
 /**
  * Create a pack with a multipack index, setting the required fields in the
@@ -35,6 +47,30 @@ private DfsMidxWriter() {
 	}
 
 	/**
+	 * Create a pack with the multipack index (without bitmaps).
+	 *
+	 * @param pm
+	 *            a progress monitor
+	 * @param objdb
+	 *            an object database
+	 * @param packs
+	 *            the packs to cover
+	 * @param base
+	 *            parent of this midx in the chain (if any).
+	 *
+	 * @return a pack (uncommitted) with the multipack index of the packs passed
+	 *         as parameter.
+	 * @throws IOException
+	 *             an error opening the packs or writing the stream.
+	 */
+	public static DfsPackDescription writeMidx(ProgressMonitor pm,
+			DfsObjDatabase objdb, List<DfsPackFile> packs,
+			@Nullable DfsPackDescription base) throws IOException {
+		return writeMidx(pm, objdb, packs, base,
+				new PackConfig(objdb.getRepository()));
+	}
+
+	/**
 	 * Create a pack with the multipack index
 	 *
 	 * @param pm
@@ -45,6 +81,8 @@ private DfsMidxWriter() {
 	 *            the packs to cover
 	 * @param base
 	 *            parent of this midx in the chain (if any).
+	 * @param packConfig
+	 *            pack config with the parameters to write bitmaps.
 	 * @return a pack (uncommitted) with the multipack index of the packs passed
 	 *         as parameter.
 	 * @throws IOException
@@ -52,7 +90,8 @@ private DfsMidxWriter() {
 	 */
 	public static DfsPackDescription writeMidx(ProgressMonitor pm,
 			DfsObjDatabase objdb, List<DfsPackFile> packs,
-			@Nullable DfsPackDescription base) throws IOException {
+			@Nullable DfsPackDescription base, PackConfig packConfig)
+			throws IOException {
 		LinkedHashMap<String, PackIndex> inputs = new LinkedHashMap<>(
 				packs.size());
 		try (DfsReader ctx = objdb.newReader()) {
@@ -68,6 +107,7 @@ public static DfsPackDescription writeMidx(ProgressMonitor pm,
 			MultiPackIndexWriter w = new MultiPackIndexWriter();
 			MultiPackIndexWriter.Result result = w.write(pm, out, inputs);
 			midxPackDesc.addFileExt(MULTI_PACK_INDEX);
+			midxPackDesc.setFileSize(MULTI_PACK_INDEX, result.bytesWritten());
 			midxPackDesc.setObjectCount(result.objectCount());
 
 			Map<String, DfsPackDescription> byName = packs.stream()
@@ -82,6 +122,52 @@ public static DfsPackDescription writeMidx(ProgressMonitor pm,
 			}
 		}
 
+		// TODO(ifrade): At the moment write bitmaps only in the bottom midx.
+		// A single-pack midx in the base should be covering only GC. No
+		// need to write midx bitmaps (we will use GC bitmaps).
+		if (base == null && midxPackDesc.getCoveredPacks().size() > 1) {
+			createAndAttachBitmaps(objdb.getRepository(), midxPackDesc,
+					packConfig);
+		}
+
 		return midxPackDesc;
 	}
+
+	private static void createAndAttachBitmaps(DfsRepository db,
+			DfsPackDescription desc, PackConfig cfg) throws IOException {
+
+		DfsObjDatabase objdb = db.getObjectDatabase();
+		// We need a DfsPackFile to reread the contents
+		DfsPackFileMidx midxPack = db.getObjectDatabase().createDfsPackFileMidx(
+				DfsBlockCache.getInstance(), desc, new ArrayList<>());
+
+		// TODO(ifrade): Verify we duplicate the behaviour about tags of regular
+		// bitmapping
+		List<ObjectId> allHeads = db.getRefDatabase()
+				.getRefsByPrefix(Constants.R_HEADS).stream()
+				.map(r -> r.getObjectId()).filter(Objects::nonNull).toList();
+		if (allHeads.isEmpty()) {
+			return;
+		}
+
+		try (DfsReader ctx = objdb.newReader()) {
+			RefAdvancerWalk adv = new RefAdvancerWalk(db,
+					c -> midxPack.hasObject(ctx, c));
+			Set<RevCommit> inPack = adv.advance(allHeads);
+
+			byte[] checksum = midxPack.getChecksum(ctx);
+			PackBitmapIndexBuilder writeBitmaps = new PackBitmapIndexBuilder(
+					midxPack.getLocalObjects(ctx));
+			int commitCount = writeBitmaps.getCommits().cardinality();
+
+			PackBitmapCalculator calculator = new PackBitmapCalculator(cfg);
+			// This will do ctx.getBitmapIndex() to reuse/copy previous bitmaps
+			calculator.calculate(ctx, NullProgressMonitor.INSTANCE, commitCount,
+					inPack, new HashSet<>(), writeBitmaps);
+			PackBitmapIndexWriter pbiWriter = db.getObjectDatabase()
+					.getPackBitmapIndexWriter(desc);
+			pbiWriter.write(writeBitmaps, checksum);
+		}
+	}
+
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java
index ecc97e9..4997b90 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java
@@ -241,20 +241,6 @@ void setPackIndex(PackIndex idx) {
 	}
 
 	/**
-	 * Get the PackIndex for this PackFile.
-	 *
-	 * @param ctx
-	 *            reader context to support reading from the backing store if
-	 *            the index is not already loaded in memory.
-	 * @return the PackIndex.
-	 * @throws java.io.IOException
-	 *             the pack index is not available, or is corrupt.
-	 */
-	public PackIndex getPackIndex(DfsReader ctx) throws IOException {
-		return idx(ctx);
-	}
-
-	/**
 	 * Get a view of this packfile as a set of objects
 	 * <p>
 	 * To use when the caller only needs to check inclusion (without specific
@@ -267,10 +253,20 @@ public PackIndex getPackIndex(DfsReader ctx) throws IOException {
 	 *             cannot load the backing data from storage
 	 */
 	public ObjectIdSet asObjectIdSet(DfsReader ctx) throws IOException {
-		return idx(ctx);
+		return getPackIndex(ctx);
 	}
 
-	private PackIndex idx(DfsReader ctx) throws IOException {
+	/**
+	 * Get the PackIndex for this PackFile.
+	 *
+	 * @param ctx
+	 *            reader context to support reading from the backing store if
+	 *            the index is not already loaded in memory.
+	 * @return the PackIndex.
+	 * @throws java.io.IOException
+	 *             the pack index is not available, or is corrupt.
+	 */
+	public PackIndex getPackIndex(DfsReader ctx) throws IOException {
 		if (index != null) {
 			return index;
 		}
@@ -399,7 +395,8 @@ public PackReverseIndex getReverseIdx(DfsReader ctx) throws IOException {
 			return reverseIndex;
 		}
 
-		reverseIndex = indexFactory.getPackIndexes().reverseIndex(ctx, idx(ctx));
+		reverseIndex = indexFactory.getPackIndexes().reverseIndex(ctx,
+				getPackIndex(ctx));
 		if (reverseIndex == null) {
 			throw new IOException(
 					"Couldn't get a reference to the reverse index"); //$NON-NLS-1$
@@ -460,12 +457,12 @@ private PackObjectSizeIndex getObjectSizeIndex(DfsReader ctx)
 	 *             the pack index is not available, or is corrupt.
 	 */
 	public boolean hasObject(DfsReader ctx, AnyObjectId id) throws IOException {
-		final long offset = idx(ctx).findOffset(id);
+		final long offset = getPackIndex(ctx).findOffset(id);
 		return 0 < offset && !isCorrupt(offset);
 	}
 
 	int findIdxPosition(DfsReader ctx, AnyObjectId id) throws IOException {
-		return idx(ctx).findPosition(id);
+		return getPackIndex(ctx).findPosition(id);
 	}
 
 	/**
@@ -482,12 +479,12 @@ int findIdxPosition(DfsReader ctx, AnyObjectId id) throws IOException {
 	 */
 	ObjectLoader get(DfsReader ctx, AnyObjectId id)
 			throws IOException {
-		long offset = idx(ctx).findOffset(id);
+		long offset = getPackIndex(ctx).findOffset(id);
 		return 0 < offset && !isCorrupt(offset) ? load(ctx, offset) : null;
 	}
 
 	long findOffset(DfsReader ctx, AnyObjectId id) throws IOException {
-		return idx(ctx).findOffset(id);
+		return getPackIndex(ctx).findOffset(id);
 	}
 
 	/**
@@ -513,7 +510,7 @@ List<DfsObjectToPack> findAllFromPack(DfsReader ctx,
 			if (skipFound && otp.isFound()) {
 				continue;
 			}
-			long p = idx(ctx).findOffset(otp);
+			long p = getPackIndex(ctx).findOffset(otp);
 			if (p <= 0 || isCorrupt(p)) {
 				continue;
 			}
@@ -526,7 +523,7 @@ List<DfsObjectToPack> findAllFromPack(DfsReader ctx,
 
 	void resolve(DfsReader ctx, Set<ObjectId> matches, AbbreviatedObjectId id,
 			int matchLimit) throws IOException {
-		idx(ctx).resolve(matches, id, matchLimit);
+		getPackIndex(ctx).resolve(matches, id, matchLimit);
 	}
 
 	private byte[] decompress(long position, int sz, DfsReader ctx)
@@ -703,11 +700,11 @@ void copyAsIs(PackOutputStream out, DfsObjectToPack src,
 		try {
 			quickCopy = ctx.quickCopy(this, dataOffset, dataLength);
 
-			if (validate && idx(ctx).hasCRC32Support()) {
+			if (validate && getPackIndex(ctx).hasCRC32Support()) {
 				assert(crc1 != null);
 				// Index has the CRC32 code cached, validate the object.
 				//
-				expectedCRC = idx(ctx).findCRC32(src);
+				expectedCRC = getPackIndex(ctx).findCRC32(src);
 				if (quickCopy != null) {
 					quickCopy.crc32(crc1, dataOffset, (int) dataLength);
 				} else {
@@ -1000,7 +997,7 @@ ObjectLoader load(DfsReader ctx, long pos)
 
 	private long findDeltaBase(DfsReader ctx, ObjectId baseId)
 			throws IOException, MissingObjectException {
-		long ofs = idx(ctx).findOffset(baseId);
+		long ofs = getPackIndex(ctx).findOffset(baseId);
 		if (ofs < 0) {
 			throw new MissingObjectException(baseId,
 					JGitText.get().missingDeltaBase);
@@ -1094,7 +1091,7 @@ int getObjectType(DfsReader ctx, long pos) throws IOException {
 	}
 
 	long getObjectSize(DfsReader ctx, AnyObjectId id) throws IOException {
-		final long offset = idx(ctx).findOffset(id);
+		final long offset = getPackIndex(ctx).findOffset(id);
 		return 0 < offset ? getObjectSize(ctx, offset) : -1;
 	}
 
@@ -1545,7 +1542,8 @@ public LoadResult loadPackBitmapIndex(DfsReader ctx, DfsPackFile pack)
 				PackBitmapIndex bmidx;
 				try {
 					bmidx = PackBitmapIndex.read(alignTo8kBlocks(rc),
-							() -> pack.idx(ctx), () -> pack.getReverseIdx(ctx),
+							() -> pack.getPackIndex(ctx),
+							() -> pack.getReverseIdx(ctx),
 							ctx.getOptions().shouldLoadRevIndexInParallel());
 				} finally {
 					size = rc.position();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidx.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidx.java
index 5ef395d..0582737 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidx.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidx.java
@@ -11,14 +11,20 @@
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
+import java.util.Set;
 import java.util.zip.DataFormatException;
 
 import org.eclipse.jgit.annotations.Nullable;
 import org.eclipse.jgit.errors.StoredObjectRepresentationNotAvailableException;
 import org.eclipse.jgit.internal.storage.file.PackIndex;
 import org.eclipse.jgit.internal.storage.file.PackReverseIndex;
+import org.eclipse.jgit.internal.storage.pack.ObjectToPack;
 import org.eclipse.jgit.internal.storage.pack.PackOutputStream;
+import org.eclipse.jgit.lib.AbbreviatedObjectId;
+import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectLoader;
 
 /**
@@ -31,7 +37,7 @@
  * and forward to the pack.
  */
 public abstract sealed class DfsPackFileMidx extends DfsPackFile
-		permits DfsPackFileMidxNPacks {
+		permits DfsPackFileMidxNPacks, DfsPackFileMidxSingle {
 
 	/**
 	 * Create a midx pack
@@ -49,6 +55,10 @@ public abstract sealed class DfsPackFileMidx extends DfsPackFile
 	public static DfsPackFileMidx create(DfsBlockCache cache,
 			DfsPackDescription desc, List<DfsPackFile> requiredPacks,
 			@Nullable DfsPackFileMidx base) {
+		if (desc.getCoveredPacks().size() == 1) {
+			return new DfsPackFileMidxSingle(cache, desc, requiredPacks.get(0),
+					base);
+		}
 		return new DfsPackFileMidxNPacks(cache, desc, requiredPacks, base);
 	}
 
@@ -100,6 +110,24 @@ public List<DfsPackFile> getAllCoveredPacks() {
 	}
 
 	/**
+	 * Get the objectId at the corresponding position in the midx chain up to
+	 * this point
+	 * <p>
+	 * In a chain with midx-tip (100 objects) and midx-base (50 objects),
+	 * positions 0-49 belong to the base midx and 50-149 to the tip midx.
+	 *
+	 * @param ctx
+	 *            a reader for the midx data
+	 * @param nthPosition
+	 *            position in midx chain
+	 * @return the objectId
+	 * @throws IOException
+	 *             a problem reading midx bytes
+	 */
+	abstract ObjectId getObjectAt(DfsReader ctx, long nthPosition)
+			throws IOException;
+
+	/**
 	 * Count of objects in this <b>pack</b> (i.e. including, recursively, its
 	 * base)
 	 *
@@ -113,18 +141,43 @@ protected int getObjectCount(DfsReader ctx) throws IOException {
 		return (int) getPackDescription().getObjectCount();
 	}
 
-	@Override
-	public PackIndex getPackIndex(DfsReader ctx) {
-		throw new IllegalStateException(
-				"Shouldn't use multipack index if the primary index is needed"); //$NON-NLS-1$
-	}
+	/**
+	 * Return checksum of the midx
+	 *
+	 * @param ctx
+	 *            a reader
+	 * @return checksum of the midx
+	 * @throws IOException
+	 *             an error reading the file
+	 */
+	protected abstract byte[] getChecksum(DfsReader ctx) throws IOException;
 
 	@Override
-	public PackReverseIndex getReverseIdx(DfsReader ctx) {
-		throw new IllegalStateException(
-				"Shouldn't use multipack index if the reverse index is needed"); //$NON-NLS-1$
+	public final PackIndex getPackIndex(DfsReader ctx) {
+		return new MidxPackIndex(this, ctx);
 	}
 
+	/**
+	 * Return all objects in this midx (not recursively) as ObjectToPack
+	 * instances (oid, offset, type). Ordered by sha1.
+	 * <p>
+	 * ObjectToPack is the preferred format for the bitmap builder. This can
+	 * probably be optimized.
+	 *
+	 * @param ctx
+	 *            a reader
+	 * @return list of objects in this midx (NOT in its chain) with offset and
+	 *         type
+	 * @throws IOException
+	 *             an error reading the midx
+	 */
+	abstract List<ObjectToPack> getLocalObjects(DfsReader ctx)
+			throws IOException;
+
+	@Override
+	public abstract PackReverseIndex getReverseIdx(DfsReader ctx)
+			throws IOException;
+
 	@Override
 	ObjectLoader load(DfsReader ctx, long midxOffset) throws IOException {
 		DfsPackOffset location = getOffsetCalculator().decode(midxOffset);
@@ -331,4 +384,101 @@ long getPackOffset() {
 			return midxOffset - packStart;
 		}
 	}
+
+	private static class MidxPackIndex implements PackIndex {
+
+		private final DfsPackFileMidx pack;
+
+		private final DfsReader ctx;
+
+		MidxPackIndex(DfsPackFileMidx pack, DfsReader ctx) {
+			this.pack = pack;
+			this.ctx = ctx;
+		}
+
+		@Override
+		public Iterator<MutableEntry> iterator() {
+			throw new UnsupportedOperationException("Not implemented yet");
+		}
+
+		@Override
+		public long getObjectCount() {
+			try {
+				return pack.getObjectCount(ctx);
+			} catch (IOException e) {
+				throw new RuntimeException(e);
+			}
+		}
+
+		@Override
+		public long getOffset64Count() {
+			// TODO(ifrade): This method seems to be used only for stats.
+			// Maybe we can just remove it.
+			return 0;
+		}
+
+		@Override
+		public ObjectId getObjectId(long nthPosition) {
+			try {
+				return pack.getObjectAt(ctx, nthPosition);
+			} catch (IOException e) {
+				throw new RuntimeException(e);
+			}
+		}
+
+		@Override
+		public long getOffset(long nthPosition) {
+			ObjectId objectAt;
+			try {
+				objectAt = pack.getObjectAt(ctx, nthPosition);
+			} catch (IOException e) {
+				throw new RuntimeException(e);
+			}
+			if (objectAt == null) {
+				return -1;
+			}
+
+			return findOffset(objectAt);
+		}
+
+		@Override
+		public long findOffset(AnyObjectId objId) {
+			try {
+				return pack.findOffset(ctx, objId);
+			} catch (IOException e) {
+				throw new RuntimeException(e);
+			}
+		}
+
+		@Override
+		public int findPosition(AnyObjectId objId) {
+			try {
+				return pack.findIdxPosition(ctx, objId);
+			} catch (IOException e) {
+				throw new RuntimeException(e);
+			}
+		}
+
+		@Override
+		public long findCRC32(AnyObjectId objId)
+				throws UnsupportedOperationException {
+			throw new UnsupportedOperationException();
+		}
+
+		@Override
+		public boolean hasCRC32Support() {
+			return false;
+		}
+
+		@Override
+		public void resolve(Set<ObjectId> matches, AbbreviatedObjectId id,
+				int matchLimit) throws IOException {
+			pack.resolve(ctx, matches, id, matchLimit);
+		}
+
+		@Override
+		public byte[] getChecksum() {
+			throw new UnsupportedOperationException();
+		}
+	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidxNPacks.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidxNPacks.java
index 6ff078a..bed7a53 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidxNPacks.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidxNPacks.java
@@ -9,6 +9,7 @@
  */
 package org.eclipse.jgit.internal.storage.dfs;
 
+import static org.eclipse.jgit.internal.storage.pack.PackExt.BITMAP_INDEX;
 import static org.eclipse.jgit.internal.storage.pack.PackExt.MULTI_PACK_INDEX;
 import static org.eclipse.jgit.internal.storage.pack.PackExt.PACK;
 
@@ -23,8 +24,11 @@
 import java.util.stream.Collectors;
 
 import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.errors.CorruptObjectException;
+import org.eclipse.jgit.errors.PackMismatchException;
 import org.eclipse.jgit.internal.storage.commitgraph.CommitGraph;
 import org.eclipse.jgit.internal.storage.file.PackBitmapIndex;
+import org.eclipse.jgit.internal.storage.file.PackReverseIndex;
 import org.eclipse.jgit.internal.storage.midx.MultiPackIndex;
 import org.eclipse.jgit.internal.storage.midx.MultiPackIndex.PackOffset;
 import org.eclipse.jgit.internal.storage.midx.MultiPackIndexLoader;
@@ -130,7 +134,7 @@ private record RefWithSize(MultiPackIndex idx, long size) {
 
 	// Visible for testing
 	@Override
-	protected VOffsetCalculator getOffsetCalculator() {
+	protected VOffsetCalculatorNPacks getOffsetCalculator() {
 		return offsetCalculator;
 	}
 
@@ -140,16 +144,19 @@ public ObjectIdSet asObjectIdSet(DfsReader ctx) throws IOException {
 		return multiPackIndex::hasObject;
 	}
 
-
 	@Override
 	public PackBitmapIndex getBitmapIndex(DfsReader ctx) throws IOException {
-		// TODO(ifrade): at some point we will have bitmaps over the multipack
-		// index
-		// At the moment bitmap is in GC, at the end of the chain
+		// We have bitmaps only at the bottom of the midx or pack stack
 		if (base != null) {
 			return base.getBitmapIndex(ctx);
 		}
 
+		if (ctx.getOptions().shouldUseMidxBitmaps()
+				&& getPackDescription().hasFileExt(BITMAP_INDEX)) {
+			// Return our own bitmaps
+			return super.getBitmapIndex(ctx);
+		}
+
 		for (DfsPackFile pack : packsInIdOrder) {
 			PackBitmapIndex bitmapIndex = pack.getBitmapIndex(ctx);
 			if (bitmapIndex != null) {
@@ -188,6 +195,32 @@ public CommitGraph getCommitGraph(DfsReader ctx) throws IOException {
 		return null;
 	}
 
+	@Override
+	public List<ObjectToPack> getLocalObjects(DfsReader ctx)
+			throws IOException {
+		MultiPackIndex midx = midx(ctx);
+		int localObjCount = midx(ctx).getObjectCount();
+		List<ObjectToPack> otps = new ArrayList<>(localObjCount);
+		for (int idxPosition = 0; idxPosition < localObjCount; idxPosition++) {
+			ObjectId oid = midx.getObjectAt(idxPosition);
+			PackOffset packOffset = midx.find(oid);
+			long offset = offsetCalculator.encode(packOffset);
+			int objectType = getObjectType(ctx, offset);
+			ObjectToPack otp = new ObjectToPack(oid, objectType);
+			otp.setOffset(offset);
+			otps.add(otp);
+		}
+		return otps;
+	}
+
+	@Override
+	public PackReverseIndex getReverseIdx(DfsReader ctx) throws IOException {
+		return new MidxReverseIndex(ctx, this,
+				base == null ? 0 : base.getObjectCount(ctx),
+				getOffsetCalculator().baseMaxOffset,
+				base == null ? null : base.getReverseIdx(ctx));
+	}
+
 	/**
 	 * Count of objects in this <b>pack</b> (i.e. including, recursively, its
 	 * base)
@@ -204,6 +237,11 @@ protected int getObjectCount(DfsReader ctx) throws IOException {
 		return midx(ctx).getObjectCount() + baseObjectCount;
 	}
 
+	@Override
+	protected byte[] getChecksum(DfsReader ctx) throws IOException {
+		return midx(ctx).getChecksum();
+	}
+
 	/**
 	 * Packs indexed by this multipack index (base NOT included)
 	 *
@@ -227,6 +265,17 @@ public DfsPackFileMidx getMultipackIndexBase() {
 	}
 
 	@Override
+	ObjectId getObjectAt(DfsReader ctx, long nthPosition) throws IOException {
+		int baseObjectCount = base == null ? 0 : base.getObjectCount(ctx);
+		if (nthPosition >= baseObjectCount) {
+			long localPosition = nthPosition - baseObjectCount;
+			return midx(ctx).getObjectAt((int) localPosition);
+		}
+
+		return base.getObjectAt(ctx, nthPosition);
+	}
+
+	@Override
 	public int findIdxPosition(DfsReader ctx, AnyObjectId id)
 			throws IOException {
 		int p = midx(ctx).findPosition(id);
@@ -363,7 +412,6 @@ List<DfsObjectToPack> findAllFromPack(DfsReader ctx,
 		return tmp;
 	}
 
-
 	// Visible for testing
 	static class VOffsetCalculatorNPacks implements VOffsetCalculator {
 		private final DfsPackFile[] packs;
@@ -376,6 +424,8 @@ static class VOffsetCalculatorNPacks implements VOffsetCalculator {
 
 		private final DfsPackOffset poBuffer = new DfsPackOffset();
 
+		private final PackOffset localPoBuffer = new PackOffset();
+
 		static VOffsetCalculatorNPacks fromPacks(DfsPackFile[] packsInIdOrder,
 				VOffsetCalculator baseOffsetCalculator) {
 			long[] accSizes = new long[packsInIdOrder.length + 1];
@@ -406,6 +456,22 @@ long encode(MultiPackIndex.PackOffset location) {
 					+ baseMaxOffset;
 		}
 
+		MultiPackIndex.PackOffset decodeLocal(long voffset) {
+			if (voffset == -1 || voffset < baseMaxOffset
+					|| voffset > getMaxOffset()) {
+				return null;
+			}
+
+			long localOffset = voffset - baseMaxOffset;
+			for (int i = 1; i < accSizes.length; i++) {
+				if (localOffset <= accSizes[i]) {
+					return localPoBuffer.setValues(i - 1,
+							localOffset - accSizes[i - 1]);
+				}
+			}
+			return null;
+		}
+
 		@Override
 		public DfsPackOffset decode(long voffset) {
 			if (voffset == -1) {
@@ -431,4 +497,94 @@ public long getMaxOffset() {
 			return accSizes[accSizes.length - 1] + baseMaxOffset;
 		}
 	}
+
+	private static final class MidxReverseIndex implements PackReverseIndex {
+		private final PackReverseIndex parentRidx;
+
+		private final DfsPackFileMidxNPacks localMidx;
+
+		private final DfsReader ctx;
+
+		private final long baseObjectCount;
+
+		private final long baseMaxOffset;
+
+		MidxReverseIndex(DfsReader ctx, DfsPackFileMidxNPacks localMidx,
+				long baseObjectCount, long baseMaxOffset,
+				PackReverseIndex parentRidx) {
+			this.ctx = ctx;
+			this.parentRidx = parentRidx;
+			this.localMidx = localMidx;
+			this.baseObjectCount = baseObjectCount;
+			this.baseMaxOffset = baseMaxOffset;
+		}
+
+		@Override
+		public void verifyPackChecksum(String packFilePath)
+				throws PackMismatchException {
+
+		}
+
+		private MultiPackIndex loadLocalMidx() {
+			try {
+				return localMidx.midx(ctx);
+			} catch (IOException e) {
+				throw new RuntimeException(e);
+			}
+		}
+
+		@Override
+		public ObjectId findObject(long offset) {
+			if (offset < baseMaxOffset) {
+				return parentRidx.findObject(offset);
+			}
+
+			PackOffset localPo = localMidx.getOffsetCalculator()
+					.decodeLocal(offset);
+			if (localPo == null) {
+				return null;
+			}
+
+			int p = loadLocalMidx().findBitmapPosition(localPo);
+			if (p == -1) {
+				// If we found the local
+				// position, this should NOT
+				// happen
+				throw new IllegalStateException();
+			}
+
+			return loadLocalMidx().getObjectAtBitmapPosition(p);
+		}
+
+		@Override
+		public long findNextOffset(long offset, long maxOffset)
+				throws CorruptObjectException {
+			throw new UnsupportedOperationException();
+		}
+
+		@Override
+		public int findPosition(long offset) {
+			if (offset < baseMaxOffset) {
+				return parentRidx.findPosition(offset);
+			}
+
+			PackOffset localPo = localMidx.getOffsetCalculator()
+					.decodeLocal(offset);
+			if (localPo == null) {
+				return -1;
+			}
+
+			return loadLocalMidx().findBitmapPosition(localPo)
+					+ (int) baseObjectCount;
+		}
+
+		@Override
+		public ObjectId findObjectByPosition(int nthPosition) {
+			if (nthPosition < baseObjectCount) {
+				return parentRidx.findObjectByPosition(nthPosition);
+			}
+			return loadLocalMidx().getObjectAtBitmapPosition(
+					nthPosition - (int) baseObjectCount);
+		}
+	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidxSingle.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidxSingle.java
new file mode 100644
index 0000000..71ff884
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidxSingle.java
@@ -0,0 +1,476 @@
+/*
+ * Copyright (C) 2025, Google LLC.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.internal.storage.dfs;
+
+import static org.eclipse.jgit.internal.storage.pack.PackExt.MULTI_PACK_INDEX;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.channels.Channels;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.errors.CorruptObjectException;
+import org.eclipse.jgit.errors.PackMismatchException;
+import org.eclipse.jgit.internal.storage.commitgraph.CommitGraph;
+import org.eclipse.jgit.internal.storage.file.PackBitmapIndex;
+import org.eclipse.jgit.internal.storage.file.PackIndex;
+import org.eclipse.jgit.internal.storage.file.PackReverseIndex;
+import org.eclipse.jgit.internal.storage.midx.MultiPackIndex.PackOffset;
+import org.eclipse.jgit.internal.storage.pack.ObjectToPack;
+import org.eclipse.jgit.internal.storage.pack.PackExt;
+import org.eclipse.jgit.internal.storage.pack.PackOutputStream;
+import org.eclipse.jgit.lib.AbbreviatedObjectId;
+import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.BitmapIndex;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectIdSet;
+import org.eclipse.jgit.lib.ObjectLoader;
+import org.eclipse.jgit.util.BlockList;
+import org.eclipse.jgit.util.IO;
+
+/**
+ * A single pack that looks like a midx, to be used in the midx chain
+ */
+public final class DfsPackFileMidxSingle extends DfsPackFileMidx {
+	private final SingleVOffsetCalculator offsetCalculator;
+
+	private final DfsPackFile pack;
+
+	private final DfsPackFileMidx base;
+
+	private byte[] checksum;
+
+	private final LocalPackOffset poBuffer = new LocalPackOffset();
+
+	DfsPackFileMidxSingle(DfsBlockCache cache, DfsPackDescription midxDesc,
+			DfsPackFile pack, @Nullable DfsPackFileMidx base) {
+		super(cache, midxDesc);
+		this.pack = pack;
+		offsetCalculator = new SingleVOffsetCalculator(this.pack,
+				base != null ? base.getOffsetCalculator() : null);
+		this.length = offsetCalculator.getMaxOffset();
+		this.base = base;
+	}
+
+	// Visible for testing
+	@Override
+	protected VOffsetCalculator getOffsetCalculator() {
+		return offsetCalculator;
+	}
+
+	@Override
+	public ObjectIdSet asObjectIdSet(DfsReader ctx) throws IOException {
+		return pack.asObjectIdSet(ctx);
+	}
+
+	@Override
+	public PackReverseIndex getReverseIdx(DfsReader ctx) throws IOException {
+		return new MidxReverseIndex(pack.getReverseIdx(ctx),
+				offsetCalculator.baseMaxOffset,
+				base == null ? null : base.getReverseIdx(ctx),
+				base == null ? 0 : base.getObjectCount(ctx));
+	}
+
+	@Override
+	public PackBitmapIndex getBitmapIndex(DfsReader ctx) throws IOException {
+		// TODO(ifrade): at some point we will have bitmaps over the multipack
+		// index
+		// At the moment bitmap is in GC, at the end of the chain
+		if (base != null) {
+			return base.getBitmapIndex(ctx);
+		}
+
+		return pack.getBitmapIndex(ctx);
+	}
+
+	@Override
+	List<DfsPackFile> fullyIncludedIn(DfsReader ctx,
+			BitmapIndex.BitmapBuilder need) throws IOException {
+		List<DfsPackFile> fullyIncluded = new ArrayList<>();
+		List<DfsPackFile> includedPacks = pack.fullyIncludedIn(ctx, need);
+		if (!includedPacks.isEmpty()) {
+			fullyIncluded.addAll(includedPacks);
+		}
+
+		if (base != null) {
+			fullyIncluded.addAll(base.fullyIncludedIn(ctx, need));
+		}
+
+		return fullyIncluded;
+	}
+
+	@Override
+	public CommitGraph getCommitGraph(DfsReader ctx) throws IOException {
+		return pack.getCommitGraph(ctx);
+	}
+
+	/**
+	 * Count of objects in this <b>pack</b> (i.e. including, recursively, its
+	 * base)
+	 *
+	 * @param ctx
+	 *            a reader
+	 * @return count of objects in this pack, including its bases
+	 * @throws IOException
+	 *             an error reading a midx in the chain
+	 */
+	@Override
+	protected int getObjectCount(DfsReader ctx) throws IOException {
+		int baseObjectCount = base == null ? 0 : base.getObjectCount(ctx);
+		return (int) pack.getPackDescription().getObjectCount()
+				+ baseObjectCount;
+	}
+
+	@Override
+	protected byte[] getChecksum(DfsReader ctx) throws IOException {
+		if (checksum == null) {
+			long checksumPos = desc.getFileSize(MULTI_PACK_INDEX) - 20;
+			if (checksumPos <= 0) {
+				throw new IllegalStateException("Midx stream too short");
+			}
+
+			try (ReadableChannel rc = ctx.db.openFile(desc, MULTI_PACK_INDEX);
+					InputStream in = Channels.newInputStream(rc)) {
+				checksum = new byte[20];
+				in.skip(checksumPos);
+				IO.readFully(in, checksum, 0, 20);
+			}
+		}
+		return checksum;
+	}
+
+	/**
+	 * Packs indexed by this multipack index (base NOT included)
+	 *
+	 * @return packs indexed by this multipack index
+	 */
+	@Override
+	public List<DfsPackFile> getCoveredPacks() {
+		return List.of(pack);
+	}
+
+	/**
+	 * Base of this multipack index
+	 * <p>
+	 * If this midx is part of a chain, this is its parent
+	 *
+	 * @return the base of this multipack index
+	 */
+	@Override
+	public DfsPackFileMidx getMultipackIndexBase() {
+		return base;
+	}
+
+	@Override
+	public int findIdxPosition(DfsReader ctx, AnyObjectId id)
+			throws IOException {
+		int p = pack.findIdxPosition(ctx, id);
+		if (p >= 0) {
+			int baseObjects = base == null ? 0 : base.getObjectCount(ctx);
+			return p + baseObjects;
+		}
+
+		if (base == null) {
+			return -1;
+		}
+
+		return base.findIdxPosition(ctx, id);
+	}
+
+	@Override
+	ObjectId getObjectAt(DfsReader ctx, long nthPosition) throws IOException {
+		int baseObjects = base == null ? 0 : base.getObjectCount(ctx);
+		if (nthPosition >= baseObjects) {
+			long localPosition = nthPosition - baseObjects;
+			return pack.getPackIndex(ctx).getObjectId(localPosition);
+		}
+
+		return base.getObjectAt(ctx, nthPosition);
+	}
+
+	@Override
+	public boolean hasObject(DfsReader ctx, AnyObjectId id) throws IOException {
+		if (pack.hasObject(ctx, id)) {
+			return true;
+		}
+
+		if (base == null) {
+			return false;
+		}
+
+		return base.hasObject(ctx, id);
+	}
+
+	@Override
+	ObjectLoader get(DfsReader ctx, AnyObjectId id) throws IOException {
+		ObjectLoader objectLoader = pack.get(ctx, id);
+		if (objectLoader != null) {
+			return objectLoader;
+		}
+
+		if (base == null) {
+			return null;
+		}
+
+		return base.get(ctx, id);
+	}
+
+	private PackOffset find(DfsReader ctx, AnyObjectId id) throws IOException {
+		long offset = pack.findOffset(ctx, id);
+		if (offset >= 0) {
+			poBuffer.setOffset(offset);
+			return poBuffer;
+		}
+		return null;
+	}
+
+	@Override
+	long findOffset(DfsReader ctx, AnyObjectId id) throws IOException {
+		PackOffset po = find(ctx, id);
+		if (po != null) {
+			return offsetCalculator.encode(po);
+		}
+
+		if (base == null) {
+			return -1;
+		}
+
+		return base.findOffset(ctx, id);
+	}
+
+	@Override
+	void resolve(DfsReader ctx, Set<ObjectId> matches, AbbreviatedObjectId id,
+			int matchLimit) throws IOException {
+		pack.resolve(ctx, matches, id, matchLimit);
+		if (matches.size() < matchLimit && base != null) {
+			base.resolve(ctx, matches, id, matchLimit);
+		}
+	}
+
+	@Override
+	void copyPackAsIs(PackOutputStream out, DfsReader ctx) throws IOException {
+		pack.copyPackAsIs(out, ctx);
+
+		if (base != null) {
+			base.copyPackAsIs(out, ctx);
+		}
+	}
+
+	@Override
+	long getObjectSize(DfsReader ctx, AnyObjectId id) throws IOException {
+		long objectSize = pack.getObjectSize(ctx, id);
+		if (objectSize >= 0) {
+			return objectSize;
+		}
+
+		if (base == null) {
+			return -1;
+		}
+
+		return base.getObjectSize(ctx, id);
+	}
+
+	@Override
+	boolean hasObjectSizeIndex(DfsReader ctx) {
+		// TODO(ifrade): If the base has object size index, we can say yes
+		return false;
+	}
+
+	@Override
+	int getObjectSizeIndexThreshold(DfsReader ctx) {
+		return Integer.MAX_VALUE;
+	}
+
+	@Override
+	long getIndexedObjectSize(DfsReader ctx, int idxPosition) {
+		return -1;
+	}
+
+	@Override
+	public List<ObjectToPack> getLocalObjects(DfsReader ctx)
+			throws IOException {
+		PackIndex idx = getPackIndex(ctx);
+		int localObjCount = (int) idx.getObjectCount();
+		List<ObjectToPack> otps = new ArrayList<>(localObjCount);
+		for (int idxPosition = 0; idxPosition < localObjCount; idxPosition++) {
+			ObjectId oid = idx.getObjectId(idxPosition);
+			long offset = idx.getOffset(idxPosition);
+			int objectType = getObjectType(ctx, offset);
+			ObjectToPack otp = new ObjectToPack(oid, objectType);
+			otp.setOffset(offset);
+			otps.add(otp);
+		}
+		return otps;
+	}
+
+	@Override
+	List<DfsObjectToPack> findAllFromPack(DfsReader ctx,
+			Iterable<ObjectToPack> objects, boolean skipFound)
+			throws IOException {
+		List<DfsObjectToPack> tmp = new BlockList<>();
+		List<ObjectToPack> notFoundHere = new BlockList<>();
+		for (ObjectToPack obj : objects) {
+			DfsObjectToPack otp = (DfsObjectToPack) obj;
+			if (skipFound && otp.isFound()) {
+				continue;
+			}
+			long p = offsetCalculator.encode(find(ctx, otp));
+			if (p < 0) {
+				notFoundHere.add(otp);
+				continue;
+			}
+			otp.setOffset(p);
+			tmp.add(otp);
+		}
+
+		if (base != null && !notFoundHere.isEmpty()) {
+			List<DfsObjectToPack> inChain = base.findAllFromPack(ctx,
+					notFoundHere, skipFound);
+			tmp.addAll(inChain);
+		}
+		tmp.sort(OFFSET_SORT);
+		return tmp;
+	}
+
+	/**
+	 * As this pack is always at the bottom, midx-offset is always offset
+	 */
+	static class SingleVOffsetCalculator implements VOffsetCalculator {
+
+		private final long packSize;
+
+		private final DfsPackOffset poBuffer = new DfsPackOffset();
+
+		private final VOffsetCalculator baseOffsetCalculator;
+
+		private final long baseMaxOffset;
+
+		SingleVOffsetCalculator(DfsPackFile realPack,
+				@Nullable VOffsetCalculator base) {
+			this.packSize = realPack.getPackDescription()
+					.getFileSize(PackExt.PACK);
+			this.baseOffsetCalculator = base;
+			baseMaxOffset = base != null ? base.getMaxOffset() : 0;
+			poBuffer.setValues(realPack, baseMaxOffset, 0);
+		}
+
+		long encode(PackOffset location) {
+			if (location == null) {
+				return -1;
+			}
+
+			if (location.getOffset() > packSize || location.getPackId() != 0) {
+				throw new IllegalArgumentException(String.format(
+						"Invalid midx location (packId: %d, offset: %d)", //$NON-NLS-1$
+						location.getPackId(), location.getOffset()));
+			}
+			return location.getOffset() + baseMaxOffset;
+		}
+
+		@Override
+		public DfsPackOffset decode(long voffset) {
+			if (voffset == -1) {
+				return null;
+			}
+
+			if (voffset < baseMaxOffset) {
+				return baseOffsetCalculator.decode(voffset);
+			}
+
+			long localOffset = voffset - baseMaxOffset;
+			if (localOffset > packSize) {
+				throw new IllegalArgumentException(
+						"Asking offset beyond limits"); //$NON-NLS-1$
+			}
+
+			return poBuffer.setMidxOffset(voffset);
+		}
+
+		@Override
+		public long getMaxOffset() {
+			return packSize + baseMaxOffset;
+		}
+	}
+
+	/**
+	 * A packOffset with the packId and packStart fixed to 0
+	 */
+	private static class LocalPackOffset extends PackOffset {
+
+		void setOffset(long offset) {
+			super.setValues(0, offset);
+		}
+	}
+
+	private static class MidxReverseIndex implements PackReverseIndex {
+		private final long baseMaxOffset;
+
+		private final long baseObjectCount;
+
+		private final PackReverseIndex baseRidx;
+
+		private final PackReverseIndex ridx;
+
+		MidxReverseIndex(PackReverseIndex ridx, long baseMaxOffset,
+				PackReverseIndex baseRidx, long baseObjectCount) {
+			this.ridx = ridx;
+			this.baseMaxOffset = baseMaxOffset;
+			this.baseRidx = baseRidx;
+			this.baseObjectCount = baseObjectCount;
+
+		}
+
+		@Override
+		public void verifyPackChecksum(String packFilePath)
+				throws PackMismatchException {
+
+		}
+
+		@Override
+		public ObjectId findObject(long offset) {
+			if (offset < baseMaxOffset) {
+				return baseRidx.findObject(offset);
+			}
+
+			long localOffset = offset - baseMaxOffset;
+			return ridx.findObject(localOffset);
+		}
+
+		@Override
+		public long findNextOffset(long offset, long maxOffset)
+				throws CorruptObjectException {
+			// TODO(ifrade): In this single-pack midx we can actually implement
+			// this
+			throw new UnsupportedOperationException();
+		}
+
+		@Override
+		public int findPosition(long offset) {
+			if (offset < baseMaxOffset) {
+				return baseRidx.findPosition(offset);
+			}
+			long localOffset = offset - baseMaxOffset;
+			return ridx.findPosition(localOffset) + (int) baseObjectCount;
+		}
+
+		@Override
+		public ObjectId findObjectByPosition(int nthPosition) {
+			if (nthPosition < baseObjectCount) {
+				return baseRidx.findObjectByPosition(nthPosition);
+			}
+			long localPosition = nthPosition - baseObjectCount;
+			// TODO(ifrade): Check downcasting
+			return ridx.findObjectByPosition((int) localPosition);
+		}
+	}
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReaderOptions.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReaderOptions.java
index c397469..e1d7047 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReaderOptions.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReaderOptions.java
@@ -40,6 +40,8 @@ public class DfsReaderOptions {
 
 	private boolean useObjectSizeIndex;
 
+	private boolean useMidxBitmaps;
+
 	/**
 	 * Create a default reader configuration.
 	 */
@@ -163,6 +165,29 @@ public DfsReaderOptions setUseObjectSizeIndex(boolean useObjectSizeIndex) {
 	}
 
 	/**
+	 * Use bitmaps in the midx if available.
+	 *
+	 * @return true if a midx pack should use its own bitmaps. false to fallback
+	 *         to GC bitmaps.
+	 */
+	public boolean shouldUseMidxBitmaps() {
+		return useMidxBitmaps;
+	}
+
+	/**
+	 * Set if the midx packs should use their bitmaps or fallback to bitmaps in
+	 * GC pack.
+	 *
+	 * @param useMidxBitmaps
+	 *            useMidxBitmaps to set
+	 * @return {@code this}
+	 */
+	public DfsReaderOptions setUseMidxBitmaps(boolean useMidxBitmaps) {
+		this.useMidxBitmaps = useMidxBitmaps;
+		return this;
+	}
+
+	/**
 	 * Update properties by setting fields from the configuration.
 	 * <p>
 	 * If a property is not defined in the configuration, then it is left
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/MidxPackFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/MidxPackFilter.java
index 50de974..670950a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/MidxPackFilter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/MidxPackFilter.java
@@ -9,13 +9,16 @@
  */
 package org.eclipse.jgit.internal.storage.dfs;
 
-import org.eclipse.jgit.internal.storage.pack.PackExt;
-
+import java.util.ArrayList;
+import java.util.Comparator;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Optional;
 import java.util.Set;
 import java.util.stream.Collectors;
 
+import org.eclipse.jgit.internal.storage.pack.PackExt;
+
 /**
  * Format a flat list of packs and midxs into a valid list of packs.
  * <p>
@@ -30,6 +33,23 @@ public class MidxPackFilter {
 	private MidxPackFilter() {
 	}
 
+	private static Comparator<DfsPackDescription> midxComparator = Comparator
+			.comparingLong(DfsPackDescription::getLastModified)
+			// If multiple midx where written at the same time, take the one
+			// with covering most objects first (it must be the tip)
+			.thenComparingLong(MidxPackFilter::getTotalCoveredObjects)
+			.reversed();
+
+	private static long getTotalCoveredObjects(DfsPackDescription desc) {
+		long objCount = 0;
+		DfsPackDescription current = desc;
+		while (current != null) {
+			objCount += current.getObjectCount();
+			current = current.getMultiPackIndexBase();
+		}
+		return objCount;
+	}
+
 	/**
 	 * Reorganize the flat list of packs removing the midxs
 	 *
@@ -59,40 +79,60 @@ public static List<DfsPackDescription> skipMidxs(
 	 */
 	public static List<DfsPackDescription> useMidx(
 			List<DfsPackDescription> packs) {
-		// Take the packs covered by the midxs out of the list
 		List<DfsPackDescription> midxs = packs.stream()
 				.filter(desc -> desc.hasFileExt(PackExt.MULTI_PACK_INDEX))
-				.toList();
+				.sorted(midxComparator).toList();
 		if (midxs.isEmpty()) {
 			return packs;
 		}
 
-		Set<DfsPackDescription> inputPacks = new HashSet<>(packs);
-		Set<DfsPackDescription> allCoveredPacks = new HashSet<>();
-		for (DfsPackDescription midx : midxs) {
-			Set<DfsPackDescription> coveredPacks = new HashSet<>();
-			findCoveredPacks(midx, coveredPacks);
-			if (!inputPacks.containsAll(coveredPacks)) {
-				// This midx references packs not in the pack db.
-				// It could be part of a chain, so we just ignore all midxs
-				return skipMidxs(packs);
-			}
-			allCoveredPacks.addAll(coveredPacks);
+		Set<DfsPackDescription> packsSet = new HashSet<>(packs);
+		Optional<DfsPackDescription> bestMidx = midxs.stream()
+				.filter(midx -> isValid(midx, packsSet)).findFirst();
+		if (bestMidx.isEmpty()) {
+			return skipMidxs(packs);
 		}
 
-		return packs.stream().filter(d -> !allCoveredPacks.contains(d))
-				.collect(Collectors.toList());
+		// Take the packs covered by the midxs and other midxs themselves out of
+		// the list
+		Set<DfsPackDescription> coveredPacksAndMidxs = getAllCoveredPacks(
+				bestMidx.get());
+		return packs.stream().filter(p -> !coveredPacksAndMidxs.contains(p))
+				// At this point, any midx in the list besides bestMidx is a
+				// straggler.
+				.filter(p -> !p.hasFileExt(PackExt.MULTI_PACK_INDEX)
+						|| p.equals(bestMidx.get()))
+				.collect(Collectors.toCollection(ArrayList::new));
 	}
 
-	private static void findCoveredPacks(DfsPackDescription midx,
-			Set<DfsPackDescription> covered) {
-		if (!midx.getCoveredPacks().isEmpty()) {
-			covered.addAll(midx.getCoveredPacks());
-		}
+	private static boolean isValid(DfsPackDescription midx,
+			Set<DfsPackDescription> packs) {
+		DfsPackDescription tip = midx;
+		while (tip != null) {
+			if (!packs.containsAll(tip.getCoveredPacks())) {
+				return false;
+			}
 
-		if (midx.getMultiPackIndexBase() != null) {
-			findCoveredPacks(midx.getMultiPackIndexBase(), covered);
-			covered.add(midx.getMultiPackIndexBase());
+			tip = tip.getMultiPackIndexBase();
 		}
+		return true;
+	}
+
+	private static Set<DfsPackDescription> getAllCoveredPacks(
+			DfsPackDescription midx) {
+		Set<DfsPackDescription> covered = new HashSet<>();
+		DfsPackDescription current = midx;
+		while (current != null) {
+			if (!current.getCoveredPacks().isEmpty()) {
+				covered.addAll(current.getCoveredPacks());
+			}
+
+			DfsPackDescription base = current.getMultiPackIndexBase();
+			if (base != null) {
+				covered.add(base);
+			}
+			current = base;
+		}
+		return covered;
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/RefAdvancerWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/RefAdvancerWalk.java
new file mode 100644
index 0000000..d0d8056
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/RefAdvancerWalk.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2026, Google LLC.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.internal.storage.dfs;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.jgit.errors.StopWalkException;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevObject;
+import org.eclipse.jgit.revwalk.RevSort;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.revwalk.filter.RevFilter;
+
+/**
+ * Walk from some commits and find where to they enter a pack
+ */
+class RefAdvancerWalk {
+
+	private final DfsRepository db;
+
+	private final InPackPredicate includeP;
+
+	/**
+	 * True when the commit is in the pack
+	 */
+	@FunctionalInterface
+	interface InPackPredicate {
+		boolean test(RevCommit c) throws IOException;
+	}
+
+	RefAdvancerWalk(DfsRepository db, InPackPredicate include) {
+		this.db = db;
+		this.includeP = include;
+	}
+
+	private RevWalk createRevWalk() {
+		RevWalk rw = new RevWalk(db);
+		rw.sort(RevSort.COMMIT_TIME_DESC);
+		rw.setRevFilter(new FirstInPack(includeP));
+		return rw;
+	}
+
+	/**
+	 * Advance the tips to their first commit inside the pack
+	 *
+	 * @param allTips
+	 *            tips of interesting refs
+	 * @return first commit(s) where the tips enter the pack. A tips may
+	 *         translate into 0 commits (it doesn't enter the pack in its
+	 *         history), 1 commit (a linear history) or n commits (merges lead
+	 *         to multiple histories into the pack). A tip already inside the
+	 *         pack is returned as it is.
+	 * @throws IOException
+	 *             error browsing history
+	 */
+	Set<RevCommit> advance(List<ObjectId> allTips) throws IOException {
+		Set<RevCommit> tipsInMidx = new HashSet<>(allTips.size());
+		try (RevWalk rw = createRevWalk()) {
+			for (ObjectId tip : allTips) {
+				RevObject tipObject = rw.parseAny(tip);
+				if (!(tipObject instanceof RevCommit tipCommit)) {
+					continue;
+				}
+
+				rw.markStart(tipCommit);
+				RevCommit inPack;
+				while ((inPack = rw.next()) != null) {
+					tipsInMidx.add(inPack);
+				}
+			}
+		}
+		return tipsInMidx;
+	}
+
+	private static class FirstInPack extends RevFilter {
+
+		private final InPackPredicate isInPack;
+
+		FirstInPack(InPackPredicate isInPack) {
+			this.isInPack = isInPack;
+		}
+
+		@Override
+		public boolean include(RevWalk walker, RevCommit cmit)
+				throws StopWalkException, IOException {
+			if (!isInPack.test(cmit)) {
+				return false;
+			}
+
+			for (RevCommit p : cmit.getParents()) {
+				walker.markUninteresting(p);
+			}
+			return true;
+		}
+
+		@Override
+		public RevFilter clone() {
+			return this;
+		}
+	}
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java
index 7c6a304..6a78271 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java
@@ -82,6 +82,8 @@
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.CoreConfig;
 import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.GcConfig;
+import org.eclipse.jgit.lib.GcConfig.PackRefsMode;
 import org.eclipse.jgit.lib.NullProgressMonitor;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectIdSet;
@@ -171,6 +173,8 @@ public static void setExecutor(ExecutorService e) {
 
 	private PackConfig pconfig;
 
+	private GcConfig gcConfig;
+
 	/**
 	 * the refs which existed during the last call to {@link #repack()}. This is
 	 * needed during {@link #prune(Set)} where we can optimize by looking at the
@@ -207,6 +211,7 @@ public GC(FileRepository repo) {
 		this.repo = repo;
 		this.pconfig = new PackConfig(repo);
 		this.pm = NullProgressMonitor.INSTANCE;
+		this.gcConfig = repo.getConfig().get(GcConfig.KEY);
 	}
 
 	/**
@@ -282,6 +287,18 @@ private ExecutorService executor() {
 		return (executor != null) ? executor : WorkQueue.getExecutor();
 	}
 
+	/**
+	 * Set the gc configuration.
+	 *
+	 * @param gcConfig
+	 *            the gc configuration
+	 * @return this instance
+	 */
+	public GC setGcConfig(GcConfig gcConfig) {
+		this.gcConfig = gcConfig;
+		return this;
+	}
+
 	private Collection<Pack> doGc()
 			throws IOException, ParseException, GitAPIException {
 		if (automatic && !needGc()) {
@@ -292,8 +309,13 @@ private Collection<Pack> doGc()
 				return Collections.emptyList();
 			}
 			pm.start(6 /* tasks */);
-			new PackRefsCommand(repo).setProgressMonitor(pm).setAll(true)
-					.call();
+			boolean packRefs = gcConfig.getPackRefs() == PackRefsMode.TRUE
+					|| (gcConfig.getPackRefs() == PackRefsMode.NOTBARE
+							&& !repo.isBare());
+			if (packRefs) {
+				new PackRefsCommand(repo).setProgressMonitor(pm).setAll(true)
+						.call();
+			}
 			// TODO: implement reflog_expire(pm, repo);
 			Collection<Pack> newPacks = repack();
 			prune(Collections.emptySet());
@@ -747,6 +769,15 @@ private long getPackExpireDate() throws ParseException {
 	}
 
 	/**
+	 * Get the gc configuration.
+	 *
+	 * @return the gc configuration.
+	 */
+	public GcConfig getGcConfig() {
+		return gcConfig;
+	}
+
+	/**
 	 * Remove all entries from a map which key is the id of an object referenced
 	 * by the given ObjectWalk
 	 *
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java
index 9c262e9..9fa3ff3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java
@@ -121,6 +121,9 @@ public class RefDirectory extends RefDatabase {
 	/** If in the header, denotes the file has peeled data. */
 	public static final String PACKED_REFS_PEELED = " peeled"; //$NON-NLS-1$
 
+	/** If in the header, denotes the file has sorted data. */
+	public static final String PACKED_REFS_SORTED = " sorted"; //$NON-NLS-1$
+
 	@SuppressWarnings("boxing")
 	private static final List<Integer> RETRY_SLEEP_MS =
 			Collections.unmodifiableList(Arrays.asList(0, 100, 200, 400, 800, 1600));
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MultiPackIndex.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MultiPackIndex.java
index edaa221..1721cb6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MultiPackIndex.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MultiPackIndex.java
@@ -10,23 +10,26 @@
 
 package org.eclipse.jgit.internal.storage.midx;
 
+import java.util.Iterator;
+import java.util.List;
 import java.util.Set;
 
 import org.eclipse.jgit.lib.AbbreviatedObjectId;
 import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.MutableObjectId;
 import org.eclipse.jgit.lib.ObjectId;
 
 /**
  * An index over multiple packs
  */
-public interface MultiPackIndex {
+public interface MultiPackIndex extends Iterable<MultiPackIndex.MutableEntry> {
 
 	/**
 	 * Obtain the array of packfiles in the MultiPackIndex.
 	 * <p>
 	 * The pack ids correspond to positions in this list.
 	 *
-	 * @return array of packnames refered in this multipak index
+	 * @return array of packnames refered in this multipack index
 	 */
 	String[] getPackNames();
 
@@ -66,6 +69,35 @@ public interface MultiPackIndex {
 	int findPosition(AnyObjectId objectId);
 
 	/**
+	 * Return the position in offset order (i.e. ridx or bitmap position) for
+	 * the (packId, offset) pair.
+	 *
+	 * @param po
+	 *            a location in the midx (packId, offset)
+	 * @return the position in the midx, in offset order
+	 */
+	int findBitmapPosition(PackOffset po);
+
+	/**
+	 * Object id at the specified position in offset order (i.e. position in the
+	 * ridx or bitmap)
+	 *
+	 * @param bitmapPosition
+	 *            position in the bitmap
+	 * @return object id at that position.
+	 */
+	ObjectId getObjectAtBitmapPosition(int bitmapPosition);
+
+	/**
+	 * ObjectId at this position in the midx
+	 *
+	 * @param position
+	 *            position inside this midx in sha1 order
+	 * @return the object id at that position
+	 */
+	ObjectId getObjectAt(int position);
+
+	/**
 	 * Number of objects in this midx
 	 * <p>
 	 * This number doesn't match with the sum of objects in each covered pack
@@ -90,6 +122,13 @@ public interface MultiPackIndex {
 	void resolve(Set<ObjectId> matches, AbbreviatedObjectId id, int matchLimit);
 
 	/**
+	 * Index checksum of the contents of this midx file
+	 *
+	 * @return checksum of the contents of this midx file
+	 */
+	byte[] getChecksum();
+
+	/**
 	 * Memory size of this multipack index
 	 *
 	 * @return size of this multipack index in memory, in bytes
@@ -97,13 +136,41 @@ public interface MultiPackIndex {
 	long getMemorySize();
 
 	/**
+	 * Return an iterator over the <em>local</em> objects in this midx.
+	 * <p>
+	 * In chained midxs, this iterator does not include the base midx.
+	 *
+	 * @return iterator in sha1 order of the objects in this midx
+	 */
+	@Override
+	MidxIterator iterator();
+
+	/**
+	 * An peekable iterator for the midx
+	 */
+	interface MidxIterator extends Iterator<MutableEntry> {
+		/**
+		 * Like next() but without advancing the iterator.
+		 *
+		 * @return next() element in the iterator without advancing
+		 */
+		MutableEntry peek();
+
+		/**
+		 * Pack names in the order of new packIds emitted by the iterator
+		 *
+		 * @return pack names
+		 */
+		List<String> getPackNames();
+	}
+
+	/**
 	 * (packId, offset) coordinates of an object
 	 * <p>
 	 * Mutable object to avoid creating many instances while looking for objects
 	 * in the pack. Use #copy() to get a new instance with the data.
 	 */
-	class PackOffset {
-
+	class PackOffset implements Comparable<PackOffset> {
 		private int packId;
 
 		private long offset;
@@ -123,7 +190,10 @@ public static PackOffset create(int packId, long offset) {
 			return new PackOffset().setValues(packId, offset);
 		}
 
-		protected PackOffset setValues(int packId, long offset) {
+		public PackOffset() {
+		}
+
+		public PackOffset setValues(int packId, long offset) {
 			this.packId = packId;
 			this.offset = offset;
 			return this;
@@ -141,5 +211,76 @@ public PackOffset copy() {
 			PackOffset copy = new PackOffset();
 			return copy.setValues(this.packId, this.offset);
 		}
+
+		@Override
+		public int compareTo(PackOffset packOffset) {
+			int cmp = this.packId - packOffset.packId;
+			if (cmp != 0) {
+				return cmp;
+			}
+
+			return Long.compare(this.offset, packOffset.offset);
+		}
+
+		@Override
+		public String toString() {
+			return String.format("PackOffset(packId=%d|offset=%d)", packId,
+					offset);
+
+		}
+	}
+
+	/**
+	 * Entry from the midx with object id, pack id, offset (in pack)
+	 * <p>
+	 * Mutable so the iterator can reuse the instance for performance.
+	 */
+	class MutableEntry implements Comparable<MutableEntry> {
+		protected final MutableObjectId oid = new MutableObjectId();
+
+		protected final PackOffset packOffset = new PackOffset();
+
+		@Override
+		public int compareTo(MutableEntry mutableEntry) {
+			int cmp = oid.compareTo(mutableEntry.oid);
+			if (cmp != 0) {
+				return cmp;
+			}
+
+			return packOffset.getPackId() - mutableEntry.packOffset.getPackId();
+		}
+
+		/**
+		 * Copy data from other into this instance, adding the shift to the
+		 * packId
+		 *
+		 * @param other
+		 *            another entry
+		 * @param shift
+		 *            amount to add to the packid
+		 * @return this instance
+		 */
+		public MutableEntry fill(MutableEntry other, int shift) {
+			oid.fromObjectId(other.oid);
+			packOffset.setValues(other.getPackId() + shift, other.getOffset());
+			return this;
+		}
+
+		public MutableObjectId getObjectId() {
+			return oid;
+		}
+
+		public int getPackId() {
+			return packOffset.getPackId();
+		}
+
+		public long getOffset() {
+			return packOffset.getOffset();
+		}
+
+		@Override
+		public String toString() {
+			return String.format("%s,%s", oid.name(), packOffset);
+		}
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MultiPackIndexLoader.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MultiPackIndexLoader.java
index 1d4f47a..4b70c2c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MultiPackIndexLoader.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MultiPackIndexLoader.java
@@ -187,11 +187,17 @@ public static MultiPackIndex read(InputStream fd)
 			case MIDX_CHUNKID_LARGEOFFSETS:
 				builder.addObjectLargeOffsets(buffer);
 				break;
+			case MIDX_CHUNKID_REVINDEX:
+				builder.addReverseIndex(buffer);
+				break;
 			default:
 				LOG.warn(MessageFormat.format(JGitText.get().midxChunkUnknown,
 						Integer.toHexString(chunkId)));
 			}
 		}
+		byte[] checksum = new byte[20];
+		IO.readFully(fd, checksum, 0, 20);
+		builder.addChecksum(checksum);
 		return builder.build();
 	}
 
@@ -223,6 +229,8 @@ static class MultiPackIndexBuilder {
 		// Optional
 		private byte[] bitmapPackOrder;
 
+		private byte[] checksum;
+
 		private MultiPackIndexBuilder(int hashLength) {
 			this.hashLength = hashLength;
 		}
@@ -300,7 +308,8 @@ MultiPackIndex build() throws MultiPackIndexFormatException {
 
 			assertPackCounts(packCount, packNames.length);
 			return new MultiPackIndexV1(hashLength, oidFanout, oidLookup,
-					packNames, bitmappedPackfiles, objectOffsets, largeObjectOffsets);
+					packNames, bitmappedPackfiles, objectOffsets,
+					largeObjectOffsets, bitmapPackOrder, checksum);
 		}
 
 		private static void assertChunkNotNull(Object object, int chunkId)
@@ -330,6 +339,10 @@ private static void assertPackCounts(int headerCount,
 						Integer.valueOf(packfileNamesCount)));
 			}
 		}
+
+		public void addChecksum(byte[] checksum) {
+			this.checksum = checksum;
+		}
 	}
 
 	/**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MultiPackIndexV1.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MultiPackIndexV1.java
index 8ae1fe6..ac6f00c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MultiPackIndexV1.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MultiPackIndexV1.java
@@ -12,6 +12,7 @@
 
 import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
+import java.util.List;
 import java.util.Set;
 
 import org.eclipse.jgit.annotations.NonNull;
@@ -20,6 +21,7 @@
 import org.eclipse.jgit.internal.storage.midx.MultiPackIndexLoader.MultiPackIndexFormatException;
 import org.eclipse.jgit.lib.AbbreviatedObjectId;
 import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.MutableObjectId;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.util.NB;
 
@@ -34,20 +36,25 @@ class MultiPackIndexV1 implements MultiPackIndex {
 
 	private final String[] packNames;
 
-	private final byte[] bitmappedPackfiles;
-
 	private final OffsetLookup offsets;
 
 	private final PackOffset result = new PackOffset();
 
+	private final ReverseIndex ridx;
+
+	private final byte[] checksum;
+
 	MultiPackIndexV1(int hashLength, @NonNull byte[] oidFanout,
 			@NonNull byte[] oidLookup, String[] packNames,
 			byte[] bitmappedPackfiles, byte[] objectOffsets,
-			byte[] largeObjectOffsets) throws MultiPackIndexFormatException {
-		this.bitmappedPackfiles = bitmappedPackfiles;
+			byte[] largeObjectOffsets, byte[] bitmapPackOrder, byte[] checksum)
+			throws MultiPackIndexFormatException {
 		this.idx = new OidLookup(hashLength, oidFanout, oidLookup);
 		this.offsets = new OffsetLookup(objectOffsets, largeObjectOffsets);
 		this.packNames = packNames;
+		this.ridx = new ReverseIndex(bitmapPackOrder, idx, offsets,
+				bitmappedPackfiles);
+		this.checksum = checksum;
 	}
 
 	@Override
@@ -66,6 +73,21 @@ public int findPosition(AnyObjectId oid) {
 	}
 
 	@Override
+	public int findBitmapPosition(PackOffset po) {
+		return ridx.findBitmapPosition(po);
+	}
+
+	@Override
+	public ObjectId getObjectAtBitmapPosition(int bitmapPosition) {
+		return ridx.getObjectId(bitmapPosition);
+	}
+
+	@Override
+	public ObjectId getObjectAt(int position) {
+		return idx.getObjectAt(position);
+	}
+
+	@Override
 	public int getObjectCount() {
 		return idx.getObjectCount();
 	}
@@ -88,23 +110,30 @@ public void resolve(Set<ObjectId> matches, AbbreviatedObjectId id,
 	}
 
 	@Override
+	public byte[] getChecksum() {
+		return checksum;
+	}
+
+	@Override
 	public long getMemorySize() {
 		int packNamesSize = Arrays.stream(packNames)
 				.mapToInt(s -> s.getBytes(StandardCharsets.UTF_8).length).sum();
-		return packNamesSize + byteArrayLengh(bitmappedPackfiles)
-				+ idx.getMemorySize() + offsets.getMemorySize();
+		return packNamesSize + ridx.getMemorySize() + idx.getMemorySize()
+				+ offsets.getMemorySize() + checksum.length;
 	}
 
+
 	@Override
 	public String toString() {
 		return "MultiPackIndexV1 {idx=" + idx + ", packfileNames=" //$NON-NLS-1$ //$NON-NLS-2$
-				+ Arrays.toString(packNames) + ", bitmappedPackfiles=" //$NON-NLS-1$
-				+ byteArrayToString(bitmappedPackfiles) + ", objectOffsets=" //$NON-NLS-1$
+				+ Arrays.toString(packNames) + ", ridx=" //$NON-NLS-1$
+				+ ridx + ", objectOffsets=" //$NON-NLS-1$
 				+ offsets + '}';
 	}
 
-	private static String byteArrayToString(byte[] array) {
-		return array == null ? "null" : new String(array); //$NON-NLS-1$
+	@Override
+	public MidxIterator iterator() {
+		return new LocalMidxIterator(this);
 	}
 
 	private static int byteArrayLengh(byte[] array) {
@@ -246,6 +275,11 @@ int findMultiPackIndexPosition(AnyObjectId id) {
 			return -1;
 		}
 
+		ObjectId getObjectAt(int midxPosition) {
+			int rawOffset = hashLength * midxPosition;
+			return ObjectId.fromRaw(oidLookup, rawOffset);
+		}
+
 		void resolve(Set<ObjectId> matches, AbbreviatedObjectId id,
 				int matchLimit) {
 			if (matches.size() >= matchLimit) {
@@ -307,5 +341,129 @@ long getMemorySize() {
 		int getObjectCount() {
 			return fanoutTable[FANOUT - 1];
 		}
+
+		void readOidAt(int position, MutableObjectId output) {
+			output.fromRaw(oidLookup, idOffset(position));
+		}
+	}
+
+	/**
+	 * Iterates over a single midx
+	 */
+	private static class LocalMidxIterator implements MidxIterator {
+
+		private final MultiPackIndexV1 midx;
+
+		private int position;
+
+		private final MutableEntry entry;
+
+		/**
+		 * Iterator over a single idx (ignoring the bse)
+		 *
+		 * @param midx
+		 *            the midx to iterate
+		 */
+		LocalMidxIterator(MultiPackIndexV1 midx) {
+			this.midx = midx;
+			this.entry = new MutableEntry();
+		}
+
+		@Override
+		public boolean hasNext() {
+			return position < midx.idx.getObjectCount();
+		}
+
+		@Override
+		public MutableEntry next() {
+			MutableEntry current = peek();
+			position++;
+			return current;
+		}
+
+		@Override
+		public MutableEntry peek() {
+			midx.idx.readOidAt(position, entry.oid);
+			midx.offsets.getObjectOffset(position, entry.packOffset);
+			return entry;
+		}
+
+		@Override
+		public List<String> getPackNames() {
+			return Arrays.asList(midx.getPackNames());
+		}
+	}
+
+	private static class ReverseIndex {
+		private final byte[] bitmappedPackfiles;
+
+		private final byte[] bitmapPackOrder;
+
+		private final OffsetLookup offsets;
+
+		private final OidLookup oids;
+
+		ReverseIndex(byte[] bitmapPackOrder, OidLookup oids,
+				OffsetLookup offsets, byte[] bitmappedPackfiles) {
+			this.bitmappedPackfiles = bitmappedPackfiles;
+			this.bitmapPackOrder = bitmapPackOrder;
+			this.oids = oids;
+			this.offsets = offsets;
+		}
+
+		public int findBitmapPosition(PackOffset po) {
+			if (bitmapPackOrder == null || bitmappedPackfiles == null) {
+				return -1;
+			}
+
+			/*
+			 * Bitmapped Packfiles (ID: {'B', 'T', 'M', 'P'}) Stores a table of
+			 * two 4-byte unsigned integers in network order. Each table entry
+			 * corresponds to a single pack (in the order that they appear above
+			 * in the `PNAM` chunk). The values for each table entry are as
+			 * follows: - The first bit position (in pseudo-pack order, see
+			 * below) to contain an object from that pack. - The number of bits
+			 * whose objects are selected from that pack.
+			 */
+			int packStartBit = NB.decodeInt32(bitmappedPackfiles,
+					po.getPackId() * 8);
+			int packBitLength = NB.decodeInt32(bitmappedPackfiles,
+					(po.getPackId() * 8) + 4);
+			return binarySearch(packStartBit, packStartBit + packBitLength, po);
+		}
+
+		private int binarySearch(int start, int end, PackOffset needle) {
+			PackOffset result = new PackOffset();
+			int low = start;
+			int high = end;
+			while (low < high) {
+				int mid = (low + high) >>> 1;
+				int midxPosition = NB.decodeInt32(bitmapPackOrder, mid * 4);
+				offsets.getObjectOffset(midxPosition, result);
+				int cmp = needle.compareTo(result);
+				if (cmp < 0) {
+					high = mid;
+				} else if (cmp == 0) {
+					return mid;
+				} else {
+					low = mid + 1;
+				}
+			}
+			return -1;
+		}
+
+		public ObjectId getObjectId(int bitmapPosition) {
+			if (bitmapPackOrder == null) {
+				return null;
+			}
+			int midxPosition = NB.decodeInt32(bitmapPackOrder,
+					bitmapPosition * 4);
+			return oids.getObjectAt(midxPosition);
+		}
+
+		public long getMemorySize() {
+			return (long) byteArrayLengh(bitmapPackOrder)
+					+ byteArrayLengh(bitmappedPackfiles);
+		}
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MultiPackIndexWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MultiPackIndexWriter.java
index 993e7df..4d2e580 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MultiPackIndexWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MultiPackIndexWriter.java
@@ -10,6 +10,7 @@
 package org.eclipse.jgit.internal.storage.midx;
 
 import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.CHUNK_LOOKUP_WIDTH;
+import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.MIDX_CHUNKID_BITMAPPEDPACKS;
 import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.MIDX_CHUNKID_LARGEOFFSETS;
 import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.MIDX_CHUNKID_OBJECTOFFSETS;
 import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.MIDX_CHUNKID_OIDFANOUT;
@@ -137,6 +138,8 @@ private List<ChunkHeader> createChunkHeaders(PackIndexMerger data) {
 		}
 		chunkHeaders.add(new ChunkHeader(MIDX_CHUNKID_REVINDEX,
 				4L * data.getUniqueObjectCount(), this::writeRidx));
+		chunkHeaders.add(new ChunkHeader(MIDX_CHUNKID_BITMAPPEDPACKS,
+				8L * data.getPackCount(), this::writeBitmappedPackfiles));
 
 		int packNamesSize = data.getPackNames().stream()
 				.mapToInt(String::length).map(i -> i + 1 /* null at the end */)
@@ -308,13 +311,12 @@ private void writeRidx(WriteContext ctx) throws IOException {
 			MidxMutableEntry e = iterator.next();
 			OffsetPosition op = new OffsetPosition(e.getOffset(), midxPosition);
 			midxPosition++;
-			packOffsets.computeIfAbsent(Integer.valueOf(e.getPackId()),
-					k -> new ArrayList<>()).add(op);
+			packOffsets.computeIfAbsent(e.getPackId(), k -> new ArrayList<>())
+					.add(op);
 		}
 
 		for (int i = 0; i < ctx.data.getPackCount(); i++) {
-			List<OffsetPosition> offsetsForPack = packOffsets
-					.get(Integer.valueOf(i));
+			List<OffsetPosition> offsetsForPack = packOffsets.get(i);
 			if (offsetsForPack == null) {
 				continue;
 			}
@@ -328,6 +330,21 @@ private void writeRidx(WriteContext ctx) throws IOException {
 		}
 	}
 
+	private void writeBitmappedPackfiles(WriteContext ctx) throws IOException {
+		int[] objsPerPack = ctx.data.getObjectsPerPack();
+
+		byte[] buffer = new byte[8 * objsPerPack.length];
+		int bufferPos = 0;
+		int accruedBitmapPositions = 0;
+		for (int pack = 0; pack < objsPerPack.length; pack++) {
+			NB.encodeInt32(buffer, bufferPos, accruedBitmapPositions);
+			NB.encodeInt32(buffer, bufferPos + 4, objsPerPack[pack]);
+			accruedBitmapPositions += objsPerPack[pack];
+			bufferPos += 8;
+		}
+		ctx.out.write(buffer);
+	}
+
 	/**
 	 * Write the large offset chunk
 	 * <p>
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/PackIndexMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/PackIndexMerger.java
index fd040b9..4a296ee 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/PackIndexMerger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/PackIndexMerger.java
@@ -92,6 +92,8 @@ private void fill(int packId, PackIndex.MutableEntry other) {
 
 	private final int uniqueObjectCount;
 
+	private final int[] objectsPerPack;
+
 	/**
 	 * Build a common view of these pack indexes
 	 * <p>
@@ -104,6 +106,7 @@ private void fill(int packId, PackIndex.MutableEntry other) {
 		this.packNames = packs.keySet().stream().toList();
 		this.indexes = packs.values().stream().toList();
 
+		objectsPerPack = new int[packNames.size()];
 		// Iterate for duplicates
 		int objectCount = 0;
 		boolean hasLargeOffsets = false;
@@ -127,6 +130,7 @@ private void fill(int packId, PackIndex.MutableEntry other) {
 
 			lastSeen.fromObjectId(entry.oid);
 			objectCount++;
+			objectsPerPack[entry.packId]++;
 		}
 		uniqueObjectCount = objectCount;
 		offsetsOver31BitsCount = over31bits;
@@ -164,6 +168,16 @@ int getOffsetsOver31BitsCount() {
 	}
 
 	/**
+	 * Number of objects selected for the midx per packid
+	 *
+	 * @return array where position n contains the amount of objects selected
+	 *         for pack id n
+	 */
+	int[] getObjectsPerPack() {
+		return objectsPerPack;
+	}
+
+	/**
 	 * List of pack names in alphabetical order.
 	 * <p>
 	 * Order matters: In case of duplicates, the multipack index prefers the
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/BitmapCommit.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/BitmapCommit.java
index 33c478e..41cbe4b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/BitmapCommit.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/BitmapCommit.java
@@ -30,8 +30,21 @@ public final class BitmapCommit extends ObjectId {
 		this.addToIndex = false;
 	}
 
-	BitmapCommit(AnyObjectId objectId, boolean reuseWalker, int flags,
-				 boolean addToIndex) {
+	// Visible for testing
+	/**
+	 * Commit that should get a bitmap
+	 *
+	 * @param objectId
+	 *            objectId of the commit
+	 * @param reuseWalker
+	 *            if the bitmap walker can be reused
+	 * @param flags
+	 *            flags
+	 * @param addToIndex
+	 *            if the bitmap should be added to the index
+	 */
+	public BitmapCommit(AnyObjectId objectId, boolean reuseWalker, int flags,
+			boolean addToIndex) {
 		super(objectId);
 		this.reuseWalker = reuseWalker;
 		this.flags = flags;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackBitmapCalculator.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackBitmapCalculator.java
new file mode 100644
index 0000000..7fa635f
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackBitmapCalculator.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2026, Google LLC.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.internal.storage.pack;
+
+import java.io.IOException;
+import java.text.MessageFormat;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+
+import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.internal.storage.file.PackBitmapIndexBuilder;
+import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.BitmapIndex;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectReader;
+import org.eclipse.jgit.lib.ProgressMonitor;
+import org.eclipse.jgit.revwalk.BitmapWalker;
+import org.eclipse.jgit.storage.pack.PackConfig;
+
+/**
+ * Helper to find out interesting commits, create their bitmaps and write them
+ * into the PackBitmapIndexBuilder.
+ */
+public class PackBitmapCalculator {
+
+	private final PackConfig config;
+
+	/**
+	 * Constructor
+	 *
+	 * @param config
+	 *            configuration
+	 */
+	public PackBitmapCalculator(PackConfig config) {
+		this.config = config;
+	}
+
+	/**
+	 * Choose commits, create bitmaps and send them to the builder
+	 *
+	 * @param reader
+	 *            an object reader
+	 * @param pm
+	 *            a progress monitor
+	 * @param wants
+	 *            where to start walking looking for commits to bitmap
+	 * @param numCommits
+	 *            expected number of new commits to include in the bitmap
+	 * @param excludeFromBitmapSelection
+	 *            commits to ignore
+	 * @param writeBitmaps
+	 *            store of newly created bitmaps
+	 * @throws IOException
+	 *             an error
+	 */
+	public void calculate(ObjectReader reader, ProgressMonitor pm,
+			int numCommits, Set<? extends ObjectId> wants,
+			Set<? extends ObjectId> excludeFromBitmapSelection,
+			PackBitmapIndexBuilder writeBitmaps) throws IOException {
+		PackWriterBitmapPreparer bitmapPreparer = new PackWriterBitmapPreparer(
+				reader, writeBitmaps, pm, wants, config);
+
+		Collection<BitmapCommit> selectedCommits = bitmapPreparer
+				.selectCommits(numCommits, excludeFromBitmapSelection);
+		pm.beginTask(JGitText.get().buildingBitmaps, selectedCommits.size());
+
+		BitmapWalker walker = bitmapPreparer.newBitmapWalker();
+		AnyObjectId last = null;
+		for (BitmapCommit cmit : selectedCommits) {
+			if (!cmit.isReuseWalker()) {
+				walker = bitmapPreparer.newBitmapWalker();
+			}
+			BitmapIndex.BitmapBuilder bitmap = walker
+					.findObjects(Collections.singleton(cmit), null, false);
+
+			if (last != null && cmit.isReuseWalker() && !bitmap.contains(last))
+				throw new IllegalStateException(
+						MessageFormat.format(JGitText.get().bitmapMissingObject,
+								cmit.name(), last.name()));
+			last = BitmapCommit.copyFrom(cmit).build();
+			writeBitmaps.processBitmapForWrite(cmit, bitmap.build(),
+					cmit.getFlags());
+
+			// The bitmap walker should stop when the walk hits the previous
+			// commit, which saves time.
+			walker.setPrevCommit(last);
+			walker.setPrevBitmap(bitmap);
+
+			pm.update(1);
+		}
+		pm.endTask();
+	}
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java
index 27fb814..c2d7577 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java
@@ -2534,40 +2534,10 @@ public boolean prepareBitmapIndex(ProgressMonitor pm) throws IOException {
 		// Allow byName to be GC'd if JVM GC runs before the end of the method.
 		byName = null;
 
-		PackWriterBitmapPreparer bitmapPreparer = new PackWriterBitmapPreparer(
-				reader, writeBitmaps, pm, stats.interestingObjects, config);
+		PackBitmapCalculator bitmapWrite = new PackBitmapCalculator(config);
+		bitmapWrite.calculate(reader, pm, numCommits, stats.interestingObjects,
+				excludeFromBitmapSelection, writeBitmaps);
 
-		Collection<BitmapCommit> selectedCommits = bitmapPreparer
-				.selectCommits(numCommits, excludeFromBitmapSelection);
-
-		beginPhase(PackingPhase.BUILDING_BITMAPS, pm, selectedCommits.size());
-
-		BitmapWalker walker = bitmapPreparer.newBitmapWalker();
-		AnyObjectId last = null;
-		for (BitmapCommit cmit : selectedCommits) {
-			if (!cmit.isReuseWalker()) {
-				walker = bitmapPreparer.newBitmapWalker();
-			}
-			BitmapBuilder bitmap = walker.findObjects(
-					Collections.singleton(cmit), null, false);
-
-			if (last != null && cmit.isReuseWalker() && !bitmap.contains(last))
-				throw new IllegalStateException(MessageFormat.format(
-						JGitText.get().bitmapMissingObject, cmit.name(),
-						last.name()));
-			last = BitmapCommit.copyFrom(cmit).build();
-			writeBitmaps.processBitmapForWrite(cmit, bitmap.build(),
-					cmit.getFlags());
-
-			// The bitmap walker should stop when the walk hits the previous
-			// commit, which saves time.
-			walker.setPrevCommit(last);
-			walker.setPrevBitmap(bitmap);
-
-			pm.update(1);
-		}
-
-		endPhase(pm);
 		return true;
 	}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
index 56b801e..73c7006 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
@@ -1122,4 +1122,11 @@ public final class ConfigConstants {
 	 * @since 7.5
 	 */
 	public static final String CONFIG_KEY_MULTIPACKINDEX = "multiPackIndex";
+
+	/**
+	 * The "packRefs" key
+	 *
+	 * @since 7.6
+	 */
+	public static final String CONFIG_KEY_PACK_REFS = "packRefs";
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/GcConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/GcConfig.java
new file mode 100644
index 0000000..7239bd7
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/GcConfig.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2026, Matthias Sohn <matthias.sohn@sap.com>
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.lib;
+
+import org.eclipse.jgit.lib.Config.SectionParser;
+
+/**
+ * GC configuration settings.
+ *
+ * @since 7.6
+ */
+public class GcConfig {
+	/** Key for {@link Config#get(SectionParser)}. */
+	public static final Config.SectionParser<GcConfig> KEY = GcConfig::new;
+
+	/**
+	 * Whether to pack refs during gc.
+	 */
+	public enum PackRefsMode {
+		/**
+		 * Pack no refs.
+		 */
+		FALSE,
+		/**
+		 * Pack all refs except symbolic refs.
+		 */
+		TRUE,
+		/**
+		 * Pack all refs except symbolic refs within all non-bare repositories.
+		 */
+		NOTBARE
+	}
+
+	private final PackRefsMode packRefs;
+
+	/**
+	 * Create a new gc configuration from the passed configuration.
+	 *
+	 * @param rc
+	 *            git configuration
+	 */
+	public GcConfig(Config rc) {
+		this.packRefs = rc.getEnum(ConfigConstants.CONFIG_GC_SECTION, null,
+				ConfigConstants.CONFIG_KEY_PACK_REFS, PackRefsMode.TRUE);
+	}
+
+	/**
+	 * Create a new gc configuration with the given settings.
+	 *
+	 * @param packRefs
+	 *            whether to pack refs during gc
+	 */
+	public GcConfig(PackRefsMode packRefs) {
+		this.packRefs = packRefs;
+	}
+
+	/**
+	 * Get the pack refs mode configuring which refs to pack during gc.
+	 *
+	 * @return the pack refs mode configuring which refs to pack during gc.
+	 */
+	public PackRefsMode getPackRefs() {
+		return packRefs;
+	}
+
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefWriter.java
index 41917f8..58aed82 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefWriter.java
@@ -139,6 +139,7 @@ public void writePackedRefs() throws IOException {
 		if (peeled) {
 			w.write(RefDirectory.PACKED_REFS_HEADER);
 			w.write(RefDirectory.PACKED_REFS_PEELED);
+			w.write(RefDirectory.PACKED_REFS_SORTED);
 			w.write('\n');
 		}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/TemporaryBuffer.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/TemporaryBuffer.java
index fb893a6..0f45162 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/TemporaryBuffer.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/TemporaryBuffer.java
@@ -52,6 +52,8 @@ public abstract class TemporaryBuffer extends OutputStream {
 	/** If {@link #inCoreLimit} has been reached, remainder goes here. */
 	private OutputStream overflow;
 
+	private boolean destroyed;
+
 	/**
 	 * Create a new empty temporary buffer.
 	 *
@@ -85,6 +87,7 @@ protected TemporaryBuffer(int estimatedSize, int limit) {
 	/** {@inheritDoc} */
 	@Override
 	public void write(int b) throws IOException {
+		checkDestroyed();
 		if (overflow != null) {
 			overflow.write(b);
 			return;
@@ -106,6 +109,7 @@ public void write(int b) throws IOException {
 	/** {@inheritDoc} */
 	@Override
 	public void write(byte[] b, int off, int len) throws IOException {
+		checkDestroyed();
 		if (overflow == null) {
 			while (len > 0) {
 				Block s = last();
@@ -152,6 +156,7 @@ protected void doFlush() throws IOException {
 	 *             writing to a local temporary file.
 	 */
 	public void copy(InputStream in) throws IOException {
+		checkDestroyed();
 		if (blocks != null) {
 			for (;;) {
 				Block s = last();
@@ -183,6 +188,7 @@ public void copy(InputStream in) throws IOException {
 	 * @return total length of the buffer, in bytes.
 	 */
 	public long length() {
+		checkDestroyedUnchecked();
 		return inCoreLength();
 	}
 
@@ -201,6 +207,7 @@ private long inCoreLength() {
 	 *             an error occurred reading from a local temporary file
 	 */
 	public byte[] toByteArray() throws IOException {
+		checkDestroyed();
 		final long len = length();
 		if (Integer.MAX_VALUE < len)
 			throw new OutOfMemoryError(JGitText.get().lengthExceedsMaximumArraySize);
@@ -245,6 +252,7 @@ public String toString(int limit) {
 	 * @since 4.2
 	 */
 	public byte[] toByteArray(int limit) throws IOException {
+		checkDestroyed();
 		final long len = Math.min(length(), limit);
 		if (Integer.MAX_VALUE < len)
 			throw new OutOfMemoryError(
@@ -281,6 +289,7 @@ public String toString(int limit) {
 	 */
 	public void writeTo(OutputStream os, ProgressMonitor pm)
 			throws IOException {
+		checkDestroyed();
 		if (pm == null)
 			pm = NullProgressMonitor.INSTANCE;
 		for (Block b : blocks) {
@@ -301,6 +310,7 @@ public void writeTo(OutputStream os, ProgressMonitor pm)
 	 *             an error occurred opening the temporary file.
 	 */
 	public InputStream openInputStream() throws IOException {
+		checkDestroyed();
 		return new BlockInputStream();
 	}
 
@@ -315,6 +325,7 @@ public InputStream openInputStream() throws IOException {
 	 * @since 4.11
 	 */
 	public InputStream openInputStreamWithAutoDestroy() throws IOException {
+		checkDestroyed();
 		return new BlockInputStream() {
 			@Override
 			public void close() throws IOException {
@@ -328,13 +339,15 @@ public void close() throws IOException {
 	 * Reset this buffer for reuse, purging all buffered content.
 	 */
 	public void reset() {
-		if (overflow != null) {
-			destroy();
+		if (destroyed) {
+			return;
 		}
-		if (blocks != null)
+		closeOverflow();
+		if (blocks != null) {
 			blocks.clear();
-		else
+		} else {
 			blocks = new ArrayList<>(initialBlocks);
+		}
 		blocks.add(new Block(Math.min(inCoreLimit, Block.SZ)));
 	}
 
@@ -372,24 +385,24 @@ private void switchToOverflow() throws IOException {
 		overflow.write(last.buffer, 0, last.count);
 	}
 
-	/** {@inheritDoc} */
 	@Override
 	public void close() throws IOException {
-		if (overflow != null) {
-			try {
-				overflow.close();
-			} finally {
-				overflow = null;
-			}
+		if (destroyed) {
+			return;
 		}
+		closeOverflow();
 	}
 
 	/**
 	 * Clear this buffer so it has no data, and cannot be used again.
 	 */
 	public void destroy() {
+		destroyed = true;
 		blocks = null;
+		closeOverflow();
+	}
 
+	private void closeOverflow() {
 		if (overflow != null) {
 			try {
 				overflow.close();
@@ -401,6 +414,19 @@ public void destroy() {
 		}
 	}
 
+	private void checkDestroyed() throws IOException {
+		if (destroyed) {
+			throw new IOException(JGitText.get().temporaryBufferIsDestroyed);
+		}
+	}
+
+	private void checkDestroyedUnchecked() {
+		if (destroyed) {
+			throw new UncheckedIOException(
+					new IOException(JGitText.get().temporaryBufferIsDestroyed));
+		}
+	}
+
 	/**
 	 * A fully buffered output stream using local disk storage for large data.
 	 * <p>
@@ -462,6 +488,7 @@ protected OutputStream overflow() throws IOException {
 
 		@Override
 		public long length() {
+			super.checkDestroyedUnchecked();
 			if (onDiskFile == null) {
 				return super.length();
 			}
diff --git a/pom.xml b/pom.xml
index f84160c..3db9955 100644
--- a/pom.xml
+++ b/pom.xml
@@ -120,7 +120,7 @@
 
     <jgit-last-release-version>7.5.0.202512021534-r</jgit-last-release-version>
     <ant-version>1.10.15</ant-version>
-    <apache-sshd-version>2.16.0</apache-sshd-version>
+    <apache-sshd-version>2.17.1</apache-sshd-version>
     <jsch-version>0.1.55</jsch-version>
     <jzlib-version>1.1.3</jzlib-version>
     <javaewah-version>1.2.3</javaewah-version>
@@ -131,24 +131,24 @@
     <osgi-core-version>6.0.0</osgi-core-version>
     <servlet-api-version>4.0.4</servlet-api-version>
     <jetty-version>12.1.5</jetty-version>
-    <japicmp-version>0.24.2</japicmp-version>
+    <japicmp-version>0.25.0</japicmp-version>
     <httpclient-version>4.5.14</httpclient-version>
     <httpcore-version>4.4.16</httpcore-version>
     <slf4j-version>2.0.17</slf4j-version>
     <maven-javadoc-plugin-version>3.12.0</maven-javadoc-plugin-version>
     <gson-version>2.13.2</gson-version>
     <bouncycastle-version>1.83</bouncycastle-version>
-    <spotbugs-maven-plugin-version>4.9.8.1</spotbugs-maven-plugin-version>
+    <spotbugs-maven-plugin-version>4.9.8.2</spotbugs-maven-plugin-version>
     <maven-project-info-reports-plugin-version>3.9.0</maven-project-info-reports-plugin-version>
     <maven-jxr-plugin-version>3.6.0</maven-jxr-plugin-version>
     <maven-surefire-plugin-version>3.5.4</maven-surefire-plugin-version>
     <maven-surefire-report-plugin-version>${maven-surefire-plugin-version}</maven-surefire-report-plugin-version>
     <maven-compiler-plugin-version>3.14.1</maven-compiler-plugin-version>
-    <plexus-compiler-version>2.16.0</plexus-compiler-version>
+    <plexus-compiler-version>2.16.1</plexus-compiler-version>
     <hamcrest-version>3.0</hamcrest-version>
-    <assertj-version>3.27.6</assertj-version>
+    <assertj-version>3.27.7</assertj-version>
     <jna-version>5.18.1</jna-version>
-    <byte-buddy-version>1.18.2</byte-buddy-version>
+    <byte-buddy-version>1.18.4</byte-buddy-version>
 
     <!-- Properties to enable jacoco code coverage analysis -->
     <sonar.core.codeCoveragePlugin>jacoco</sonar.core.codeCoveragePlugin>
@@ -184,7 +184,7 @@
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-jar-plugin</artifactId>
-          <version>3.4.2</version>
+          <version>3.5.0</version>
           <configuration>
             <archive>
               <manifestEntries>
@@ -220,7 +220,7 @@
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-antrun-plugin</artifactId>
-          <version>3.1.0</version>
+          <version>3.2.0</version>
         </plugin>
 
         <plugin>
@@ -232,7 +232,7 @@
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-source-plugin</artifactId>
-          <version>3.3.1</version>
+          <version>3.4.0</version>
         </plugin>
 
         <plugin>
@@ -277,7 +277,7 @@
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-pmd-plugin</artifactId>
-          <version>3.27.0</version>
+          <version>3.28.0</version>
           <configuration>
             <inputEncoding>${project.build.sourceEncoding}</inputEncoding>
             <minimumTokens>100</minimumTokens>
@@ -352,12 +352,12 @@
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-resources-plugin</artifactId>
-          <version>3.3.1</version>
+          <version>3.4.0</version>
         </plugin>
         <plugin>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-maven-plugin</artifactId>
-          <version>3.5.0</version>
+          <version>3.5.10</version>
         </plugin>
         <plugin>
           <groupId>org.eclipse.dash</groupId>
@@ -1020,7 +1020,7 @@
       <dependency>
         <groupId>org.mockito</groupId>
         <artifactId>mockito-core</artifactId>
-        <version>5.20.0</version>
+        <version>5.21.0</version>
       </dependency>
 
       <dependency>
@@ -1129,7 +1129,7 @@
               <dependency>
                 <groupId>org.eclipse.jdt</groupId>
                 <artifactId>ecj</artifactId>
-                <version>3.43.0</version>
+                <version>3.44.0</version>
               </dependency>
             </dependencies>
           </plugin>
diff --git a/tools/maven-central/Pipfile.lock b/tools/maven-central/Pipfile.lock
index 40358c9..e566398 100644
--- a/tools/maven-central/Pipfile.lock
+++ b/tools/maven-central/Pipfile.lock
@@ -27,104 +27,138 @@
         },
         "certifi": {
             "hashes": [
-                "sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407",
-                "sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5"
+                "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c",
+                "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120"
             ],
             "markers": "python_version >= '3.7'",
-            "version": "==2025.8.3"
+            "version": "==2026.1.4"
         },
         "charset-normalizer": {
             "hashes": [
-                "sha256:00237675befef519d9af72169d8604a067d92755e84fe76492fef5441db05b91",
-                "sha256:02425242e96bcf29a49711b0ca9f37e451da7c70562bc10e8ed992a5a7a25cc0",
-                "sha256:027b776c26d38b7f15b26a5da1044f376455fb3766df8fc38563b4efbc515154",
-                "sha256:07a0eae9e2787b586e129fdcbe1af6997f8d0e5abaa0bc98c0e20e124d67e601",
-                "sha256:0cacf8f7297b0c4fcb74227692ca46b4a5852f8f4f24b3c766dd94a1075c4884",
-                "sha256:0e78314bdc32fa80696f72fa16dc61168fda4d6a0c014e0380f9d02f0e5d8a07",
-                "sha256:0f2be7e0cf7754b9a30eb01f4295cc3d4358a479843b31f328afd210e2c7598c",
-                "sha256:13faeacfe61784e2559e690fc53fa4c5ae97c6fcedb8eb6fb8d0a15b475d2c64",
-                "sha256:14c2a87c65b351109f6abfc424cab3927b3bdece6f706e4d12faaf3d52ee5efe",
-                "sha256:1606f4a55c0fd363d754049cdf400175ee96c992b1f8018b993941f221221c5f",
-                "sha256:16a8770207946ac75703458e2c743631c79c59c5890c80011d536248f8eaa432",
-                "sha256:18343b2d246dc6761a249ba1fb13f9ee9a2bcd95decc767319506056ea4ad4dc",
-                "sha256:18b97b8404387b96cdbd30ad660f6407799126d26a39ca65729162fd810a99aa",
-                "sha256:1bb60174149316da1c35fa5233681f7c0f9f514509b8e399ab70fea5f17e45c9",
-                "sha256:1e8ac75d72fa3775e0b7cb7e4629cec13b7514d928d15ef8ea06bca03ef01cae",
-                "sha256:1ef99f0456d3d46a50945c98de1774da86f8e992ab5c77865ea8b8195341fc19",
-                "sha256:2001a39612b241dae17b4687898843f254f8748b796a2e16f1051a17078d991d",
-                "sha256:23b6b24d74478dc833444cbd927c338349d6ae852ba53a0d02a2de1fce45b96e",
-                "sha256:252098c8c7a873e17dd696ed98bbe91dbacd571da4b87df3736768efa7a792e4",
-                "sha256:257f26fed7d7ff59921b78244f3cd93ed2af1800ff048c33f624c87475819dd7",
-                "sha256:2c322db9c8c89009a990ef07c3bcc9f011a3269bc06782f916cd3d9eed7c9312",
-                "sha256:30a96e1e1f865f78b030d65241c1ee850cdf422d869e9028e2fc1d5e4db73b92",
-                "sha256:30d006f98569de3459c2fc1f2acde170b7b2bd265dc1943e87e1a4efe1b67c31",
-                "sha256:31a9a6f775f9bcd865d88ee350f0ffb0e25936a7f930ca98995c05abf1faf21c",
-                "sha256:320e8e66157cc4e247d9ddca8e21f427efc7a04bbd0ac8a9faf56583fa543f9f",
-                "sha256:34a7f768e3f985abdb42841e20e17b330ad3aaf4bb7e7aeeb73db2e70f077b99",
-                "sha256:3653fad4fe3ed447a596ae8638b437f827234f01a8cd801842e43f3d0a6b281b",
-                "sha256:3cd35b7e8aedeb9e34c41385fda4f73ba609e561faedfae0a9e75e44ac558a15",
-                "sha256:3cfb2aad70f2c6debfbcb717f23b7eb55febc0bb23dcffc0f076009da10c6392",
-                "sha256:416175faf02e4b0810f1f38bcb54682878a4af94059a1cd63b8747244420801f",
-                "sha256:41d1fc408ff5fdfb910200ec0e74abc40387bccb3252f3f27c0676731df2b2c8",
-                "sha256:42e5088973e56e31e4fa58eb6bd709e42fc03799c11c42929592889a2e54c491",
-                "sha256:4ca4c094de7771a98d7fbd67d9e5dbf1eb73efa4f744a730437d8a3a5cf994f0",
-                "sha256:511729f456829ef86ac41ca78c63a5cb55240ed23b4b737faca0eb1abb1c41bc",
-                "sha256:53cd68b185d98dde4ad8990e56a58dea83a4162161b1ea9272e5c9182ce415e0",
-                "sha256:585f3b2a80fbd26b048a0be90c5aae8f06605d3c92615911c3a2b03a8a3b796f",
-                "sha256:5b413b0b1bfd94dbf4023ad6945889f374cd24e3f62de58d6bb102c4d9ae534a",
-                "sha256:5d8d01eac18c423815ed4f4a2ec3b439d654e55ee4ad610e153cf02faf67ea40",
-                "sha256:6aab0f181c486f973bc7262a97f5aca3ee7e1437011ef0c2ec04b5a11d16c927",
-                "sha256:6cf8fd4c04756b6b60146d98cd8a77d0cdae0e1ca20329da2ac85eed779b6849",
-                "sha256:6fb70de56f1859a3f71261cbe41005f56a7842cc348d3aeb26237560bfa5e0ce",
-                "sha256:6fce4b8500244f6fcb71465d4a4930d132ba9ab8e71a7859e6a5d59851068d14",
-                "sha256:70bfc5f2c318afece2f5838ea5e4c3febada0be750fcf4775641052bbba14d05",
-                "sha256:73dc19b562516fc9bcf6e5d6e596df0b4eb98d87e4f79f3ae71840e6ed21361c",
-                "sha256:74d77e25adda8581ffc1c720f1c81ca082921329452eba58b16233ab1842141c",
-                "sha256:78deba4d8f9590fe4dae384aeff04082510a709957e968753ff3c48399f6f92a",
-                "sha256:86df271bf921c2ee3818f0522e9a5b8092ca2ad8b065ece5d7d9d0e9f4849bcc",
-                "sha256:88ab34806dea0671532d3f82d82b85e8fc23d7b2dd12fa837978dad9bb392a34",
-                "sha256:8999f965f922ae054125286faf9f11bc6932184b93011d138925a1773830bbe9",
-                "sha256:8dcfc373f888e4fb39a7bc57e93e3b845e7f462dacc008d9749568b1c4ece096",
-                "sha256:939578d9d8fd4299220161fdd76e86c6a251987476f5243e8864a7844476ba14",
-                "sha256:96b2b3d1a83ad55310de8c7b4a2d04d9277d5591f40761274856635acc5fcb30",
-                "sha256:a2d08ac246bb48479170408d6c19f6385fa743e7157d716e144cad849b2dd94b",
-                "sha256:b256ee2e749283ef3ddcff51a675ff43798d92d746d1a6e4631bf8c707d22d0b",
-                "sha256:b5e3b2d152e74e100a9e9573837aba24aab611d39428ded46f4e4022ea7d1942",
-                "sha256:b89bc04de1d83006373429975f8ef9e7932534b8cc9ca582e4db7d20d91816db",
-                "sha256:bd28b817ea8c70215401f657edef3a8aa83c29d447fb0b622c35403780ba11d5",
-                "sha256:c60e092517a73c632ec38e290eba714e9627abe9d301c8c8a12ec32c314a2a4b",
-                "sha256:c6dbd0ccdda3a2ba7c2ecd9d77b37f3b5831687d8dc1b6ca5f56a4880cc7b7ce",
-                "sha256:c6e490913a46fa054e03699c70019ab869e990270597018cef1d8562132c2669",
-                "sha256:c6f162aabe9a91a309510d74eeb6507fab5fff92337a15acbe77753d88d9dcf0",
-                "sha256:c6fd51128a41297f5409deab284fecbe5305ebd7e5a1f959bee1c054622b7018",
-                "sha256:cc34f233c9e71701040d772aa7490318673aa7164a0efe3172b2981218c26d93",
-                "sha256:cc9370a2da1ac13f0153780040f465839e6cccb4a1e44810124b4e22483c93fe",
-                "sha256:ccf600859c183d70eb47e05a44cd80a4ce77394d1ac0f79dbd2dd90a69a3a049",
-                "sha256:ce571ab16d890d23b5c278547ba694193a45011ff86a9162a71307ed9f86759a",
-                "sha256:cf1ebb7d78e1ad8ec2a8c4732c7be2e736f6e5123a4146c5b89c9d1f585f8cef",
-                "sha256:d0e909868420b7049dafd3a31d45125b31143eec59235311fc4c57ea26a4acd2",
-                "sha256:d22dbedd33326a4a5190dd4fe9e9e693ef12160c77382d9e87919bce54f3d4ca",
-                "sha256:d716a916938e03231e86e43782ca7878fb602a125a91e7acb8b5112e2e96ac16",
-                "sha256:d79c198e27580c8e958906f803e63cddb77653731be08851c7df0b1a14a8fc0f",
-                "sha256:d95bfb53c211b57198bb91c46dd5a2d8018b3af446583aab40074bf7988401cb",
-                "sha256:e28e334d3ff134e88989d90ba04b47d84382a828c061d0d1027b1b12a62b39b1",
-                "sha256:ec557499516fc90fd374bf2e32349a2887a876fbf162c160e3c01b6849eaf557",
-                "sha256:fb6fecfd65564f208cbf0fba07f107fb661bcd1a7c389edbced3f7a493f70e37",
-                "sha256:fb731e5deb0c7ef82d698b0f4c5bb724633ee2a489401594c5c88b02e6cb15f7",
-                "sha256:fb7f67a1bfa6e40b438170ebdc8158b78dc465a5a67b6dde178a46987b244a72",
-                "sha256:fd10de089bcdcd1be95a2f73dbe6254798ec1bda9f450d5828c96f93e2536b9c",
-                "sha256:fdabf8315679312cfa71302f9bd509ded4f2f263fb5b765cf1433b39106c3cc9"
+                "sha256:027f6de494925c0ab2a55eab46ae5129951638a49a34d87f4c3eda90f696b4ad",
+                "sha256:077fbb858e903c73f6c9db43374fd213b0b6a778106bc7032446a8e8b5b38b93",
+                "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394",
+                "sha256:0d3d8f15c07f86e9ff82319b3d9ef6f4bf907608f53fe9d92b28ea9ae3d1fd89",
+                "sha256:0f04b14ffe5fdc8c4933862d8306109a2c51e0704acfa35d51598eb45a1e89fc",
+                "sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86",
+                "sha256:194f08cbb32dc406d6e1aea671a68be0823673db2832b38405deba2fb0d88f63",
+                "sha256:1bee1e43c28aa63cb16e5c14e582580546b08e535299b8b6158a7c9c768a1f3d",
+                "sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f",
+                "sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8",
+                "sha256:244bfb999c71b35de57821b8ea746b24e863398194a4014e4c76adc2bbdfeff0",
+                "sha256:2677acec1a2f8ef614c6888b5b4ae4060cc184174a938ed4e8ef690e15d3e505",
+                "sha256:277e970e750505ed74c832b4bf75dac7476262ee2a013f5574dd49075879e161",
+                "sha256:2aaba3b0819274cc41757a1da876f810a3e4d7b6eb25699253a4effef9e8e4af",
+                "sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152",
+                "sha256:2c9d3c380143a1fedbff95a312aa798578371eb29da42106a29019368a475318",
+                "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72",
+                "sha256:31fd66405eaf47bb62e8cd575dc621c56c668f27d46a61d975a249930dd5e2a4",
+                "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e",
+                "sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3",
+                "sha256:44c2a8734b333e0578090c4cd6b16f275e07aa6614ca8715e6c038e865e70576",
+                "sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c",
+                "sha256:4902828217069c3c5c71094537a8e623f5d097858ac6ca8252f7b4d10b7560f1",
+                "sha256:4bd5d4137d500351a30687c2d3971758aac9a19208fc110ccb9d7188fbe709e8",
+                "sha256:4fe7859a4e3e8457458e2ff592f15ccb02f3da787fcd31e0183879c3ad4692a1",
+                "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2",
+                "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44",
+                "sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26",
+                "sha256:5947809c8a2417be3267efc979c47d76a079758166f7d43ef5ae8e9f92751f88",
+                "sha256:5ae497466c7901d54b639cf42d5b8c1b6a4fead55215500d2f486d34db48d016",
+                "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede",
+                "sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf",
+                "sha256:5cb4d72eea50c8868f5288b7f7f33ed276118325c1dfd3957089f6b519e1382a",
+                "sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc",
+                "sha256:5f819d5fe9234f9f82d75bdfa9aef3a3d72c4d24a6e57aeaebba32a704553aa0",
+                "sha256:64b55f9dce520635f018f907ff1b0df1fdc31f2795a922fb49dd14fbcdf48c84",
+                "sha256:6515f3182dbe4ea06ced2d9e8666d97b46ef4c75e326b79bb624110f122551db",
+                "sha256:65e2befcd84bc6f37095f5961e68a6f077bf44946771354a28ad434c2cce0ae1",
+                "sha256:6aee717dcfead04c6eb1ce3bd29ac1e22663cdea57f943c87d1eab9a025438d7",
+                "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed",
+                "sha256:6e1fcf0720908f200cd21aa4e6750a48ff6ce4afe7ff5a79a90d5ed8a08296f8",
+                "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133",
+                "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e",
+                "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef",
+                "sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14",
+                "sha256:778d2e08eda00f4256d7f672ca9fef386071c9202f5e4607920b86d7803387f2",
+                "sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0",
+                "sha256:798d75d81754988d2565bff1b97ba5a44411867c0cf32b77a7e8f8d84796b10d",
+                "sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828",
+                "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f",
+                "sha256:7c308f7e26e4363d79df40ca5b2be1c6ba9f02bdbccfed5abddb7859a6ce72cf",
+                "sha256:7fa17817dc5625de8a027cb8b26d9fefa3ea28c8253929b8d6649e705d2835b6",
+                "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328",
+                "sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090",
+                "sha256:837c2ce8c5a65a2035be9b3569c684358dfbf109fd3b6969630a87535495ceaa",
+                "sha256:840c25fb618a231545cbab0564a799f101b63b9901f2569faecd6b222ac72381",
+                "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c",
+                "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb",
+                "sha256:8ef3c867360f88ac904fd3f5e1f902f13307af9052646963ee08ff4f131adafc",
+                "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a",
+                "sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec",
+                "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc",
+                "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac",
+                "sha256:9cd98cdc06614a2f768d2b7286d66805f94c48cde050acdbbb7db2600ab3197e",
+                "sha256:9d1bb833febdff5c8927f922386db610b49db6e0d4f4ee29601d71e7c2694313",
+                "sha256:9f7fcd74d410a36883701fafa2482a6af2ff5ba96b9a620e9e0721e28ead5569",
+                "sha256:a59cb51917aa591b1c4e6a43c132f0cdc3c76dbad6155df4e28ee626cc77a0a3",
+                "sha256:a61900df84c667873b292c3de315a786dd8dac506704dea57bc957bd31e22c7d",
+                "sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525",
+                "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894",
+                "sha256:a8bf8d0f749c5757af2142fe7903a9df1d2e8aa3841559b2bad34b08d0e2bcf3",
+                "sha256:a9768c477b9d7bd54bc0c86dbaebdec6f03306675526c9927c0e8a04e8f94af9",
+                "sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a",
+                "sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9",
+                "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14",
+                "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25",
+                "sha256:b5d84d37db046c5ca74ee7bb47dd6cbc13f80665fdde3e8040bdd3fb015ecb50",
+                "sha256:b7cf1017d601aa35e6bb650b6ad28652c9cd78ee6caff19f3c28d03e1c80acbf",
+                "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1",
+                "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3",
+                "sha256:c4ef880e27901b6cc782f1b95f82da9313c0eb95c3af699103088fa0ac3ce9ac",
+                "sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e",
+                "sha256:ca5862d5b3928c4940729dacc329aa9102900382fea192fc5e52eb69d6093815",
+                "sha256:cb01158d8b88ee68f15949894ccc6712278243d95f344770fa7593fa2d94410c",
+                "sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6",
+                "sha256:cc00f04ed596e9dc0da42ed17ac5e596c6ccba999ba6bd92b0e0aef2f170f2d6",
+                "sha256:cd09d08005f958f370f539f186d10aec3377d55b9eeb0d796025d4886119d76e",
+                "sha256:cd4b7ca9984e5e7985c12bc60a6f173f3c958eae74f3ef6624bb6b26e2abbae4",
+                "sha256:ce8a0633f41a967713a59c4139d29110c07e826d131a316b50ce11b1d79b4f84",
+                "sha256:cead0978fc57397645f12578bfd2d5ea9138ea0fac82b2f63f7f7c6877986a69",
+                "sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15",
+                "sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191",
+                "sha256:d9c7f57c3d666a53421049053eaacdd14bbd0a528e2186fcb2e672effd053bb0",
+                "sha256:d9e45d7faa48ee908174d8fe84854479ef838fc6a705c9315372eacbc2f02897",
+                "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd",
+                "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2",
+                "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794",
+                "sha256:e824f1492727fa856dd6eda4f7cee25f8518a12f3c4a56a74e8095695089cf6d",
+                "sha256:e912091979546adf63357d7e2ccff9b44f026c075aeaf25a52d0e95ad2281074",
+                "sha256:eaabd426fe94daf8fd157c32e571c85cb12e66692f15516a83a03264b08d06c3",
+                "sha256:ebf3e58c7ec8a8bed6d66a75d7fb37b55e5015b03ceae72a8e7c74495551e224",
+                "sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838",
+                "sha256:eecbc200c7fd5ddb9a7f16c7decb07b566c29fa2161a16cf67b8d068bd21690a",
+                "sha256:f155a433c2ec037d4e8df17d18922c3a0d9b3232a396690f17175d2946f0218d",
+                "sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d",
+                "sha256:f34be2938726fc13801220747472850852fe6b1ea75869a048d6f896838c896f",
+                "sha256:f820802628d2694cb7e56db99213f930856014862f3fd943d290ea8438d07ca8",
+                "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490",
+                "sha256:f8e160feb2aed042cd657a72acc0b481212ed28b1b9a95c0cee1621b524e1966",
+                "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9",
+                "sha256:fa09f53c465e532f4d3db095e0c55b615f010ad81803d383195b6b5ca6cbf5f3",
+                "sha256:faa3a41b2b66b6e50f84ae4a68c64fcd0c44355741c6374813a800cd6695db9e",
+                "sha256:fd44c878ea55ba351104cb93cc85e74916eb8fa440ca7903e57575e97394f608"
             ],
             "markers": "python_version >= '3.7'",
-            "version": "==3.4.3"
+            "version": "==3.4.4"
         },
         "idna": {
             "hashes": [
-                "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9",
-                "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"
+                "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea",
+                "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902"
             ],
-            "markers": "python_version >= '3.6'",
-            "version": "==3.10"
+            "markers": "python_version >= '3.8'",
+            "version": "==3.11"
         },
         "pyyaml": {
             "hashes": [
@@ -217,11 +251,11 @@
         },
         "urllib3": {
             "hashes": [
-                "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760",
-                "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc"
+                "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed",
+                "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4"
             ],
             "markers": "python_version >= '3.9'",
-            "version": "==2.5.0"
+            "version": "==2.6.3"
         }
     },
     "develop": {
diff --git a/tools/maven-central/README.md b/tools/maven-central/README.md
index 40156a5..d4533d9 100644
--- a/tools/maven-central/README.md
+++ b/tools/maven-central/README.md
@@ -77,9 +77,29 @@
   if the release looks good. You can download uploaded artifacts from there.
   How to manually test a staged release is explained
   [here](https://central.sonatype.org/publish/publish-portal-api/#manually-testing-a-deployment-bundle)
-- publish the new release
+  - create a bearer token as described [here](https://central.sonatype.org/publish/publish-portal-api/#authentication-authorization)
+  - add the sections mentioned [here](https://central.sonatype.org/publish/publish-portal-api/#maven)
+    using the bearer token you created in the previous step to your `~/.m2/settings.xml`
+  - clone the jgit-build-test repo from github
+    ```
+    $ git clone https://github.com/msohn/jgit-build-test
+    ```
+  - update the version in its `pom.xml` to the new JGit release you staged
+  - delete all jgit artifacts from your local m2 repository
+    ```
+    $ rm -r ~/.m2/org/eclipse/jgit
+    ```
+  - build the jgit-built-test maven project to test if all artifacts of the new release
+    can be downloaded and used in a build
+    ```
+    $ mvn clean install -Pcentral.manual.testing
+    ```
+  - commit the version update in jgit-build-test and push it to github
+- if the test build of jgit-build-test succeeded publish the new release
   - by clicking "Publish" on the [portal deployment page](https://central.sonatype.com/publishing/deployments)
   - or by running
     ```
     $ JRELEASER_MAVENCENTRAL_STAGE=PUBLISH jreleaser deploy
     ```
+  - when publication finished check if the new version is available
+    on [Maven Central](https://repo1.maven.org/maven2/org/eclipse/jgit/)