Git development
 help / color / mirror / Atom feed
From: Maciej Ciemborowicz <maciej.ciemborowicz@gmail.com>
To: git@vger.kernel.org
Cc: Patrick Steinhardt <ps@pks.im>,
	Junio C Hamano <gitster@pobox.com>,
	Karthik Nayak <karthik.188@gmail.com>
Subject: [PATCH v3 0/4] refs: run copy and rename through transactions
Date: Wed, 07 Oct 2026 20:05:13 +0200	[thread overview]
Message-ID: <cover.1791395643.git.maciej.ciemborowicz@gmail.com> (raw)
In-Reply-To: <20260920165037.88524-1-maciej.ciemborowicz@gmail.com>

Reference copy and rename bypass the transaction API. With files, the
reference-transaction hook sees only the source deletion; with reftable,
it sees neither endpoint. This series puts the logical ref updates and
the reflog history into ordinary transactions so hooks can observe and
reject the complete operation.

Thanks to Patrick, Junio and Karthik for their feedback. Following the
review of v2, this version uses ref_transaction_update_reflog(), the API
used by backend migration, to replay history. A new
ref_transaction_replace_reflog() operation supplies the missing ability
to discard destination history before installing the queued entries.

Changes since v2:

* Split the work into four patches: internal hook suppression, reflog
  replacement, copy/rename integration, and removal of the old callbacks.
* Remove the special copy/rename dispatch from backend prepare, finish
  and abort. Each destination points to its source update, so multiple
  copies, renames and ordinary updates can share one transaction.
* Keep the hook-suppression flag private and check it centrally in
  run_transaction_hook(). It is used for the physical packed-refs child
  transaction, whose changes the parent already reports.
* Drop the pre-lock snapshot revalidation. A preparing hook may change
  the source; prepared and committed report the value read under lock.
  Copy sources are locked but are not reported as changes to the hook.
* Stage reflog replacements during prepare. A prepared veto discards
  staging files without restoring old values over live refs or changing
  the source, destination or HEAD history.
* Add coverage for complete reflog contents, mixed transactions, hook
  vetoes, source races and failure paths, and measure the performance
  cost of replaying history.

Backend-specific work remains necessary to implement the transaction
primitives. Files stages logs beside logs/refs using unique temporary
files. For directory/file conflicts and case-only renames, it queues
the destination in packed-refs: the loose source cannot remain visible
while also making room for a loose destination lock. During finish, a
backup preserves the source log until the destination log is installed;
an installation error restores that backup. Reftable writes tombstones
for old destination entries in the same table as the replacement.

The backends' final reflog records remain distinct: files appends
old->old; reftable appends old->zero and zero->old for rename, or
zero->old for copy. Forced reftable copies do change behavior: unrelated
destination history is replaced by source history, matching files when
the source has a reflog.

Replaying history requires O(N) time and memory. Buffered staging avoids
a write system call per entry, but files rename loses its constant-time
reflog move. On macOS/arm64, with no hook configured, median milliseconds
per operation over seven samples of ten operations were:

                    entries       base        v3
  files copy             10       5.05      5.08
  files rename           10       4.88      5.26
  files copy          10000      13.20     16.11
  files rename        10000       5.09     17.09
  reftable copy          10       5.25      6.11
  reftable rename        10       5.81      6.50
  reftable copy       10000      53.39     68.06
  reftable rename     10000      43.44     54.06

Process startup is included. Copy overwrites the same destination;
rename alternates between two names. Reftable starts from a migration
of the same files fixture. Repeated operations add normal log entries
and incur normal reftable compaction. Patch 3 adds
t/perf/p1424-ref-copy-rename.sh; these measurements used a separate
monotonic-clock driver because GNU time is not installed here. The
files rename regression is a cost of this design, not just hook overhead.

Validation covered 15 relevant suites with files and reftable, including
branch, update-ref, hooks, migration, reflogs and worktree refs. The two
new suites contain 34 tests, with backend-specific skips; they also
passed with SHA-256 and AddressSanitizer/UndefinedBehaviorSanitizer.
The reflog prerequisite and main change were tested as intermediate
trees. This was not a full test-suite run or a Linux/Windows run.

Files transactions are still not crash-atomic. A later failure in
finish may leave partial ref changes, as with ordinary transactions.
The source-log backup covers an installation error, not a process crash.
Unrelated nested renames can also contend for the global packed-refs
lock.

The base is 0f8e75abeb. This series is independent of the separate
batched-deletion old-OID fix discussed elsewhere in the thread.

Original patch:
https://lore.kernel.org/git/20260920165037.88524-1-maciej.ciemborowicz@gmail.com/

The range-diff below treats the rewritten and split implementation as
four new commits, so the changes above describe the mapping from v2.

Maciej Ciemborowicz (4):
  refs: distinguish internal transactions from logical updates
  refs: support replacing reflogs in a transaction
  refs: run copy and rename through ordinary transactions
  refs: remove backend-specific copy and rename callbacks

 Documentation/githooks.adoc     |  10 +
 refs.c                          | 200 ++++++++-
 refs.h                          |  25 ++
 refs/debug.c                    |  24 --
 refs/files-backend.c            | 739 +++++++++++++++++---------------
 refs/packed-backend.c           |   2 -
 refs/refs-internal.h            |  28 +-
 refs/reftable-backend.c         | 334 ++-------------
 t/helper/test-ref-store.c       |  76 ++++
 t/perf/p1424-ref-copy-rename.sh |  48 +++
 t/t1424-ref-copy-transaction.sh | 352 +++++++++++++++
 t/t1425-reflog-transaction.sh   |  59 +++
 12 files changed, 1206 insertions(+), 691 deletions(-)
 create mode 100755 t/perf/p1424-ref-copy-rename.sh
 create mode 100755 t/t1424-ref-copy-transaction.sh
 create mode 100755 t/t1425-reflog-transaction.sh

Range-diff against v2:
1:  d852537d8c < -:  ---------- refs: run copy and rename through transactions
-:  ---------- > 1:  6d7c146e57 refs: distinguish internal transactions from logical updates
-:  ---------- > 2:  5c3ec4eb49 refs: support replacing reflogs in a transaction
-:  ---------- > 3:  77af4e809c refs: run copy and rename through ordinary transactions
-:  ---------- > 4:  83fa644fb3 refs: remove backend-specific copy and rename callbacks

base-commit: 0f8e75abebff0877cae681a3d5ff31ac47f54220
-- 
2.39.3 (Apple Git-146)

  parent reply	other threads:[~2026-10-07 18:05 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-19 13:33 [BUG] reference-transaction hook misses destination of git branch -m Maciej Ciemborowicz
2026-09-19 20:52 ` Karthik Nayak
2026-09-20 16:50   ` [PATCH] refs: run copy and rename through transactions Maciej Ciemborowicz
2026-09-21 17:54     ` Junio C Hamano
2026-09-21 23:28       ` Junio C Hamano
2026-09-22 13:08         ` Maciej Ciemborowicz
2026-09-23 13:36     ` [PATCH v2] " Maciej Ciemborowicz
2026-09-30  3:32       ` Maciej Ciemborowicz
2026-10-02 10:56       ` Patrick Steinhardt
2026-10-02 14:16         ` Maciej Ciemborowicz
2026-10-05  6:03           ` Patrick Steinhardt
2026-10-07 18:05     ` Maciej Ciemborowicz [this message]
2026-10-07 18:05       ` [PATCH v3 1/4] refs: distinguish internal transactions from logical updates Maciej Ciemborowicz
2026-10-07 18:05       ` [PATCH v3 2/4] refs: support replacing reflogs in a transaction Maciej Ciemborowicz
2026-10-07 18:05       ` [PATCH v3 3/4] refs: run copy and rename through ordinary transactions Maciej Ciemborowicz
2026-10-07 18:05       ` [PATCH v3 4/4] refs: remove backend-specific copy and rename callbacks Maciej Ciemborowicz
2026-10-07 19:55       ` [PATCH v3 0/4] refs: run copy and rename through transactions Junio C Hamano
2026-10-08  9:44     ` [PATCH v4 " Maciej Ciemborowicz
2026-10-08  9:44       ` [PATCH v4 1/4] refs: distinguish internal transactions from logical updates Maciej Ciemborowicz
2026-10-08  9:44       ` [PATCH v4 2/4] refs: support replacing reflogs in a transaction Maciej Ciemborowicz
2026-10-08  9:44       ` [PATCH v4 3/4] refs: run copy and rename through ordinary transactions Maciej Ciemborowicz
2026-10-08  9:44       ` [PATCH v4 4/4] refs: remove backend-specific copy and rename callbacks Maciej Ciemborowicz
2026-10-08 10:10       ` [PATCH v4 0/4] refs: run copy and rename through transactions Patrick Steinhardt
2026-10-08 10:43         ` Maciej Ciemborowicz
2026-10-08 11:01           ` Maciej Ciemborowicz
2026-10-08 15:45             ` Junio C Hamano
2026-10-08 19:06               ` Maciej Ciemborowicz
2026-10-08 19:19                 ` Kristoffer Haugsbakk
2026-10-08 21:11                   ` Maciej Ciemborowicz
2026-10-09  5:41                 ` Patrick Steinhardt
2026-10-08 15:54         ` Junio C Hamano
2026-09-23 12:49   ` [PATCH v4 0/3] refs: report old OIDs for batched deletions Maciej Ciemborowicz

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=cover.1791395643.git.maciej.ciemborowicz@gmail.com \
    --to=maciej.ciemborowicz@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=karthik.188@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