From: Patrick Steinhardt Date: Tue, 17 Feb 2026 07:24:29 GMT Subject: Re: [PATCH v6 6/6] refs: add GIT_REFERENCE_BACKEND to specify reference backend Message-ID: In-Reply-To: <20260214-kn-alternate-ref-dir-v6-6-86a82c77cf59@gmail.com> On Sat, Feb 14, 2026 at 11:34:19PM +0100, Karthik Nayak wrote: > Git allows setting a different object directory via > 'GIT_OBJECT_DIRECTORY', but provides no equivalent for references. In > the previous commit we extended the 'extensions.refStorage' config to > also support an URI input for reference backend with location. > > Let's also add a new environment variable 'GIT_REFERENCE_BACKEND' that > takes in the same input as the config variable. Having an environment > variable allows us to modify the reference backend and location on the > fly for individual Git commands. > > The environment variable also allows usage of alternate reference > directories during 'git-clone(1)' and 'git-init(1)'. Add the config to > the repository when created with the environment variable set. > > When initializing the repository with an alternate reference folder, > create the required stubs in the repositories $GIT_DIR. The inverse, > i.e. removal of the ref store doesn't clean up the stubs in the $GIT_DIR > since that would render it unusable. Removal of ref store is only used > when migrating between ref formats and cleanup of the $GIT_DIR doesn't > make sense in such a situation. Nice. > diff --git a/refs.c b/refs.c > index 87ef54abd4..6b3883a325 100644 > --- a/refs.c > +++ b/refs.c > @@ -2192,16 +2192,21 @@ int ref_store_create_on_disk(struct ref_store *refs, int flags, struct strbuf *e > { > int ret = refs->be->create_on_disk(refs, flags, err); > > - if (!ret && > - ref_storage_format_by_name(refs->be->name) != REF_STORAGE_FORMAT_FILES) { > - struct strbuf msg = STRBUF_INIT; > - > - strbuf_addf(&msg, "this repository uses the %s format", refs->be->name); > - refs_create_refdir_stubs(refs->repo, refs->gitdir, msg.buf); > - strbuf_release(&msg); > + if (!ret) { > + /* Creation of stubs for linked worktrees are handled in the worktree code. */ > + if (!(flags & REF_STORE_CREATE_ON_DISK_IS_WORKTREE) && refs->repo->ref_storage_payload) { > + refs_create_refdir_stubs(refs->repo, refs->repo->gitdir, > + "repository uses alternate refs storage"); > + } else if (ref_storage_format_by_name(refs->be->name) != REF_STORAGE_FORMAT_FILES) { > + struct strbuf msg = STRBUF_INIT; > + strbuf_addf(&msg, "this repository uses the %s format", refs->be->name); > + refs_create_refdir_stubs(refs->repo, refs->gitdir, msg.buf); > + strbuf_release(&msg); > + } > } Okay, this here is the reason why you've moved the stub creation into the generic parts. Makes sense. > > return ret; > + > } There's a stray newline here. > diff --git a/setup.c b/setup.c > index d407f3347b..90cb9be578 100644 > --- a/setup.c > +++ b/setup.c > @@ -2337,7 +2357,8 @@ void initialize_repository_version(int hash_algo, > * the remote repository's format. > */ > if (hash_algo != GIT_HASH_SHA1_LEGACY || > - ref_storage_format != REF_STORAGE_FORMAT_FILES) > + ref_storage_format != REF_STORAGE_FORMAT_FILES || > + the_repository->ref_storage_payload) > target_version = GIT_REPO_VERSION_READ; > > if (hash_algo != GIT_HASH_SHA1_LEGACY && hash_algo != GIT_HASH_UNKNOWN) Right. If we've got a payload during init we know that we must use the repository extension. Makes sense. > @@ -2346,11 +2367,20 @@ void initialize_repository_version(int hash_algo, > else if (reinit) > repo_config_set_gently(the_repository, "extensions.objectformat", NULL); > > - if (ref_storage_format != REF_STORAGE_FORMAT_FILES) > + if (the_repository->ref_storage_payload) { > + struct strbuf ref_uri = STRBUF_INIT; > + > + strbuf_addf(&ref_uri, "%s://%s", > + ref_storage_format_to_name(ref_storage_format), > + the_repository->ref_storage_payload); > + repo_config_set(the_repository, "extensions.refstorage", ref_uri.buf); > + strbuf_release(&ref_uri); > + } else if (ref_storage_format != REF_STORAGE_FORMAT_FILES) { > repo_config_set(the_repository, "extensions.refstorage", > ref_storage_format_to_name(ref_storage_format)); > - else if (reinit) > + } else if (reinit) { > repo_config_set_gently(the_repository, "extensions.refstorage", NULL); > + } > > if (reinit) { > struct strbuf config = STRBUF_INIT; And here we write the payload into the configuration, if we've got one. > diff --git a/t/t1423-ref-backend.sh b/t/t1423-ref-backend.sh > index 9912433b8c..b743c03a59 100755 > --- a/t/t1423-ref-backend.sh > +++ b/t/t1423-ref-backend.sh [snip] > +test_expect_success 'initializing repository with alt ref directory' ' > + test_when_finished "rm -rf repo refdir" && > + mkdir refdir && > + BACKEND="$(test_detect_ref_format)://$(pwd)/refdir" && > + GIT_REFERENCE_BACKEND=$BACKEND git init repo && > + ( > + cd repo && > + > + git config get extensions.refstorage >expect && > + echo $BACKEND >actual && > + test_cmp expect actual && > + > + test_commit 1 && > + test_commit 2 && > + test_commit 3 && > + git refs list >out && > + test_grep "refs/tags/1" out && > + test_grep "refs/tags/2" out && > + test_grep "refs/tags/3" out > + ) > +' Should we also verify that the refdir contains the data and that the repository only contains stubs? > +test_expect_success 'cloning repository with alt ref directory' ' > + test_when_finished "rm -rf source repo refdir" && > + mkdir refdir && > + > + git init source && > + test_commit -C source 1 && > + test_commit -C source 2 && > + test_commit -C source 3 && > + > + BACKEND="$(test_detect_ref_format)://$(pwd)/refdir" && > + GIT_REFERENCE_BACKEND=$BACKEND git clone source repo && > + > + git -C repo config get extensions.refstorage >expect && > + echo $BACKEND >actual && > + test_cmp expect actual && > + > + git -C source for-each-ref refs/tags/ >expect && > + git -C repo for-each-ref refs/tags/ >actual && > + test_cmp expect actual > +' > + Same question here. Thanks! Patrick