From: Eric Ju <eric.peijian@gmail.com>
To: git@vger.kernel.org
Cc: ps@pks.im, jltobler@gmail.com, eric.peijian@gmail.com,
ericju711@gmail.com
Subject: [PATCH v2 0/1] refs: add 'preparing' phase to the reference-transaction hook
Date: Mon, 16 Mar 2026 00:51:01 -0400 [thread overview]
Message-ID: <20260316045102.70551-1-eric.peijian@gmail.com> (raw)
In-Reply-To: <20260313193537.62827-1-eric.peijian@gmail.com>
The "reference-transaction" hook currently exposes three phases to callers:
"prepared", "committed", and "aborted". The earliest of these, "prepared",
fires after Git has already acquired exclusive locks on every affected
reference. This is well-suited for last-chance validation, but it arrives
too late for any use case that requires coordination before locking, such
as serializing concurrent transactions across distributed storage nodes.
This series introduces a new "preparing" phase that fires before
refs->be->transaction_prepare() is called, that is, before Git takes any
reference lock on disk. Hook scripts that handle this phase receive the full
list of proposed updates and may reject the transaction by returning a
non-zero exit status, causing Git to abort cleanly before any locks are
acquired.
The motivating use case is Gitaly/Praefect, GitLab's distributed Git storage
layer. Praefect must serialize concurrent writes that target the same
references across replicas. With only the "prepared" phase available, by the
time Praefect can observe a transaction the locks are already held, making
reordering impossible. The "preparing" phase provides the necessary
pre-lock window.
Compatibility note: this change is not strictly backwards compatible. Hook
scripts that do not expect unknown phase strings may return an error when
they encounter "preparing". We consider this acceptable for the same reasons
cited when symref support was added to the hook in a8ae923f85 (refs: support
symrefs in 'reference-transaction' hook, 2024-05-07): the hook is documented
as exposing internal implementation details, and its semantics have been
adjusted before. An alternative of introducing a "reference-transaction-v2"
hook was considered but rejected as unnecessarily heavyweight.
---
Changes since v1:
- Fix commit title to follow "area: description" convention
("refs: add 'preparing' phase to reference-transaction hook")
- Correct phase names in documentation to past tense
("committed", "aborted")
- Fix the sentence about backwards compatibility with unknown phases
- Update die() messages to identify the hook by full name and phase
("ref updates rejected by the reference-transaction hook at its
preparing/prepared phase")
- Consolidate author identity to eric.peijian@gmail.com
- Add clarification in reply to the question about how to use the preparing
phase for write serialization
Eric Ju (1):
refs: add 'preparing' phase to the reference-transaction hook
Documentation/githooks.adoc | 19 ++++++++++++-------
refs.c | 9 ++++++++-
t/t1416-ref-transaction-hooks.sh | 30 ++++++++++++++++++++++++++----
t/t5510-fetch.sh | 7 ++++++-
4 files changed, 52 insertions(+), 13 deletions(-)
Range-diff against v1:
1: 5f9f13a84d ! 1: fb74f21d98 Add preparing state to reference-transaction hook
@@
## Metadata ##
-Author: Eric Ju <eju@gitlab.com>
+Author: Eric Ju <eric.peijian@gmail.com>
## Commit message ##
- Add preparing state to reference-transaction hook
+ refs: add 'preparing' phase to the reference-transaction hook
The "reference-transaction" hook is invoked multiple times during a ref
transaction. Each invocation corresponds to a different phase:
- The "prepared" phase indicates that references have been locked.
- - The "commit" phase indicates that all updates have been written to disk.
- - The "abort" phase indicates that the transaction has been aborted and that
+ - The "committed" phase indicates that all updates have been written to disk.
+ - The "aborted" phase indicates that the transaction has been aborted and that
all changes have been rolled back.
This hook can be used to learn about the updates that Git wants to perform.
@@ Commit message
interfering with the locking state.
This change is strictly speaking not backwards compatible. Existing hook
- scripts that do not know to handle unknown phases handle the "preparing" state
- string will encounter an unknown phase, and that might cause them to return an
- error now. But the hook is considered to expose internal implementation details
+ scripts that do not know how to handle unknown phases may treat
+ 'preparing' as an error and return non-zero.
+ But the hook is considered to expose internal implementation details
of how Git works, and as such we have been a bit more lenient with changing its
exact semantics, like for example in a8ae923f85 (refs: support symrefs in
'reference-transaction' hook, 2024-05-07).
@@ Commit message
Helped-by: Patrick Steinhardt <ps@pks.im>
Helped-by: Justin Tobler <jltobler@gmail.com>
+ Helped-by: Karthik Nayak <karthik.188@gmail.com>
Signed-off-by: Eric Ju <eric.peijian@gmail.com>
## Documentation/githooks.adoc ##
@@ refs.c: int ref_transaction_prepare(struct ref_transaction *transaction,
+ ret = run_transaction_hook(transaction, "preparing");
+ if (ret) {
+ ref_transaction_abort(transaction, err);
-+ die(_("ref updates aborted by %s hook"), "preparing");
++ die(_("ref updates aborted by the reference-transaction hook at its %s state"), "preparing");
+ }
+
ret = refs->be->transaction_prepare(refs, transaction, err);
@@ refs.c: int ref_transaction_prepare(struct ref_transaction *transaction,
if (ret) {
ref_transaction_abort(transaction, err);
- die(_("ref updates aborted by hook"));
-+ die(_("ref updates aborted by %s hook"), "prepared");
++ die(_("ref updates aborted by the reference-transaction hook at its %s state"), "prepared");
}
return 0;
@@ t/t1416-ref-transaction-hooks.sh: test_expect_success 'hook allows updating ref
+ fi
+ EOF
+ test_must_fail git update-ref HEAD POST 2>err &&
-+ test_grep "ref updates aborted by preparing hook" err
++ test_grep "ref updates aborted by the reference-transaction hook at its preparing state" err
+'
+
test_expect_success 'hook aborts updating ref in prepared state' '
@@ t/t1416-ref-transaction-hooks.sh: test_expect_success 'hook aborts updating ref
EOF
test_must_fail git update-ref HEAD POST 2>err &&
- test_grep "ref updates aborted by hook" err
-+ test_grep "ref updates aborted by prepared hook" err
++ test_grep "ref updates aborted by the reference-transaction hook at its prepared state" err
'
test_expect_success 'hook gets all queued updates in prepared state' '
--
2.51.0
next prev parent reply other threads:[~2026-03-16 4:51 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-13 19:35 [PATCH 0/1] Add "preparing" phase to reference-transaction hook eric.peijian
2026-03-13 19:35 ` [PATCH 1/1] Add preparing state " eric.peijian
2026-03-13 21:20 ` Junio C Hamano
2026-03-16 3:09 ` Peijian Ju
2026-03-13 23:05 ` Justin Tobler
2026-03-13 23:09 ` Junio C Hamano
2026-03-16 3:09 ` Peijian Ju
2026-03-16 4:51 ` Eric Ju [this message]
2026-03-16 4:51 ` [PATCH v2 1/1] refs: add 'preparing' phase to the " Eric Ju
2026-03-16 16:24 ` Junio C Hamano
2026-03-16 23:08 ` Peijian Ju
2026-03-16 7:03 ` [PATCH v2 0/1] " Patrick Steinhardt
2026-03-16 23:08 ` Peijian Ju
2026-03-17 2:36 ` [PATCH v3 " Eric Ju
2026-03-17 2:36 ` [PATCH v3 1/1] " Eric Ju
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260316045102.70551-1-eric.peijian@gmail.com \
--to=eric.peijian@gmail.com \
--cc=ericju711@gmail.com \
--cc=git@vger.kernel.org \
--cc=jltobler@gmail.com \
--cc=ps@pks.im \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox