Merge branch 'kn/ref-location' into jch

A mechanism to specify what reference backend to use and store
references in which directory is introduced, which would likely to
be useful during ref migration.

Comments?

* kn/ref-location:
  refs: add GIT_REF_URI to specify reference backend and directory
  refs: support obtaining ref_store for given dir
This commit is contained in:
Junio C Hamano
2025-12-12 15:53:07 +09:00
5 changed files with 196 additions and 3 deletions

View File

@@ -584,6 +584,14 @@ double-quotes and respecting backslash escapes. E.g., the value
repositories will be set to this value. The default is "files".
See `--ref-format` in linkgit:git-init[1].
`GIT_REF_URI`::
Specify which reference backend to be used along with its URI. Reference
backends like the files, reftable backend use the $GIT_DIR as their URI.
+
Expects the format `<ref_backend>://<URI-for-resource>`, where the
_<ref_backend>_ specifies the reference backend and the _<URI-for-resource>_
specifies the URI used by the backend.
Git Commits
~~~~~~~~~~~
`GIT_AUTHOR_NAME`::

View File

@@ -42,6 +42,7 @@
#define GIT_OPTIONAL_LOCKS_ENVIRONMENT "GIT_OPTIONAL_LOCKS"
#define GIT_TEXT_DOMAIN_DIR_ENVIRONMENT "GIT_TEXTDOMAINDIR"
#define GIT_ATTR_SOURCE_ENVIRONMENT "GIT_ATTR_SOURCE"
#define GIT_REF_URI_ENVIRONMENT "GIT_REF_URI"
/*
* Environment variable used to propagate the --no-advice global option to the

68
refs.c
View File

@@ -2191,17 +2191,79 @@ void ref_store_release(struct ref_store *ref_store)
free(ref_store->gitdir);
}
static struct ref_store *get_ref_store_for_dir(struct repository *r,
char *dir,
enum ref_storage_format format)
{
struct ref_store *ref_store = ref_store_init(r, format, dir,
REF_STORE_ALL_CAPS);
return maybe_debug_wrap_ref_store(dir, ref_store);
}
static struct ref_store *get_ref_store_from_uri(struct repository *repo,
const char *uri)
{
struct string_list ref_backend_info = STRING_LIST_INIT_DUP;
enum ref_storage_format format;
struct ref_store *store = NULL;
char *format_string;
char *dir;
if (!uri) {
error(_("reference backend uri is not provided"));
goto cleanup;
}
if (string_list_split(&ref_backend_info, uri, ":", 2) != 2) {
error(_("invalid reference backend uri format '%s'"), uri);
goto cleanup;
}
format_string = ref_backend_info.items[0].string;
if (!starts_with(ref_backend_info.items[1].string, "//")) {
error(_("invalid reference backend uri format '%s'"), uri);
goto cleanup;
}
dir = ref_backend_info.items[1].string + 2;
if (!dir[0]) {
error(_("invalid path in uri '%s'"), uri);
goto cleanup;
}
format = ref_storage_format_by_name(format_string);
if (format == REF_STORAGE_FORMAT_UNKNOWN) {
error(_("unknown reference backend '%s'"), format_string);
goto cleanup;
}
store = get_ref_store_for_dir(repo, dir, format);
cleanup:
string_list_clear(&ref_backend_info, 0);
return store;
}
struct ref_store *get_main_ref_store(struct repository *r)
{
char *ref_uri;
if (r->refs_private)
return r->refs_private;
if (!r->gitdir)
BUG("attempting to get main_ref_store outside of repository");
r->refs_private = ref_store_init(r, r->ref_storage_format,
r->gitdir, REF_STORE_ALL_CAPS);
r->refs_private = maybe_debug_wrap_ref_store(r->gitdir, r->refs_private);
ref_uri = getenv(GIT_REF_URI_ENVIRONMENT);
if (ref_uri) {
r->refs_private = get_ref_store_from_uri(r, ref_uri);
if (!r->refs_private)
die("failed to initialize ref store from URI: %s", ref_uri);
} else {
r->refs_private = get_ref_store_for_dir(r, r->gitdir,
r->ref_storage_format);
}
return r->refs_private;
}

View File

@@ -210,6 +210,7 @@ integration_tests = [
't1420-lost-found.sh',
't1421-reflog-write.sh',
't1422-show-ref-exists.sh',
't1423-ref-backend.sh',
't1430-bad-ref-name.sh',
't1450-fsck.sh',
't1451-fsck-buffer.sh',

121
t/t1423-ref-backend.sh Executable file
View File

@@ -0,0 +1,121 @@
#!/bin/sh
test_description='Test different reference backend URIs'
. ./test-lib.sh
test_expect_success 'empty uri provided' '
test_when_finished "rm -rf repo" &&
git init --ref-format=files repo &&
(
cd repo &&
GIT_REF_URI="" &&
export GIT_REF_URI &&
test_must_fail git refs list 2>err &&
test_grep "invalid reference backend uri format" err
)
'
test_expect_success 'invalid uri provided' '
test_when_finished "rm -rf repo" &&
git init --ref-format=files repo &&
(
cd repo &&
GIT_REF_URI="reftable@/home/reftable" &&
export GIT_REF_URI &&
test_must_fail git refs list 2>err &&
test_grep "invalid reference backend uri format" err
)
'
test_expect_success 'empty path in uri' '
test_when_finished "rm -rf repo" &&
git init --ref-format=files repo &&
(
cd repo &&
GIT_REF_URI="reftable://" &&
export GIT_REF_URI &&
test_must_fail git refs list 2>err &&
test_grep "invalid path in uri" err
)
'
test_expect_success 'uri ends at colon' '
test_when_finished "rm -rf repo" &&
git init --ref-format=files repo &&
(
cd repo &&
GIT_REF_URI="reftable:" &&
export GIT_REF_URI &&
test_must_fail git refs list 2>err &&
test_grep "invalid reference backend uri format" err
)
'
test_expect_success 'unknown reference backend' '
test_when_finished "rm -rf repo" &&
git init --ref-format=files repo &&
(
cd repo &&
GIT_REF_URI="db://.git" &&
export GIT_REF_URI &&
test_must_fail git refs list 2>err &&
test_grep "unknown reference backend" err
)
'
ref_formats="files reftable"
for from_format in $ref_formats
do
for to_format in $ref_formats
do
if test "$from_format" = "$to_format"
then
continue
fi
test_expect_success "read from $to_format backend" '
test_when_finished "rm -rf repo" &&
git init --ref-format=$from_format repo &&
(
cd repo &&
test_commit 1 &&
test_commit 2 &&
test_commit 3 &&
git refs migrate --dry-run --ref-format=$to_format >out &&
BACKEND_PATH=$(cat out | sed "s/.* ${SQ}\(.*\)${SQ}/\1/") &&
git refs list >expect &&
GIT_REF_URI="$to_format://$BACKEND_PATH" git refs list >actual &&
test_cmp expect actual
)
'
test_expect_success "write to $to_format backend" '
test_when_finished "rm -rf repo" &&
git init --ref-format=$from_format repo &&
(
cd repo &&
test_commit 1 &&
test_commit 2 &&
test_commit 3 &&
git refs migrate --dry-run --ref-format=$to_format >out &&
git refs list >expect &&
BACKEND_PATH=$(cat out | sed "s/.* ${SQ}\(.*\)${SQ}/\1/") &&
GIT_REF_URI="$to_format://$BACKEND_PATH" git tag -d 1 &&
git refs list >actual &&
test_cmp expect actual &&
GIT_REF_URI="$to_format://$BACKEND_PATH" git refs list >expect &&
git refs list >out &&
cat out | grep -v "refs/tags/1" >actual &&
test_cmp expect actual
)
'
done
done
test_done