Hello,
I found a reproducible hang in `git receive-pack` when pushing a ref update that sends zero objects into a repository that has promisor remote configuration and `.promisor` pack sidecar files.
The same zero-object ref update returns normally when the receiving repository is a normal non-bare repository or a bare repository. It also returns normally if I remove either the promisor remote config or the `.promisor` sidecar files from the receiving repository.
Check the attached script to reproduce the bug.
Environment:
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 gettext: enabled libcurl: 8.5.0 zlib: 1.3 SHA-1: SHA1_DC SHA-256: SHA256_BLK default-ref-format: files default-hash: sha1
OS: Ubuntu 24.04.4 LTS (Noble Numbat)
#!/bin/sh set -eu
GIT=${GIT:-git} ROOT=$(mktemp -d "${TMPDIR:-/tmp}/git-promisor-push-hang.XXXXXX") SRC=$ROOT/src DST=$ROOT/dst UPSTREAM=$ROOT/upstream.git TRACE=$ROOT/trace.log
echo "root: $ROOT" echo "git: $($GIT --version)"
$GIT init -q "$SRC" $GIT -C "$SRC" config user.name Repro $GIT -C "$SRC" config user.email repro@example.invalid
printf A >"$SRC/file" $GIT -C "$SRC" add file $GIT -C "$SRC" commit -q -m A $GIT -C "$SRC" branch topic OLD=$($GIT -C "$SRC" rev-parse topic)
printf B >"$SRC/file" $GIT -C "$SRC" commit -q -am B $GIT -C "$SRC" branch -M main NEW=$($GIT -C "$SRC" rev-parse main)
$GIT clone -q --bare "$SRC" "$UPSTREAM" $GIT init -q "$DST" $GIT -C "$DST" config receive.denycurrentbranch updateInstead $GIT -C "$SRC" push -q "$DST" main:main topic:topic $GIT -C "$DST" checkout -q main
$GIT -C "$DST" config remote.origin.url "file://$UPSTREAM"
$GIT -C "$DST" config remote.origin.promisor true
$GIT -C "$DST" config remote.origin.partialclonefilter blob:none
$GIT -C "$DST" gc -q
for pack in "$DST"/.git/objects/pack/*.pack
do
: >"${pack%.pack}.promisor"
done$GIT -C "$DST" update-ref refs/heads/topic "$OLD"
status=0 timeout --kill-after=2s 8 \ env GIT_TRACE=1 GIT_TRACE_PACKET=1 \ $GIT -C "$SRC" push --porcelain "$DST" HEAD:topic \ >"$TRACE" 2>&1 || status=$?
AFTER=$($GIT -C "$DST" rev-parse refs/heads/topic) ZERO_PACK=no grep -q -- '--pack_header=2,0' "$TRACE" && ZERO_PACK=yes
echo "old: $OLD" echo "new: $NEW" echo "after: $AFTER" echo "push status: $status" echo "zero-object pack observed: $ZERO_PACK" echo "trace: $TRACE"
if test "$status" = 124 && test "$AFTER" = "$OLD" && test "$ZERO_PACK" = yes then echo "BUG REPRODUCED" exit 0 fi
echo "BUG NOT REPRODUCED" exit 1