Subject: Re: [PATCH v6 6/6] refs: add GIT_REFERENCE_BACKEND to specify reference backend

From: Patrick Steinhardt <[email-masked]>
Date: Tue, 17 Feb 2026 08:24:29 +0100

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