Git development
 help / color / mirror / Atom feed
* [BUG] branch copy/rename update refs without running the reference-transaction hook
@ 2026-10-02  4:12 Никита Поникаров
  2026-10-02 19:37 ` brian m. carlson
  0 siblings, 1 reply; 2+ messages in thread
From: Никита Поникаров @ 2026-10-02  4:12 UTC (permalink / raw)
  To: git

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.<name>.event).

1. `git branch -C <src> <dst>` where <dst> exists and is not checked out
   anywhere: <dst> is overwritten with <src>'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 <src> <dst>` where <dst> does not exist: <dst> is
   created and the hook sees no line for it.

3. `git branch -m/-M <src> <dst>`:
   - files backend: the hook sees the deletion of <src> and a
     "0000... 0000... refs/heads/<dst>" line, but no line carrying
     <dst>'s new value;
   - reftable backend: no line names <dst> at all, and renaming a branch
     away deletes it without a line for it.

4. `git reflog delete --updateref --rewrite <branch>@{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.

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [BUG] branch copy/rename update refs without running the reference-transaction hook
  2026-10-02  4:12 [BUG] branch copy/rename update refs without running the reference-transaction hook Никита Поникаров
@ 2026-10-02 19:37 ` brian m. carlson
  0 siblings, 0 replies; 2+ messages in thread
From: brian m. carlson @ 2026-10-02 19:37 UTC (permalink / raw)
  To: Никита Поникаров
  Cc: git

[-- Attachment #1: Type: text/plain, Size: 2126 bytes --]

On 2026-10-02 at 04:12:55, Никита Поникаров wrote:
> Hi,

Hi,

> 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.<name>.event).
> 
> 1. `git branch -C <src> <dst>` where <dst> exists and is not checked out
>    anywhere: <dst> is overwritten with <src>'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 <src> <dst>` where <dst> does not exist: <dst> is
>    created and the hook sees no line for it.
> 
> 3. `git branch -m/-M <src> <dst>`:
>    - files backend: the hook sees the deletion of <src> and a
>      "0000... 0000... refs/heads/<dst>" line, but no line carrying
>      <dst>'s new value;
>    - reftable backend: no line names <dst> at all, and renaming a branch
>      away deletes it without a line for it.
> 
> 4. `git reflog delete --updateref --rewrite <branch>@{0}` rewinds the
>    branch without invoking the hook, on both backends.

I think there was a recent thread about this at
https://lore.kernel.org/git/CACQ=SRHCOCcmVCgHqd+sjMsZ9LCdSHuXdCo0gkwxXwYgF7iwig@mail.gmail.com/

There were some patches, but they appeared AI generated and were not
picked up.  Perhaps you or someone else could send in some
higher-quality patches not using AI (see
Documentation/SubmittingPatches) that could fix the issue.

I will say that using reference transactions to solve this problem would
be very desirable from a variety of perspectives, especially since it
would probably go a long way to unlocking way better performance for
`git remote rename` with many remote-tracking branches as well.
-- 
brian m. carlson (they/them)
Toronto, Ontario, CA

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 325 bytes --]

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-10-02 19:37 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-02  4:12 [BUG] branch copy/rename update refs without running the reference-transaction hook Никита Поникаров
2026-10-02 19:37 ` brian m. carlson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox