Thread (17 messages) flat view 17 messages, 3 authors, 8h ago
HOTtoday

[PATCH 11/11] setup: allow "git init --ref-storage=" to specify a payload

From: Patrick Steinhardt <hidden>
Date: 2026-09-04 10:36:42
Subsystem: documentation, the rest · Maintainers: Jonathan Corbet, Linus Torvalds

Reference storage backends can be configured with a payload via the
"extensions.refStorage" config key and the "GIT_REF_STORAGE" environment
variable, both of which accept a URI in the format
"<format>://<payload>". The payload may contain backend-specific
information, for example an alternate refs directory or which database
references should be stored in.

The `--ref-storage=` option of git-init(1) and git-clone(1) does not
know about payloads though: its value is parsed as a plain format name,
so backends that require a payload cannot be conveniently set up at
initialization time via the command line.

Teach the option to accept the same URI syntax. Also, document the
optional payloads for both the "files" and "reftable" backends.

Signed-off-by: Patrick Steinhardt <redacted>
---
 Documentation/git-init.adoc           |  5 ++++-
 Documentation/ref-storage-format.adoc |  8 ++++++--
 builtin/clone.c                       |  4 ++--
 builtin/init-db.c                     |  9 +--------
 setup.c                               | 14 +++++++++-----
 setup.h                               |  2 +-
 t/t0001-init.sh                       |  2 +-
 t/t1423-ref-backend.sh                | 30 ++++++++++++++++++++++++++++++
 8 files changed, 54 insertions(+), 20 deletions(-)
diff --git a/Documentation/git-init.adoc b/Documentation/git-init.adoc
index 54cff89dfe..182fc7c203 100644
--- a/Documentation/git-init.adoc
+++ b/Documentation/git-init.adoc
@@ -58,7 +58,10 @@ values are `sha1` and (if enabled) `sha256`.  `sha1` is the default.
 include::object-format-disclaimer.adoc[]
 
 `--ref-storage=<format>`::
-Specify the given ref storage _<format>_ for the repository. The valid values are:
+Specify the given ref storage _<format>_ for the repository. Backends that
+require additional configuration accept a payload in the form
+`<format>://<payload>`, for example a connection string identifying the
+database that shall store the references. The valid values are:
 +
 include::ref-storage-format.adoc[]
 
diff --git a/Documentation/ref-storage-format.adoc b/Documentation/ref-storage-format.adoc
index c5e29ec831..21d62557b7 100644
--- a/Documentation/ref-storage-format.adoc
+++ b/Documentation/ref-storage-format.adoc
@@ -1,8 +1,12 @@
-`files`;; for loose files with packed-refs.
+`files[://<path>]`;; for loose files with packed-refs. The optional payload can
+be specified to change the root directory where references are created. A
+relative path will be resolved relative to the repository's common directory.
 ifndef::with-breaking-changes[]
 	This is the default.
 endif::with-breaking-changes[]
-`reftable`;; for the reftable format.
+`reftable[://<path>]`;; for the reftable format. The optional payload can
+be specified to change the root directory where references are created. A
+relative path will be resolved relative to the repository's common directory.
 ifdef::with-breaking-changes[]
 	This is the default.
 endif::with-breaking-changes[]
diff --git a/builtin/clone.c b/builtin/clone.c
index c4f9dc7472..ce54088c51 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -1030,7 +1030,7 @@ int cmd_clone(int argc,
 		option_single_branch = deepen ? 1 : 0;
 
 	if (ref_storage) {
-		ref_storage_format = ref_storage_format_by_name(ref_storage);
+		ref_storage_format = ref_storage_format_by_uri(ref_storage, NULL);
 		if (ref_storage_format == REF_STORAGE_FORMAT_UNKNOWN)
 			die(_("unknown ref storage format '%s'"), ref_storage);
 	}
@@ -1188,7 +1188,7 @@ int cmd_clone(int argc,
 	 * their on-disk data structures.
 	 */
 	init_db(the_repository, git_dir, real_git_dir, work_tree, option_template,
-		GIT_HASH_UNKNOWN, ref_storage_format, NULL,
+		GIT_HASH_UNKNOWN, ref_storage, NULL,
 		do_not_override_repo_unix_permissions,
 		INIT_DB_QUIET | INIT_DB_SKIP_REFDB);
 
diff --git a/builtin/init-db.c b/builtin/init-db.c
index 763ee47d21..e30da2936a 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -86,7 +86,6 @@ int cmd_init_db(int argc,
 	const char *ref_storage = NULL;
 	const char *initial_branch = NULL;
 	int hash_algo = GIT_HASH_UNKNOWN;
-	enum ref_storage_format ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN;
 	int init_shared_repository = -1;
 	const struct option init_db_options[] = {
 		OPT_STRING(0, "template", &template_dir, N_("template-directory"),
@@ -175,12 +174,6 @@ int cmd_init_db(int argc,
 			die(_("unknown hash algorithm '%s'"), object_format);
 	}
 
-	if (ref_storage) {
-		ref_storage_format = ref_storage_format_by_name(ref_storage);
-		if (ref_storage_format == REF_STORAGE_FORMAT_UNKNOWN)
-			die(_("unknown ref storage format '%s'"), ref_storage);
-	}
-
 	if (init_shared_repository != -1)
 		repo_settings_set_shared_repository(the_repository, init_shared_repository);
 
@@ -251,7 +244,7 @@ int cmd_init_db(int argc,
 
 	flags |= INIT_DB_EXIST_OK;
 	ret = init_db(the_repository, git_dir, real_git_dir, work_tree,
-		      template_dir, hash_algo, ref_storage_format, initial_branch,
+		      template_dir, hash_algo, ref_storage, initial_branch,
 		      init_shared_repository, flags);
 
 	free(template_dir_to_free);
diff --git a/setup.c b/setup.c
index b81d4f134a..20a2fbb292 100644
--- a/setup.c
+++ b/setup.c
@@ -2727,7 +2727,7 @@ static int read_default_format_config(const char *key, const char *value,
 }
 
 static void repository_format_configure(struct repository_format *repo_fmt,
-					int hash, enum ref_storage_format ref_storage_format)
+					int hash, const char *ref_storage_uri)
 {
 	struct default_format_config cfg = {
 		.hash = GIT_HASH_UNKNOWN,
@@ -2738,6 +2738,7 @@ static void repository_format_configure(struct repository_format *repo_fmt,
 		.ignore_repo = 1,
 		.ignore_worktree = 1,
 	};
+	enum ref_storage_format ref_storage_format;
 	char *ref_storage_payload = NULL;
 	const char *env;
 
@@ -2788,8 +2789,11 @@ static void repository_format_configure(struct repository_format *repo_fmt,
 	 *   6. Otherwise, we fall back to the default ref storage format
 	 *      compiled into Git.
 	 */
-	if (ref_storage_format != REF_STORAGE_FORMAT_UNKNOWN) {
-		/* nothing to do */
+	if (ref_storage_uri) {
+		ref_storage_format = ref_storage_format_by_uri(ref_storage_uri, &ref_storage_payload);
+		if (ref_storage_format == REF_STORAGE_FORMAT_UNKNOWN)
+			die(_("unknown reference storage format specified via command line: '%s'"),
+			    ref_storage_uri);
 	} else if (((env = getenv(GIT_REF_STORAGE_ENVIRONMENT)) ||
 		    (env = getenv(GIT_REFERENCE_BACKEND_ENVIRONMENT)))) {
 		ref_storage_format = ref_storage_format_by_uri(env, &ref_storage_payload);
@@ -2834,7 +2838,7 @@ int init_db(struct repository *repo,
 	    const char *real_git_dir,
 	    const char *worktree,
 	    const char *template_dir, int hash,
-	    enum ref_storage_format ref_storage_format,
+	    const char *ref_storage_uri,
 	    const char *initial_branch,
 	    int init_shared_repository, unsigned int flags)
 {
@@ -2871,7 +2875,7 @@ int init_db(struct repository *repo,
 	 * is an attempt to reinitialize new repository with an old tool.
 	 */
 	read_and_verify_repository_format(&repo_fmt, repo_get_git_dir(repo), NULL);
-	repository_format_configure(&repo_fmt, hash, ref_storage_format);
+	repository_format_configure(&repo_fmt, hash, ref_storage_uri);
 	if (apply_repository_format(repo, &repo_fmt, APPLY_REPOSITORY_FORMAT_HONOR_ENV, &err) < 0)
 		die("%s", err.buf);
 
diff --git a/setup.h b/setup.h
index 763fd384e8..79e0640743 100644
--- a/setup.h
+++ b/setup.h
@@ -265,7 +265,7 @@ int init_db(struct repository *repo,
 	    const char *real_git_dir,
 	    const char *worktree,
 	    const char *template_dir, int hash_algo,
-	    enum ref_storage_format ref_storage_format,
+	    const char *ref_storage_uri,
 	    const char *initial_branch, int init_shared_repository,
 	    unsigned int flags);
 void initialize_repository_version(struct repository *repo,
diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index b481d763ff..7cdebc8ff3 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -833,7 +833,7 @@ done
 test_expect_success 'init with --ref-storage=garbage' '
 	test_when_finished "rm -rf refformat" &&
 	cat >expect <<-EOF &&
-	fatal: unknown ref storage format ${SQ}garbage${SQ}
+	fatal: unknown reference storage format specified via command line: ${SQ}garbage${SQ}
 	EOF
 	test_must_fail git init --ref-storage=garbage refformat 2>err &&
 	test_cmp expect err
diff --git a/t/t1423-ref-backend.sh b/t/t1423-ref-backend.sh
index e8285548ca..dc43e1c438 100755
--- a/t/t1423-ref-backend.sh
+++ b/t/t1423-ref-backend.sh
@@ -254,6 +254,36 @@ test_expect_success 'initializing repository with alt ref directory' '
 	)
 '
 
+test_expect_success 'initializing repository with --ref-storage and payload' '
+	test_when_finished "rm -rf repo refdir" &&
+	mkdir refdir &&
+	BACKEND="$(test_detect_ref_format)://$(pwd)/refdir" &&
+	git init --ref-storage="$BACKEND" repo &&
+	verify_files_exist repo/.git refdir &&
+
+	git -C repo config get extensions.refstorage >actual &&
+	echo $BACKEND >expect &&
+	test_cmp expect actual &&
+
+	test_commit -C repo 1 &&
+	git -C repo refs list >out &&
+	test_grep "refs/tags/1" out &&
+
+	# Reinitializing the repository is fine when not specifying any format.
+	git -C repo init &&
+	# Reinitializing with the same backend is fine, too.
+	git -C repo init --ref-storage="$BACKEND" &&
+	# Reinitializing without a payload should fail.
+	test_must_fail git -C repo init --ref-storage="$(test_detect_ref_format)" 2>err &&
+	test_grep "attempt to reinitialize repository with different reference storage payload" err &&
+	# Reinitializing with a different payload should fail, too.
+	test_must_fail git -C repo init --ref-storage="$(test_detect_ref_format)://$(pwd)/other" 2>err &&
+	test_grep "attempt to reinitialize repository with different reference storage payload" err &&
+
+	git -C repo config get extensions.refstorage >actual &&
+	test_cmp expect actual
+'
+
 test_expect_success 'cloning repository with alt ref directory' '
 	test_when_finished "rm -rf source repo refdir" &&
 	mkdir refdir &&
-- 
2.55.0.1007.g17ff1f9808.dirty
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help