Thread (47 messages) 47 messages, 3 authors, 6h ago

Re: [PATCH v3 4/5] builtin/refs: add "create" subcommand

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

On Fri, Jul 03, 2026 at 04:19:58PM +0200, Toon Claes wrote:
Patrick Steinhardt [off-list ref] writes:
quoted
diff --git a/Documentation/git-refs.adoc b/Documentation/git-refs.adoc
index 6475bdcc62..e6a3528349 100644
--- a/Documentation/git-refs.adoc
+++ b/Documentation/git-refs.adoc
@@ -181,6 +184,53 @@ static int cmd_refs_optimize(int argc, const char **argv, const char *prefix,
 	return pack_refs_core(argc, argv, prefix, repo, refs_optimize_usage);
 }
 
+static int cmd_refs_create(int argc, const char **argv, const char *prefix,
+			   struct repository *repo)
+{
+	static char const * const refs_create_usage[] = {
+		REFS_CREATE_USAGE,
+		NULL
+	};
+	const char *message = NULL;
+	unsigned flags = 0;
+	struct option opts[] = {
+		OPT_STRING(0, "message", &message, N_("reason"),
+			   N_("reason of the update")),
+		OPT_BIT(0 ,"no-deref", &flags,
+			N_("update <refname> not the one it points to"),
+			REF_NO_DEREF),
Can `git refs create --no-deref` be used to create symrefs? Should we
add a test for that? Or can it not

I understand the symmetry, but does it make sense to ask the user to
create symrefs with `--no-deref`? Feels a bit obscure. The docs say:

`--no-deref`::
	Operate on <ref> itself rather than the reference it points to via a
	symbolic ref.

That's far from obvious for a user to realize they need to pass that
option if they want to create a symref.
It doesn't cause them to create a symref. What this flag controls is
whether the command would fail when the refname exists already as a
symbolic ref. That is:

    $ git symbolic-ref refs/heads/symref refs/heads/target
    $ git refs create refs/heads/symref $OID
    $ git refs exists refs/heads/target

The git-refs(1) command would have created "refs/heads/target" in this
case, and by passing "--no-deref" you'd instead make it fail.

This flag is somewhat weird. Having it is probably a sensible think to
do, but now that I think about it I wonder whether the default makes all
that much sense in the first place. That being said, _if_ we want to
change it then we should change it for all subcommands.
quoted
diff --git a/t/t1466-refs-create.sh b/t/t1466-refs-create.sh
new file mode 100755
index 0000000000..cfb21bf863
--- /dev/null
+++ b/t/t1466-refs-create.sh
@@ -0,0 +1,151 @@
[snip]
quoted
+test_expect_success 'create fails when the reference already exists' '
+	test_when_finished "rm -rf repo" &&
+	setup_repo repo &&
+	(
+		cd repo &&
+		A=$(git rev-parse A) &&
+		B=$(git rev-parse B) &&
+		git refs create refs/heads/foo $A &&
+		test_must_fail git refs create refs/heads/foo $B 2>err &&
+		test_grep "reference already exists" err &&
+		test_ref_matches refs/heads/foo "$A"
+	)
+'
I was curious about this test:

	test_expect_success 'create succeed when the reference exists with the same value' '
		test_when_finished "rm -rf repo" &&
		setup_repo repo &&
		(
			cd repo &&
			A=$(git rev-parse A) &&
			git refs create refs/heads/foo $A &&
			git refs create refs/heads/foo $A &&
			test_ref_matches refs/heads/foo "$A"
		)
	'

That fails. It that intentional?
Yes, this is intentional. We didn't end up creating the reference, which
is what the user has asked us to do, and hence we fail.

[snip]
quoted
+test_expect_success 'create with symref target and --no-deref refuses to create reference' '
+	test_when_finished "rm -rf repo" &&
+	setup_repo repo &&
+	(
+		cd repo &&
+		A=$(git rev-parse A) &&
+		git symbolic-ref refs/heads/symref refs/heads/target &&
+		test_must_fail git refs create --no-deref refs/heads/symref $A 2>err &&
+		test_grep "dangling symref already exists" err &&
+		test_must_fail git reflog exists refs/heads/target
+	)
+'
Would it make sense to add this test:

	test_expect_success 'create with symref target with --no-deref' '
		test_when_finished "rm -rf repo" &&
		setup_repo repo &&
		(
			cd repo &&
			A=$(git rev-parse A) &&
			git refs create refs/heads/target $A &&
			git refs create --no-deref refs/heads/symref refs/heads/target &&
			git reflog exists refs/heads/symref && false
		)
	'

But that makes me think, this option `--no-deref` is pretty obscure for
use with `git refs create`. There are two situations:

* The symref doesn't exists: so --no-deref basically is forcing the
  command to create a symref. That's confusing
No, it's not. It tells us that we only want to create the reference if
it doesn't exist and is not a symref. Otherwise, we'd potentially create
the reference that the symref is pointing to.

Patrick
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help