git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v3 0/4] refs: run copy and rename through transactions

From
Maciej Ciemborowicz <maciej.ciemborowicz@gmail.com>
Date
Oct 7, 2026, 18:05 UTC
Message-ID
<cover.1791395643.git.maciej.ciemborowicz@gmail.com>
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)
Previous: Patrick SteinhardtNext: Maciej Ciemborowicz
Message 12 of 18 in “[BUG] reference-transaction hook misses destination of git branch -m”
  1. Maciej CiemborowiczSep 19, 2026
  2. Karthik NayakSep 19, 2026
  3. refs: run copy and rename through transactionsMaciej Ciemborowicz, Sep 20, 2026
  4. Junio C HamanoSep 21, 2026
  5. Junio C HamanoSep 21, 2026
  6. Maciej CiemborowiczSep 22, 2026
  7. refs: run copy and rename through transactionsMaciej Ciemborowicz, Sep 23, 2026
  8. Maciej CiemborowiczSep 30, 2026
  9. Patrick SteinhardtOct 2, 2026
  10. Maciej CiemborowiczOct 2, 2026
  11. Patrick SteinhardtOct 5, 2026
  12. 0/4 refs: run copy and rename through transactionsMaciej Ciemborowicz, Oct 7, 2026
  13. 1/4 refs: distinguish internal transactions from logical updatesMaciej Ciemborowicz, Oct 7, 2026
  14. 2/4 refs: support replacing reflogs in a transactionMaciej Ciemborowicz, Oct 7, 2026
  15. 3/4 refs: run copy and rename through ordinary transactionsMaciej Ciemborowicz, Oct 7, 2026
  16. 4/4 refs: remove backend-specific copy and rename callbacksMaciej Ciemborowicz, Oct 7, 2026
  17. Junio C HamanoOct 7, 2026
  18. Maciej CiemborowiczSep 23, 2026

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.