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

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

From
Maciej Ciemborowicz <maciej.ciemborowicz@gmail.com>
Date
Oct 8, 2026, 09:44 UTC
Message-ID
<cover.1791452597.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 represents the logical ref updates and reflog history through ordinary transactions, allowing hooks to observe and reject the operation.

Junio, thank you for reporting the t0600 and t5510 failures in v3. I reproduced both on macOS with the original base as well. I had not run those suites before submitting v3; they were outside the test selection reported in that cover letter. That was a gap in my validation, and I am sorry for sending the regression.

Patch 2 added a call to prepare_reflog_replacements() after preparing the packed transaction. If packed preparation failed, its error was saved in ret, but the new call overwrote it with success. The files transaction could then proceed despite the failure to prepare packed-refs. The fix jumps to cleanup after freeing the failed packed transaction, preserving the error and releasing the remaining resources. The existing t0600.16 and t5510.35 cover this path; their expectations have not been changed.

Changes since v3:
* Rebase onto 6de20f6092 (The 4th batch, 2026-10-06), the master commit
  used in Junio's report.
* Preserve the packed preparation error in patch 2 as described above.
* Register t1425 and t1424 in t/meson.build in the commits adding them.

The four-patch structure and implementation otherwise remain unchanged. This iteration does not address the concern about the size of the main patch; the range-diff below isolates the correction and registrations.

I ran the complete standard core test collection, including the unit-test executable, on macOS/arm64 with each default ref backend:

  files:    Files=1064, Tests=34710, Result: PASS
  reftable: Files=1064, Tests=34712, Result: PASS

Both full runs include successful t0600, t5510, t1424 and t1425 runs. The build enables Perl, Python, cURL and gettext. The files run used:

  LC_ALL=C make -j8 PYTHON_PATH=/opt/homebrew/bin/python3 \
    GNU_GETTEXT_PATH=/opt/homebrew/opt/gettext \
    DEFAULT_TEST_TARGET=prove GIT_PROVE_OPTS='--jobs 8' test

The reftable run used GIT_TEST_DEFAULT_REF_FORMAT=reftable and ran every t[0-9][0-9][0-9][0-9]-*.sh plus unit-tests/bin/unit-tests through prove, with four jobs and a separate TEST_OUTPUT_DIRECTORY. Backend-specific suites can override the default. The Meson registration check and git diff --check also pass. The contrib test target completed with no unexpected failures; diff-highlight retains two known TODO failures.

The harness totals include skips and expected failures. The files run skipped 126 whole scripts, mostly for unavailable SVN, Perforce and CVS tools. Other skips include GPG, JGit, Windows-specific tests, tests requiring sudo or writable /, case-sensitive filesystem tests, the opt-in 2GB clone test, and t5564 because its web-server setup failed. There are also individual prerequisite-based skips within suites. I have not validated this iteration on Linux or Windows.

The performance trade-off described in v3 remains: replaying history uses O(N) time and memory, replacing the files backend's constant-time reflog rename. The measurements in patch 3 are from the v3 base, not a new benchmark on this base. Files transactions also remain non-atomic with respect to process crashes and failures late in finish.

Previous iteration: https://lore.kernel.org/git/cover.1791395643.git.maciej.ciemborowicz@gmail.com/

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            | 740 +++++++++++++++++---------------
 refs/packed-backend.c           |   2 -
 refs/refs-internal.h            |  28 +-
 refs/reftable-backend.c         | 334 ++------------
 t/helper/test-ref-store.c       |  76 ++++
 t/meson.build                   |   2 +
 t/perf/p1424-ref-copy-rename.sh |  48 +++
 t/t1424-ref-copy-transaction.sh | 352 +++++++++++++++
 t/t1425-reflog-transaction.sh   |  59 +++
 13 files changed, 1209 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 v3:
1:  6d7c146e57 = 1:  948927d8fb refs: distinguish internal transactions from logical updates
2:  5c3ec4eb49 ! 2:  d023da3c09 refs: support replacing reflogs in a transaction
    @@ refs/files-backend.c: static int files_transaction_prepare(struct ref_store *ref
      	transaction->backend_data = backend_data;
      
      	/*
    +@@ refs/files-backend.c: static int files_transaction_prepare(struct ref_store *ref_store,
    + 			if (ret) {
    + 				ref_transaction_free(packed_transaction);
    + 				backend_data->packed_transaction = NULL;
    ++				goto cleanup;
    + 			}
    + 		} else {
    + 			/*
     @@ refs/files-backend.c: static int files_transaction_prepare(struct ref_store *ref_store,
      		}
      	}
    @@ t/helper/test-ref-store.c: static struct command commands[] = {
      	{ "for-each-ref--exclude", cmd_for_each_ref__exclude },
      	{ "resolve-ref", cmd_resolve_ref },
     
    + ## t/meson.build ##
    +@@ t/meson.build: integration_tests = [
    +   't1421-reflog-write.sh',
    +   't1422-show-ref-exists.sh',
    +   't1423-ref-backend.sh',
    ++  't1425-reflog-transaction.sh',
    +   't1430-bad-ref-name.sh',
    +   't1450-fsck.sh',
    +   't1451-fsck-buffer.sh',
    +
      ## t/t1425-reflog-transaction.sh (new) ##
     @@
     +#!/bin/sh
3:  77af4e809c ! 3:  150349f9d0 refs: run copy and rename through ordinary transactions
    @@ refs/files-backend.c: static int files_transaction_prepare(struct ref_store *ref
     -		if (update->flags & REF_DELETING &&
     +		if (update->flags & (REF_DELETING | REF_NEEDS_PACK) &&
      		    !(update->flags & REF_LOG_ONLY) &&
    - 		    !(update->flags & REF_IS_PRUNING)) {
    - 			/*
    + 		    !(update->flags & REF_IS_PRUNING) &&
    + 		    !is_root_ref(update->refname)) {
     @@ refs/files-backend.c: static int files_transaction_prepare(struct ref_store *ref_store,
      					REF_HAVE_NEW | REF_NO_DEREF,
      					&update->new_oid, NULL, NULL,
    @@ t/helper/test-ref-store.c: static struct command commands[] = {
      	{ "for-each-ref--exclude", cmd_for_each_ref__exclude },
      	{ "resolve-ref", cmd_resolve_ref },
     
    + ## t/meson.build ##
    +@@ t/meson.build: integration_tests = [
    +   't1421-reflog-write.sh',
    +   't1422-show-ref-exists.sh',
    +   't1423-ref-backend.sh',
    ++  't1424-ref-copy-transaction.sh',
    +   't1425-reflog-transaction.sh',
    +   't1430-bad-ref-name.sh',
    +   't1450-fsck.sh',
    +
      ## t/perf/p1424-ref-copy-rename.sh (new) ##
     @@
     +#!/bin/sh
4:  83fa644fb3 = 4:  f3f2c7ee11 refs: remove backend-specific copy and rename callbacks
base-commit: 6de20f6092dcf9bdb1c8efe03db4b70c82b423dd
-- 
2.39.3 (Apple Git-146)
Previous: Junio C HamanoNext: Maciej Ciemborowicz
Message 18 of 30 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. 0/4 refs: run copy and rename through transactionsMaciej Ciemborowicz, Oct 8, 2026
  19. 1/4 refs: distinguish internal transactions from logical updatesMaciej Ciemborowicz, Oct 8, 2026
  20. 2/4 refs: support replacing reflogs in a transactionMaciej Ciemborowicz, Oct 8, 2026
  21. 3/4 refs: run copy and rename through ordinary transactionsMaciej Ciemborowicz, Oct 8, 2026
  22. 4/4 refs: remove backend-specific copy and rename callbacksMaciej Ciemborowicz, Oct 8, 2026
  23. Patrick SteinhardtOct 8, 2026
  24. Maciej CiemborowiczOct 8, 2026
  25. Maciej CiemborowiczOct 8, 2026
  26. Junio C HamanoOct 8, 2026
  27. Maciej CiemborowiczOct 8, 2026
  28. Kristoffer HaugsbakkOct 8, 2026
  29. Junio C HamanoOct 8, 2026
  30. 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.