From: Никита Поникаров Date: Fri, 02 Oct 2026 04:12:55 GMT Subject: [BUG] branch copy/rename update refs without running the reference-transaction hook Message-ID: Hi, The report below was investigated and drafted by Claude in the process of building a branch-protection tool; I've reviewed it and verified the reproduction before sending. Happy to answer questions or test patches. --- githooks(5) says the reference-transaction hook "is invoked by any Git command that performs reference updates". Some branch copy and rename operations update a ref without invoking it. Observed on git version 2.55.0.windows.5, with the hook registered both in .git/hooks and as a config-defined hook (hook..event). 1. `git branch -C ` where exists and is not checked out anywhere: is overwritten with 's value and the hook is not invoked in any phase. This happens on both the files and the reftable backend. With every documented hook event registered to a logging script, none of them fired, and a GIT_TRACE2_EVENT log showed no child process. 2. `git branch -c ` where does not exist: is created and the hook sees no line for it. 3. `git branch -m/-M `: - files backend: the hook sees the deletion of and a "0000... 0000... refs/heads/" line, but no line carrying 's new value; - reftable backend: no line names at all, and renaming a branch away deletes it without a line for it. 4. `git reflog delete --updateref --rewrite @{0}` rewinds the branch without invoking the hook, on both backends. Reproduction (any POSIX shell): git init -q -b main t && cd t git commit -q --allow-empty -m one git branch other git commit -q --allow-empty -m two git switch -q other printf '#!/bin/sh\necho "hook $1" >>"$PWD/hook.log"\ncat >/dev/null\n' >../h.sh git config hook.log.event reference-transaction git config hook.log.command "sh $(cd ..; pwd)/h.sh" : >hook.log git branch -C other main # main now points at "one" cat hook.log # empty Expected: the hook runs with a line updating refs/heads/main, as it does for `git branch -f main other`. Tools that enforce policy through this hook cannot otherwise see these updates. Note that git already refuses -C/-M onto a branch checked out in any worktree, so the gap is limited to branches that are not checked out.