This is very recent (August 2020) and followed by gitlab-org/gitlab
issue 233964
The hook itself is triggered by cmd/gitaly-hooks/hooks.go
But, GitLab using the recent Git 2.27 and planing for Git 2.28, it is faced with the new reference-transaction
hook (which was introduced in Git 2.27, June 2020):
This hook is invoked by any Git command that performs reference updates.
It executes whenever a reference transaction is prepared, committed or aborted and may thus get called multiple times.
The thread adds:
Due to performance concerns, the reference-transaction
hook is using a cache so it doesn't have to repeatedly find the hook path again.
But in case another hook is getting executed as part of the process, then the cache now points to that second hook instead of the first.
Try and see if using git push --no-verify -all
would help, as a temporary workaround.
This leads to gitlab-org/gitlab-git
issue 1144 where Patrick Steinhardt has sent a fix upstream (meaning to git/git
mailing list).
In order to not repeatedly search for the reference-transaction
hook in case it's getting called multiple times, we use a caching mechanism to only call find_hook()
once.
What was missed though is that the return value of find_hook()
actually comes from a static strbuf
, which means it will get overwritten when calling find_hook()
again.
As a result, we may call the wrong hook with parameters of the reference-transaction
hook.
This scenario was spotted in the wild when executing a git-push
with multiple references, where there are interleaving calls to both the update and the reference-transaction hook.
While initial calls to the reference-transaction
hook work as expected, it will stop working after the next invocation of the update
hook.
The result is that we now start calling the update hook with parameters and stdin of the reference-transaction
hook.
This commit fixes the issue by storing a copy of find_hook()
's return
value in the cache.
The OP Zorro Here adds in the comments:
hopefully GitLab will temporarily fix it from their end
Patrick also addresses that point in MR 2454
There's a bug in the reference-transaction implementation in git-core
which will cause interleaving calls to the reference-transaction
hook to
execute another hook by accident.
While a fix has been proposed upstream, the earliest it may be available is with Git v2.28.1.
So let's remove our reference-transaction hook for now to not expose this broken
behaviour.
I'm disabling this hook in Gitaly so that we can move ahead with the upgrade to Git v2.28.0.
Reverting all the different MRs towards that version would be a major pain.
Note, regarding that reference-transaction hook, Git 2.32 (Q2 2021) is more explicit:
See commit 23c781f, commit 5f308a8 (01 Mar 2021) by Patrick Steinhardt (pks-t
).
(Merged by Junio C Hamano -- gitster
-- in commit 20adca9, 22 Mar 2021)
githooks.txt
: clarify documentation on reference-transaction hook
Signed-off-by: Patrick Steinhardt
The reference-transaction hook doesn't clearly document its scope and what values it receives as input.
Document it to make it less surprising and clearly delimit its (current) scope.
githooks
now includes in its man page:
The hook
does not cover symbolic references (but that may change in the future).
githooks
now includes in its man page:
For each reference update that was added to the transaction, the hook
receives on standard input a line of the format:
<old-value> SP <new-value> SP <ref-name> LF
where:
<old-value>
is the old object name passed into the reference
transaction,
<new-value>
is the new object name to be stored in the
ref and
<ref-name>
is the full name of the ref.
When force updating the reference regardless of its current value or when the reference is to be created anew, <old-value>
is the all-zeroes object name.
To distinguish these cases, you can inspect the current value of
<ref-name>
via git rev-parse
.