[BUG] reference-transaction reports zero OIDs for branch and tag deletion
- From
Maciej Ciemborowicz <maciej.ciemborowicz@gmail.com>
- Date
- Sep 19, 2026, 13:34 UTC
- Message-ID
- <CACQ=SRGTTdQ+dHXhN6F52dBv5KxZBRfk_Em2fvmEmGJDoB6oTg@mail.gmail.com>
Since Git 2.31, the reference-transaction hook receives all-zero old and new object IDs when a branch or tag is deleted with a high-level command.
For example, `git branch -d topic` produces:
0000000000000000000000000000000000000000 \
0000000000000000000000000000000000000000 \
refs/heads/topicThe same happens with `git branch -D`, `git tag -d`, and deletion of a remote-tracking ref by `git remote prune`.
Git 2.28 through 2.30 reported the previous object ID followed by the all-zero object ID. Starting with Git 2.31, that information is lost. The behavior is still present in Git 2.55 with both the files and reftable backends.
A direct deletion with:
git update-ref -d refs/heads/topic "$old_oid"
continues to report the useful payload:
<old-oid> 0000000000000000000000000000000000000000 refs/heads/topic
Minimal reproducer:
#!/bin/sh
set -eu root=$(mktemp -d)
trap 'rm -rf "$root"' EXIT repo=$root/repo
hooks=$root/hooks
log=$root/transactions git init -q "$repo"
git -C "$repo" config user.name Reproducer
git -C "$repo" config user.email repro@example.com
git -C "$repo" commit --allow-empty -qm initial git -C "$repo" branch topic
git -C "$repo" tag v1 mkdir "$hooks"
cat >"$hooks/reference-transaction" <<'HOOK'
#!/bin/sh
printf '%s\n' "--- $1" >>"$HOOK_LOG"
cat >>"$HOOK_LOG"
HOOK
chmod +x "$hooks/reference-transaction" git -C "$repo" config core.hooksPath "$hooks"
export HOOK_LOG=$log
: >"$log" git -C "$repo" branch -d topic
git -C "$repo" tag -d v1cat "$log"
Actual output for the committed transactions is equivalent to:
0000000000000000000000000000000000000000 \
0000000000000000000000000000000000000000 \
refs/heads/topic
0000000000000000000000000000000000000000 \
0000000000000000000000000000000000000000 \
refs/tags/v1I expected:
<old-oid> 0000000000000000000000000000000000000000 refs/heads/topic
<old-oid> 0000000000000000000000000000000000000000 refs/tags/v1I understand that the reference-transaction documentation permits an all-zero old value when a ref is force-updated without checking its current value. However, `git branch -d` is a safety-checked deletion, Git has already resolved the branch being deleted, and Git 2.28–2.30 provided its old object ID.
Was this loss of information intentional? If not, could the previous object ID be restored for these deletion paths? If it is intentional, the documentation may need to clarify that high-level deletion commands can provide a zero-to-zero record.
The behavior was tested across Git 2.28–2.55. The compatibility results and test implementation are available here:
https://github.com/ciembor/git-hooks-ext/blob/v0.2.0/tests/compat/README.md https://github.com/ciembor/git-hooks-ext/blob/v0.2.0/tests/compat/e2e.sh
Thanks, Maciej Ciemborowicz