Thread (47 messages) read the whole thread 47 messages, 3 authors, 21d ago
COLD21d

Revision v4 of 4 in this series.

Revisions (4)
  1. v1 [diff vs current]
  2. v2 [diff vs current]
  3. v3 [diff vs current]
  4. v4 current

[PATCH v4 0/5] builtin/refs: add ability to write references

From: Patrick Steinhardt <hidden>
Date: 2026-07-06 13:27:13

Hi,

Reference-related functionality in Git is currently spread across many
different commands: git-update-ref(1), git-for-each-ref(1),
git-show-ref(1), git-pack-refs(1) and git-symbolic-ref(1). This makes it
hard for users to discover what functionality we have available to work
with references.

We have thus started to consolidate this functionality into git-refs(1),
which is a toolbox of everything related to references. Until now, the
command doesn't handle functionality of git-update-ref(1).

This patch series backfills most of the functionality by introducing
three new commands:

  - `git refs delete` to delete references. This is the equivalent of
    `git update-ref -d`.

  - `git refs update` to update references. This is the equivalent of
    `git update-ref <refname> <oldvalue> <newvalue>`.

  - `git refs rename` to rename a reference, including its reflog. This
    does not have an equivalent in git-update-ref(1), but is inspired by
    and supersedes [1].

Changes in v4:
  - Add a couple more tests around symrefs.
  - Use a subshell in one of the tests for consistency.
  - Link to v3: https://patch.msgid.link/20260630-pks-refs-writing-subcommands-v3-0-deb04de1ecef@pks.im

Changes in v3:
  - Fix confused error message.
  - Link to v2: https://patch.msgid.link/20260617-pks-refs-writing-subcommands-v2-0-07f3d18336f9@pks.im

Changes in v2:
  - Add a new "create" subcommand.
  - Consistently quote in error messages.
  - Consistently use `<old-value>` in the synopsis.
  - Don't return negative exit codes.
  - Improve documentation of "update" subcommand to mention that you can
    create and delete branches.
  - Add tests to verify that we can use "update" to do this, both in
    racy and raceless ways.
  - Add missing calls to `repo_config()`.
  - Drop useless `GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME` variable.
  - Link to v1: https://patch.msgid.link/20260616-pks-refs-writing-subcommands-v1-0-9f5219b6109d@pks.im

Thanks!

Patrick

[1]: <xmqqv7brz9ba.fsf@gitster.g>

---
Patrick Steinhardt (5):
      builtin/refs: drop `the_repository`
      builtin/refs: add "delete" subcommand
      builtin/refs: add "update" subcommand
      builtin/refs: add "create" subcommand
      builtin/refs: add "rename" subcommand

 Documentation/git-refs.adoc |  40 +++++++
 builtin/refs.c              | 222 ++++++++++++++++++++++++++++++++++--
 t/meson.build               |   4 +
 t/t1464-refs-delete.sh      | 152 +++++++++++++++++++++++++
 t/t1465-refs-update.sh      | 268 ++++++++++++++++++++++++++++++++++++++++++++
 t/t1466-refs-create.sh      | 151 +++++++++++++++++++++++++
 t/t1467-refs-rename.sh      | 144 ++++++++++++++++++++++++
 7 files changed, 973 insertions(+), 8 deletions(-)

Range-diff versus v3:

1:  dc87ed0ebc = 1:  3b40441317 builtin/refs: drop `the_repository`
2:  cec7d978f1 ! 2:  8089847912 builtin/refs: add "delete" subcommand
    @@ t/t1464-refs-delete.sh (new)
     +test_expect_success 'delete without oldvalue verification' '
     +	test_when_finished "rm -rf repo" &&
     +	setup_repo repo &&
    -+	A=$(git -C repo rev-parse A) &&
    -+	git -C repo update-ref refs/heads/foo $A &&
    -+	git -C repo refs delete refs/heads/foo &&
    -+	test_must_fail git -C repo show-ref --verify -q refs/heads/foo
    ++	(
    ++		cd repo &&
    ++		A=$(git rev-parse A) &&
    ++		git update-ref refs/heads/foo $A &&
    ++		git refs delete refs/heads/foo &&
    ++		test_must_fail git refs exists refs/heads/foo
    ++	)
     +'
     +
     +test_expect_success 'delete with matching oldvalue' '
    @@ t/t1464-refs-delete.sh (new)
     +	)
     +'
     +
    ++test_expect_success 'delete symref with --no-deref verifies target OID' '
    ++	test_when_finished "rm -rf repo" &&
    ++	setup_repo repo &&
    ++	(
    ++		cd repo &&
    ++		A=$(git rev-parse A) &&
    ++		B=$(git rev-parse B) &&
    ++		git update-ref refs/heads/foo $A &&
    ++		git symbolic-ref refs/heads/symref refs/heads/foo &&
    ++
    ++		test_must_fail git refs delete --no-deref refs/heads/symref $B &&
    ++		git refs exists refs/heads/symref &&
    ++
    ++		git refs delete --no-deref refs/heads/symref $A &&
    ++		test_must_fail git refs exists refs/heads/symref &&
    ++		git refs exists refs/heads/foo
    ++	)
    ++'
    ++
     +test_expect_success 'delete with message records reason in reflog' '
     +	test_when_finished "rm -rf repo" &&
     +	setup_repo repo &&
3:  8e73b0f711 = 3:  fb830f8f9e builtin/refs: add "update" subcommand
4:  f5ad0c9b18 = 4:  f3c17471c1 builtin/refs: add "create" subcommand
5:  5c01f2e828 ! 5:  82e4efb2a9 builtin/refs: add "rename" subcommand
    @@ t/t1467-refs-rename.sh (new)
     +	)
     +'
     +
    ++test_expect_success 'rename with symbolic ref fails' '
    ++	test_when_finished "rm -rf repo" &&
    ++	setup_repo repo &&
    ++	(
    ++		cd repo &&
    ++		A=$(git rev-parse A) &&
    ++		git refs create refs/heads/target $A &&
    ++		git symbolic-ref refs/heads/symref refs/heads/target &&
    ++		! git refs rename refs/heads/symref refs/heads/renamed 2>err &&
    ++		test_grep "is a symbolic ref, .* not supported" err
    ++	)
    ++'
    ++
     +test_expect_success 'rename with empty message fails' '
     +	test_when_finished "rm -rf repo" &&
     +	setup_repo repo &&

---
base-commit: 700432b2ba22603a0bcb71475c9c333d17c9b0d1
change-id: 20260616-pks-refs-writing-subcommands-7a77be5bda9b
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help