[BUG] git bundle create with bitmaps omits tree required by advertised ref
From: Peter Elmers <hidden>
Date: 2026-09-08 08:23:50
What did you do before the bug happened? (Steps to reproduce your issue)
I created two sibling commits with the same root tree, stored one at a local
branch and the other at a remote-tracking ref, wrote a pack bitmap, and created
a bundle that included the local branch while excluding the remote-tracking
ref.
Adding `-c pack.useBitmaps=false` appears to fix the issue.
The following script reproduces the issue:
#!/bin/sh
set -eu
repro_dir=$(mktemp -d)
source_repo="$repro_dir/source.git"
recipient_repo="$repro_dir/recipient.git"
git init -q --bare -b main "$source_repo"
git -C "$source_repo" config user.name A
git -C "$source_repo" config user.email a@example.com
empty_tree=$(git -C "$source_repo" mktree </dev/null)
base=$(printf 'base\n' | git -C "$source_repo" commit-tree "$empty_tree")
git -C "$source_repo" update-ref refs/heads/main "$base"
git clone -q --bare "$source_repo" "$recipient_repo"
blob=$(printf 'change\n' | git -C "$source_repo" hash-object -w --stdin)
shared_tree=$(printf '100644 blob %s\tfile\n' "$blob" |
git -C "$source_repo" mktree)
remote_tip=$(printf 'original\n' |
git -C "$source_repo" commit-tree "$shared_tree" -p "$base")
local_tip=$(printf 'rewritten\n' |
git -C "$source_repo" commit-tree "$shared_tree" -p "$base")
git -C "$source_repo" update-ref refs/heads/feature "$local_tip"
git -C "$source_repo" update-ref refs/remotes/origin/feature "$remote_tip"
git -C "$source_repo" repack -q -ad --write-bitmap-index
git -C "$source_repo" bundle create "$repro_dir/broken.bundle" \
feature ^refs/remotes/origin/feature
git -C "$recipient_repo" bundle verify "$repro_dir/broken.bundle"
git -C "$recipient_repo" bundle unbundle "$repro_dir/broken.bundle"
git -C "$recipient_repo" cat-file -e "$local_tip^{tree}"
The resulting commit and object topology is:
refs/remotes/origin/feature (excluded)
|
remote_tip
/ \
parent / \ tree
/ \
base shared_tree
\ /
parent \ / tree
\ /
local_tip
|
refs/heads/feature (advertised)
Both tip commits have `base` as their parent and `shared_tree` as their root
tree. The bundle advertises `local_tip` and excludes `remote_tip`.
What did you expect to happen? (Expected behavior)
After `git bundle verify` confirms that the recipient has every declared
prerequisite and `git bundle unbundle` succeeds, every object required by the
advertised `feature` commit should be available. The final `git cat-file`
command should exit successfully.
What happened instead? (Actual behavior)
`git bundle verify` reports that the bundle is okay and `git bundle unbundle`
succeeds, but the final command (cat-file) exits 128:
fatal: Not a valid object name <local-tip>^{tree}
The advertised local commit object is present, but its root tree is absent.
What's different between what you expected and what actually happened?
The bitmap-backed bundle omits an object required by an advertised ref without
declaring the excluded sibling commit as a prerequisite. A recipient containing
all declared prerequisites can therefore accept the bundle but cannot traverse
or check out the advertised commit.
Anything else you want to add:
Adding `-c pack.useBitmaps=false` to `git bundle create` makes the final
`git cat-file` command succeed.
`pack.useBitmapBoundaryTraversal=true` did not prevent the omission in a
separate run of the same commit topology.
So it looks like a bitmap format bug.
Relevant documentation:
https://git-scm.com/docs/git-config#Documentation/git-config.txt-packuseBitmaps
https://git-scm.com/docs/git-config#Documentation/git-config.txt-packuseBitmapBoundaryTraversal
https://git-scm.com/docs/git-bundle#_object_prerequisites
[System Info]
git version:
git version 2.54.0
cpu: x86_64
no commit associated with this build
sizeof-long: 8
sizeof-size_t: 8
shell-path: /bin/sh
rust: disabled
SHA-1: SHA1_DC
SHA-256: SHA256_BLK
default-ref-format: files
default-hash: sha1
uname: Linux 7.0.0-1012-aws #12~24.04.1-Ubuntu SMP PREEMPT Wed Aug 12
14:00:57 UTC 2026 x86_64
compiler info: gnuc: 9.4
libc info: glibc: 2.39
$SHELL (typically, interactive shell): /usr/bin/zsh