refs: allow reference location in refstorage config
The 'extensions.refStorage' config is used to specify the reference
backend for a given repository. Both the 'files' and 'reftable' backends
utilize the $GIT_DIR as the reference folder by default in
`get_main_ref_store()`.
Since the reference backends are pluggable, this means that they could
work with out-of-tree reference directories too. Extend the 'refStorage'
config to also support taking an URI input, where users can specify the
reference backend and the location.
Add the required changes to obtain and propagate this value to the
individual backends. Add the necessary documentation and tests.
Traditionally, for linked worktrees, references were stored in the
'$GIT_DIR/worktrees/<wt_id>' path. But when using an alternate reference
storage path, it doesn't make sense to store the main worktree
references in the new path, and the linked worktree references in the
$GIT_DIR. So, let's store linked worktree references in
'$ALTERNATE_REFERENCE_DIR/worktrees/<wt_id>'. To do this, create the
necessary files and folders while also adding stubs in the $GIT_DIR path
to ensure that it is still considered a Git directory.
Ideally, we would want to pass in a `struct worktree *` to individual
backends, instead of passing the `gitdir`. This allows them to handle
worktree specific logic. Currently, that is not possible since the
worktree code is:
- Tied to using the global `the_repository` variable.
- Is not setup before the reference database during initialization of
the repository.
Add a TODO in 'refs.c' to ensure we can eventually make that change.
Helped-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Karthik Nayak committedFeb 25, 2026 at 10:40 UTC01dc84594ee365ee7086fccc7f590ab527730531
9 files changed+259-9
Documentation/config/extensions.adoc
+15-1
index 532456644b..329d02b3c4 100644--- a/Documentation/config/extensions.adoc+++ b/Documentation/config/extensions.adoc@@ -57,10 +57,24 @@ For historical reasons, this extension is respected regardless of the `core.repositoryFormatVersion` setting. refStorage:::- Specify the ref storage format to use. The acceptable values are:+ Specify the ref storage format and a corresponding payload. The value+ can be either a format name or a URI: + --+* A format name alone (e.g., `reftable` or `files`).++* A URI format `<format>://<payload>` explicitly specifies both the+ format and payload (e.g., `reftable:///foo/bar`).++Supported format names are:+ include::../ref-storage-format.adoc[]++The payload is passed directly to the reference backend. For the files and+reftable backends, this must be a filesystem path where the references will+be stored. Defaulting to the commondir when no payload is provided. Relative+paths are resolved relative to the `$GIT_DIR`. Future backends may support+other payload schemes, e.g., postgres://127.0.0.1:5432?database=myrepo. -- + Note that this setting should only be set by linkgit:git-init[1] or
builtin/worktree.c
+34
index fbdaf2eb2e..293e808379 100644--- a/builtin/worktree.c+++ b/builtin/worktree.c@@ -425,6 +425,39 @@ static int make_worktree_orphan(const char * ref, const struct add_opts *opts, return run_command(&cp); }+/*+ * References for worktrees are generally stored in '$GIT_DIR/worktrees/<wt_id>'.+ * But when using alternate reference directories, we want to store the worktree+ * references in '$ALTERNATE_REFERENCE_DIR/worktrees/<wt_id>'.+ *+ * Create the necessary folder structure to facilitate the same. But to ensure+ * that the former path is still considered a Git directory, add stubs.+ */+static void setup_alternate_ref_dir(struct worktree *wt, const char *wt_git_path)+{+ struct strbuf sb = STRBUF_INIT;+ char *path;++ path = wt->repo->ref_storage_payload;+ if (!path)+ return;++ if (!is_absolute_path(path))+ strbuf_addf(&sb, "%s/", wt->repo->commondir);++ strbuf_addf(&sb, "%s/worktrees", path);+ safe_create_dir(wt->repo, sb.buf, 1);+ strbuf_addf(&sb, "/%s", wt->id);+ safe_create_dir(wt->repo, sb.buf, 1);+ strbuf_reset(&sb);++ strbuf_addf(&sb, "this worktree stores references in %s/worktrees/%s",+ path, wt->id);+ refs_create_refdir_stubs(wt->repo, wt_git_path, sb.buf);++ strbuf_release(&sb);+}+ static int add_worktree(const char *path, const char *refname, const struct add_opts *opts) {@@ -518,6 +551,7 @@ static int add_worktree(const char *path, const char *refname, ret = error(_("could not find created worktree '%s'"), name); goto done; }+ setup_alternate_ref_dir(wt, sb_repo.buf); wt_refs = get_worktree_ref_store(wt); ret = ref_store_create_on_disk(wt_refs, REF_STORE_CREATE_ON_DISK_IS_WORKTREE, &sb);
refs.c
+5-1
index ba2573eb7a..ef1902e85c 100644--- a/refs.c+++ b/refs.c@@ -2291,7 +2291,11 @@ static struct ref_store *ref_store_init(struct repository *repo, if (!be) BUG("reference backend is unknown");- refs = be->init(repo, NULL, gitdir, flags);+ /*+ * TODO Send in a 'struct worktree' instead of a 'gitdir', and+ * allow the backend to handle how it wants to deal with worktrees.+ */+ refs = be->init(repo, repo->ref_storage_payload, gitdir, flags); return refs; }
index 6063c4b846..95e2333bad 100644--- a/repository.h+++ b/repository.h@@ -150,6 +150,11 @@ struct repository { /* Repository's reference storage format, as serialized on disk. */ enum ref_storage_format ref_storage_format;+ /*+ * Reference storage information as needed for the backend. This contains+ * only the payload from the reference URI without the schema.+ */+ char *ref_storage_payload; /* A unique-id for tracing purposes. */ int trace2_repo_id;@@ -204,7 +209,8 @@ void repo_set_worktree(struct repository *repo, const char *path); void repo_set_hash_algo(struct repository *repo, int algo); void repo_set_compat_hash_algo(struct repository *repo, int compat_algo); void repo_set_ref_storage_format(struct repository *repo,- enum ref_storage_format format);+ enum ref_storage_format format,+ const char *payload); void initialize_repository(struct repository *repo); RESULT_MUST_BE_USED int repo_init(struct repository *r, const char *gitdir, const char *worktree);