mirror of
https://github.com/git/git.git
synced 2026-02-27 10:25:07 +00:00
Merge branch 'kn/ref-location' into jch
Allow the directory in which reference backends store their data to be specified. * kn/ref-location: refs: add GIT_REFERENCE_BACKEND to specify reference backend refs: allow reference location in refstorage config refs: receive and use the reference storage payload refs: move out stub modification to generic layer refs: extract out `refs_create_refdir_stubs()` setup: don't modify repo in `create_reference_database()`
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -584,6 +584,11 @@ 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_REFERENCE_BACKEND`::
|
||||
Specify which reference backend to be used along with its URI.
|
||||
See `extensions.refStorage` option in linkgit:git-config[1] for more
|
||||
details. Overrides the config variable when used.
|
||||
|
||||
Git Commits
|
||||
~~~~~~~~~~~
|
||||
`GIT_AUTHOR_NAME`::
|
||||
|
||||
@@ -1230,12 +1230,7 @@ int cmd_clone(int argc,
|
||||
initialize_repository_version(GIT_HASH_UNKNOWN,
|
||||
the_repository->ref_storage_format, 1);
|
||||
|
||||
strbuf_addf(&buf, "%s/HEAD", git_dir);
|
||||
write_file(buf.buf, "ref: refs/heads/.invalid");
|
||||
|
||||
strbuf_reset(&buf);
|
||||
strbuf_addf(&buf, "%s/refs", git_dir);
|
||||
safe_create_dir(the_repository, buf.buf, 1);
|
||||
refs_create_refdir_stubs(the_repository, git_dir, NULL);
|
||||
|
||||
/*
|
||||
* additional config can be injected with -c, make sure it's included
|
||||
@@ -1447,7 +1442,7 @@ int cmd_clone(int argc,
|
||||
hash_algo = hash_algo_by_ptr(transport_get_hash_algo(transport));
|
||||
initialize_repository_version(hash_algo, the_repository->ref_storage_format, 1);
|
||||
repo_set_hash_algo(the_repository, hash_algo);
|
||||
create_reference_database(the_repository->ref_storage_format, NULL, 1);
|
||||
create_reference_database(NULL, 1);
|
||||
|
||||
/*
|
||||
* Before fetching from the remote, download and install bundle
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
@@ -519,6 +552,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);
|
||||
|
||||
@@ -43,6 +43,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_REFERENCE_BACKEND_ENVIRONMENT "GIT_REFERENCE_BACKEND"
|
||||
|
||||
/*
|
||||
* Environment variable used to propagate the --no-advice global option to the
|
||||
|
||||
126
refs.c
126
refs.c
@@ -5,6 +5,7 @@
|
||||
#define USE_THE_REPOSITORY_VARIABLE
|
||||
|
||||
#include "git-compat-util.h"
|
||||
#include "abspath.h"
|
||||
#include "advice.h"
|
||||
#include "config.h"
|
||||
#include "environment.h"
|
||||
@@ -2156,15 +2157,93 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void refs_create_refdir_stubs(struct repository *repo, const char *refdir,
|
||||
const char *refs_heads_content)
|
||||
{
|
||||
struct strbuf path = STRBUF_INIT;
|
||||
|
||||
strbuf_addf(&path, "%s/HEAD", refdir);
|
||||
write_file(path.buf, "ref: refs/heads/.invalid");
|
||||
adjust_shared_perm(repo, path.buf);
|
||||
|
||||
strbuf_reset(&path);
|
||||
strbuf_addf(&path, "%s/refs", refdir);
|
||||
safe_create_dir(repo, path.buf, 1);
|
||||
|
||||
if (refs_heads_content) {
|
||||
strbuf_reset(&path);
|
||||
strbuf_addf(&path, "%s/refs/heads", refdir);
|
||||
write_file(path.buf, "%s", refs_heads_content);
|
||||
adjust_shared_perm(repo, path.buf);
|
||||
}
|
||||
|
||||
strbuf_release(&path);
|
||||
}
|
||||
|
||||
/* backend functions */
|
||||
int ref_store_create_on_disk(struct ref_store *refs, int flags, struct strbuf *err)
|
||||
{
|
||||
return refs->be->create_on_disk(refs, flags, err);
|
||||
int ret = refs->be->create_on_disk(refs, flags, err);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ref_store_remove_on_disk(struct ref_store *refs, struct strbuf *err)
|
||||
{
|
||||
return refs->be->remove_on_disk(refs, err);
|
||||
int ret = refs->be->remove_on_disk(refs, err);
|
||||
|
||||
if (!ret) {
|
||||
enum ref_storage_format format = ref_storage_format_by_name(refs->be->name);
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
|
||||
/* Backends apart from the files backend create stubs. */
|
||||
if (format == REF_STORAGE_FORMAT_FILES)
|
||||
return ret;
|
||||
|
||||
/* Alternate refs backend require stubs in the gitdir. */
|
||||
if (refs->repo->ref_storage_payload)
|
||||
return ret;
|
||||
|
||||
strbuf_addf(&sb, "%s/HEAD", refs->gitdir);
|
||||
if (unlink(sb.buf) < 0) {
|
||||
strbuf_addf(err, "could not delete stub HEAD: %s",
|
||||
strerror(errno));
|
||||
ret = -1;
|
||||
}
|
||||
strbuf_reset(&sb);
|
||||
|
||||
strbuf_addf(&sb, "%s/refs/heads", refs->gitdir);
|
||||
if (unlink(sb.buf) < 0) {
|
||||
strbuf_addf(err, "could not delete stub heads: %s",
|
||||
strerror(errno));
|
||||
ret = -1;
|
||||
}
|
||||
strbuf_reset(&sb);
|
||||
|
||||
strbuf_addf(&sb, "%s/refs", refs->gitdir);
|
||||
if (rmdir(sb.buf) < 0) {
|
||||
strbuf_addf(err, "could not delete refs directory: %s",
|
||||
strerror(errno));
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
strbuf_release(&sb);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int repo_resolve_gitlink_ref(struct repository *r,
|
||||
@@ -2217,7 +2296,11 @@ static struct ref_store *ref_store_init(struct repository *repo,
|
||||
if (!be)
|
||||
BUG("reference backend is unknown");
|
||||
|
||||
refs = be->init(repo, 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;
|
||||
}
|
||||
|
||||
@@ -3405,3 +3488,40 @@ const char *ref_transaction_error_msg(enum ref_transaction_error err)
|
||||
return "unknown failure";
|
||||
}
|
||||
}
|
||||
|
||||
void refs_compute_filesystem_location(const char *gitdir, const char *payload,
|
||||
bool *is_worktree, struct strbuf *refdir,
|
||||
struct strbuf *ref_common_dir)
|
||||
{
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
|
||||
*is_worktree = get_common_dir_noenv(ref_common_dir, gitdir);
|
||||
|
||||
if (!payload) {
|
||||
/*
|
||||
* We can use the 'gitdir' as the 'refdir' without appending the
|
||||
* worktree path, as the 'gitdir' here is already the worktree
|
||||
* path and is different from 'commondir' denoted by 'ref_common_dir'.
|
||||
*/
|
||||
strbuf_addstr(refdir, gitdir);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_absolute_path(payload)) {
|
||||
strbuf_addf(&sb, "%s/%s", ref_common_dir->buf, payload);
|
||||
strbuf_realpath(ref_common_dir, sb.buf, 1);
|
||||
} else {
|
||||
strbuf_realpath(ref_common_dir, payload, 1);
|
||||
}
|
||||
|
||||
strbuf_addbuf(refdir, ref_common_dir);
|
||||
|
||||
if (*is_worktree) {
|
||||
const char *wt_id = strrchr(gitdir, '/');
|
||||
if (!wt_id)
|
||||
BUG("worktree path does not contain slash");
|
||||
strbuf_addf(refdir, "/worktrees/%s", wt_id + 1);
|
||||
}
|
||||
|
||||
strbuf_release(&sb);
|
||||
}
|
||||
|
||||
13
refs.h
13
refs.h
@@ -1433,4 +1433,17 @@ void ref_iterator_free(struct ref_iterator *ref_iterator);
|
||||
int do_for_each_ref_iterator(struct ref_iterator *iter,
|
||||
refs_for_each_cb fn, void *cb_data);
|
||||
|
||||
/*
|
||||
* Git only recognizes a directory as a repository if it contains:
|
||||
* - HEAD file
|
||||
* - refs/ folder
|
||||
* While it is necessary within the files backend, newer backends may not
|
||||
* follow the same structure. To go around this, we create stubs as necessary.
|
||||
*
|
||||
* If provided with a 'refs_heads_msg', we create the 'refs/heads/head' file
|
||||
* with the provided message.
|
||||
*/
|
||||
void refs_create_refdir_stubs(struct repository *repo, const char *refdir,
|
||||
const char *refs_heads_msg);
|
||||
|
||||
#endif /* REFS_H */
|
||||
|
||||
@@ -106,19 +106,24 @@ static void clear_loose_ref_cache(struct files_ref_store *refs)
|
||||
* set of caches.
|
||||
*/
|
||||
static struct ref_store *files_ref_store_init(struct repository *repo,
|
||||
const char *payload,
|
||||
const char *gitdir,
|
||||
unsigned int flags)
|
||||
{
|
||||
struct files_ref_store *refs = xcalloc(1, sizeof(*refs));
|
||||
struct ref_store *ref_store = (struct ref_store *)refs;
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
struct strbuf ref_common_dir = STRBUF_INIT;
|
||||
struct strbuf refdir = STRBUF_INIT;
|
||||
bool is_worktree;
|
||||
|
||||
base_ref_store_init(ref_store, repo, gitdir, &refs_be_files);
|
||||
refs_compute_filesystem_location(gitdir, payload, &is_worktree, &refdir,
|
||||
&ref_common_dir);
|
||||
|
||||
base_ref_store_init(ref_store, repo, refdir.buf, &refs_be_files);
|
||||
refs->store_flags = flags;
|
||||
get_common_dir_noenv(&sb, gitdir);
|
||||
refs->gitcommondir = strbuf_detach(&sb, NULL);
|
||||
refs->gitcommondir = strbuf_detach(&ref_common_dir, NULL);
|
||||
refs->packed_ref_store =
|
||||
packed_ref_store_init(repo, refs->gitcommondir, flags);
|
||||
packed_ref_store_init(repo, NULL, refs->gitcommondir, flags);
|
||||
refs->log_all_ref_updates = repo_settings_get_log_all_ref_updates(repo);
|
||||
repo_config_get_bool(repo, "core.prefersymlinkrefs", &refs->prefer_symlink_refs);
|
||||
|
||||
@@ -126,6 +131,8 @@ static struct ref_store *files_ref_store_init(struct repository *repo,
|
||||
chdir_notify_reparent("files-backend $GIT_COMMONDIR",
|
||||
&refs->gitcommondir);
|
||||
|
||||
strbuf_release(&refdir);
|
||||
|
||||
return ref_store;
|
||||
}
|
||||
|
||||
@@ -3702,7 +3709,11 @@ static int files_ref_store_remove_on_disk(struct ref_store *ref_store,
|
||||
if (for_each_root_ref(refs, remove_one_root_ref, &data) < 0)
|
||||
ret = -1;
|
||||
|
||||
if (ref_store_remove_on_disk(refs->packed_ref_store, err) < 0)
|
||||
/*
|
||||
* Directly access the cleanup functions for packed-refs as the generic function
|
||||
* would try to clear stubs which isn't required for the files backend.
|
||||
*/
|
||||
if (refs->packed_ref_store->be->remove_on_disk(refs->packed_ref_store, err) < 0)
|
||||
ret = -1;
|
||||
|
||||
strbuf_release(&sb);
|
||||
|
||||
@@ -211,7 +211,12 @@ static size_t snapshot_hexsz(const struct snapshot *snapshot)
|
||||
return snapshot->refs->base.repo->hash_algo->hexsz;
|
||||
}
|
||||
|
||||
/*
|
||||
* Since packed-refs is only stored in the common dir, don't parse the
|
||||
* payload and rely on the files-backend to set 'gitdir' correctly.
|
||||
*/
|
||||
struct ref_store *packed_ref_store_init(struct repository *repo,
|
||||
const char *payload UNUSED,
|
||||
const char *gitdir,
|
||||
unsigned int store_flags)
|
||||
{
|
||||
|
||||
@@ -14,6 +14,7 @@ struct ref_transaction;
|
||||
*/
|
||||
|
||||
struct ref_store *packed_ref_store_init(struct repository *repo,
|
||||
const char *payload,
|
||||
const char *gitdir,
|
||||
unsigned int store_flags);
|
||||
|
||||
|
||||
@@ -391,6 +391,7 @@ struct ref_store;
|
||||
* the ref_store and to record the ref_store for later lookup.
|
||||
*/
|
||||
typedef struct ref_store *ref_store_init_fn(struct repository *repo,
|
||||
const char *payload,
|
||||
const char *gitdir,
|
||||
unsigned int flags);
|
||||
/*
|
||||
@@ -668,4 +669,17 @@ enum ref_transaction_error refs_verify_refnames_available(struct ref_store *refs
|
||||
unsigned int initial_transaction,
|
||||
struct strbuf *err);
|
||||
|
||||
/*
|
||||
* Given a gitdir and the reference storage payload provided, retrieve the
|
||||
* 'refdir' and 'ref_common_dir'. The former is where references should be
|
||||
* stored for the current worktree, the latter is the common reference
|
||||
* directory if working with a linked worktree. If working with the main
|
||||
* worktree, both values will be the same.
|
||||
*
|
||||
* This is used by backends that store references in the repository directly.
|
||||
*/
|
||||
void refs_compute_filesystem_location(const char *gitdir, const char *payload,
|
||||
bool *is_worktree, struct strbuf *refdir,
|
||||
struct strbuf *ref_common_dir);
|
||||
|
||||
#endif /* REFS_REFS_INTERNAL_H */
|
||||
|
||||
@@ -372,18 +372,24 @@ static int reftable_be_fsync(int fd)
|
||||
}
|
||||
|
||||
static struct ref_store *reftable_be_init(struct repository *repo,
|
||||
const char *payload,
|
||||
const char *gitdir,
|
||||
unsigned int store_flags)
|
||||
{
|
||||
struct reftable_ref_store *refs = xcalloc(1, sizeof(*refs));
|
||||
struct strbuf ref_common_dir = STRBUF_INIT;
|
||||
struct strbuf refdir = STRBUF_INIT;
|
||||
struct strbuf path = STRBUF_INIT;
|
||||
int is_worktree;
|
||||
bool is_worktree;
|
||||
mode_t mask;
|
||||
|
||||
mask = umask(0);
|
||||
umask(mask);
|
||||
|
||||
base_ref_store_init(&refs->base, repo, gitdir, &refs_be_reftable);
|
||||
refs_compute_filesystem_location(gitdir, payload, &is_worktree, &refdir,
|
||||
&ref_common_dir);
|
||||
|
||||
base_ref_store_init(&refs->base, repo, refdir.buf, &refs_be_reftable);
|
||||
strmap_init(&refs->worktree_backends);
|
||||
refs->store_flags = store_flags;
|
||||
refs->log_all_ref_updates = repo_settings_get_log_all_ref_updates(repo);
|
||||
@@ -419,14 +425,11 @@ static struct ref_store *reftable_be_init(struct repository *repo,
|
||||
/*
|
||||
* Set up the main reftable stack that is hosted in GIT_COMMON_DIR.
|
||||
* This stack contains both the shared and the main worktree refs.
|
||||
*
|
||||
* Note that we don't try to resolve the path in case we have a
|
||||
* worktree because `get_common_dir_noenv()` already does it for us.
|
||||
*/
|
||||
is_worktree = get_common_dir_noenv(&path, gitdir);
|
||||
strbuf_addbuf(&path, &ref_common_dir);
|
||||
if (!is_worktree) {
|
||||
strbuf_reset(&path);
|
||||
strbuf_realpath(&path, gitdir, 0);
|
||||
strbuf_realpath(&path, ref_common_dir.buf, 0);
|
||||
}
|
||||
strbuf_addstr(&path, "/reftable");
|
||||
refs->err = reftable_backend_init(&refs->main_backend, path.buf,
|
||||
@@ -443,10 +446,9 @@ static struct ref_store *reftable_be_init(struct repository *repo,
|
||||
* do it efficiently.
|
||||
*/
|
||||
if (is_worktree) {
|
||||
strbuf_reset(&path);
|
||||
strbuf_addf(&path, "%s/reftable", gitdir);
|
||||
strbuf_addstr(&refdir, "/reftable");
|
||||
|
||||
refs->err = reftable_backend_init(&refs->worktree_backend, path.buf,
|
||||
refs->err = reftable_backend_init(&refs->worktree_backend, refdir.buf,
|
||||
&refs->write_options);
|
||||
if (refs->err)
|
||||
goto done;
|
||||
@@ -456,6 +458,8 @@ static struct ref_store *reftable_be_init(struct repository *repo,
|
||||
|
||||
done:
|
||||
assert(refs->err != REFTABLE_API_ERROR);
|
||||
strbuf_release(&ref_common_dir);
|
||||
strbuf_release(&refdir);
|
||||
strbuf_release(&path);
|
||||
return &refs->base;
|
||||
}
|
||||
@@ -491,19 +495,6 @@ static int reftable_be_create_on_disk(struct ref_store *ref_store,
|
||||
safe_create_dir(the_repository, sb.buf, 1);
|
||||
strbuf_reset(&sb);
|
||||
|
||||
strbuf_addf(&sb, "%s/HEAD", refs->base.gitdir);
|
||||
write_file(sb.buf, "ref: refs/heads/.invalid");
|
||||
adjust_shared_perm(the_repository, sb.buf);
|
||||
strbuf_reset(&sb);
|
||||
|
||||
strbuf_addf(&sb, "%s/refs", refs->base.gitdir);
|
||||
safe_create_dir(the_repository, sb.buf, 1);
|
||||
strbuf_reset(&sb);
|
||||
|
||||
strbuf_addf(&sb, "%s/refs/heads", refs->base.gitdir);
|
||||
write_file(sb.buf, "this repository uses the reftable format");
|
||||
adjust_shared_perm(the_repository, sb.buf);
|
||||
|
||||
strbuf_release(&sb);
|
||||
return 0;
|
||||
}
|
||||
@@ -529,30 +520,6 @@ static int reftable_be_remove_on_disk(struct ref_store *ref_store,
|
||||
strerror(errno));
|
||||
ret = -1;
|
||||
}
|
||||
strbuf_reset(&sb);
|
||||
|
||||
strbuf_addf(&sb, "%s/HEAD", refs->base.gitdir);
|
||||
if (unlink(sb.buf) < 0) {
|
||||
strbuf_addf(err, "could not delete stub HEAD: %s",
|
||||
strerror(errno));
|
||||
ret = -1;
|
||||
}
|
||||
strbuf_reset(&sb);
|
||||
|
||||
strbuf_addf(&sb, "%s/refs/heads", refs->base.gitdir);
|
||||
if (unlink(sb.buf) < 0) {
|
||||
strbuf_addf(err, "could not delete stub heads: %s",
|
||||
strerror(errno));
|
||||
ret = -1;
|
||||
}
|
||||
strbuf_reset(&sb);
|
||||
|
||||
strbuf_addf(&sb, "%s/refs", refs->base.gitdir);
|
||||
if (rmdir(sb.buf) < 0) {
|
||||
strbuf_addf(err, "could not delete refs directory: %s",
|
||||
strerror(errno));
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
strbuf_release(&sb);
|
||||
return ret;
|
||||
|
||||
@@ -213,9 +213,12 @@ void repo_set_compat_hash_algo(struct repository *repo MAYBE_UNUSED, uint32_t al
|
||||
}
|
||||
|
||||
void repo_set_ref_storage_format(struct repository *repo,
|
||||
enum ref_storage_format format)
|
||||
enum ref_storage_format format,
|
||||
const char *payload)
|
||||
{
|
||||
repo->ref_storage_format = format;
|
||||
free(repo->ref_storage_payload);
|
||||
repo->ref_storage_payload = xstrdup_or_null(payload);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -297,7 +300,8 @@ int repo_init(struct repository *repo,
|
||||
|
||||
repo_set_hash_algo(repo, format.hash_algo);
|
||||
repo_set_compat_hash_algo(repo, format.compat_hash_algo);
|
||||
repo_set_ref_storage_format(repo, format.ref_storage_format);
|
||||
repo_set_ref_storage_format(repo, format.ref_storage_format,
|
||||
format.ref_storage_payload);
|
||||
repo->repository_format_worktree_config = format.worktree_config;
|
||||
repo->repository_format_relative_worktrees = format.relative_worktrees;
|
||||
repo->repository_format_precious_objects = format.precious_objects;
|
||||
@@ -390,6 +394,7 @@ void repo_clear(struct repository *repo)
|
||||
FREE_AND_NULL(repo->index_file);
|
||||
FREE_AND_NULL(repo->worktree);
|
||||
FREE_AND_NULL(repo->submodule_prefix);
|
||||
FREE_AND_NULL(repo->ref_storage_payload);
|
||||
|
||||
odb_free(repo->objects);
|
||||
repo->objects = NULL;
|
||||
|
||||
@@ -154,6 +154,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;
|
||||
@@ -212,7 +217,8 @@ void repo_set_worktree(struct repository *repo, const char *path);
|
||||
void repo_set_hash_algo(struct repository *repo, uint32_t algo);
|
||||
void repo_set_compat_hash_algo(struct repository *repo, uint32_t 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);
|
||||
|
||||
96
setup.c
96
setup.c
@@ -631,6 +631,21 @@ static enum extension_result handle_extension_v0(const char *var,
|
||||
return EXTENSION_UNKNOWN;
|
||||
}
|
||||
|
||||
static void parse_reference_uri(const char *value, char **format,
|
||||
char **payload)
|
||||
{
|
||||
const char *schema_end;
|
||||
|
||||
schema_end = strstr(value, "://");
|
||||
if (!schema_end) {
|
||||
*format = xstrdup(value);
|
||||
*payload = NULL;
|
||||
} else {
|
||||
*format = xstrndup(value, schema_end - value);
|
||||
*payload = xstrdup_or_null(schema_end + 3);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Record any new extensions in this function.
|
||||
*/
|
||||
@@ -673,10 +688,17 @@ static enum extension_result handle_extension(const char *var,
|
||||
return EXTENSION_OK;
|
||||
} else if (!strcmp(ext, "refstorage")) {
|
||||
unsigned int format;
|
||||
char *format_str;
|
||||
|
||||
if (!value)
|
||||
return config_error_nonbool(var);
|
||||
format = ref_storage_format_by_name(value);
|
||||
|
||||
parse_reference_uri(value, &format_str,
|
||||
&data->ref_storage_payload);
|
||||
|
||||
format = ref_storage_format_by_name(format_str);
|
||||
free(format_str);
|
||||
|
||||
if (format == REF_STORAGE_FORMAT_UNKNOWN)
|
||||
return error(_("invalid value for '%s': '%s'"),
|
||||
"extensions.refstorage", value);
|
||||
@@ -852,6 +874,7 @@ void clear_repository_format(struct repository_format *format)
|
||||
string_list_clear(&format->v1_only_extensions, 0);
|
||||
free(format->work_tree);
|
||||
free(format->partial_clone);
|
||||
free(format->ref_storage_payload);
|
||||
init_repository_format(format);
|
||||
}
|
||||
|
||||
@@ -1817,6 +1840,7 @@ const char *setup_git_directory_gently(int *nongit_ok)
|
||||
static struct strbuf cwd = STRBUF_INIT;
|
||||
struct strbuf dir = STRBUF_INIT, gitdir = STRBUF_INIT, report = STRBUF_INIT;
|
||||
const char *prefix = NULL;
|
||||
const char *ref_backend_uri;
|
||||
struct repository_format repo_fmt = REPOSITORY_FORMAT_INIT;
|
||||
|
||||
/*
|
||||
@@ -1944,7 +1968,8 @@ const char *setup_git_directory_gently(int *nongit_ok)
|
||||
repo_set_compat_hash_algo(the_repository,
|
||||
repo_fmt.compat_hash_algo);
|
||||
repo_set_ref_storage_format(the_repository,
|
||||
repo_fmt.ref_storage_format);
|
||||
repo_fmt.ref_storage_format,
|
||||
repo_fmt.ref_storage_payload);
|
||||
the_repository->repository_format_worktree_config =
|
||||
repo_fmt.worktree_config;
|
||||
the_repository->repository_format_relative_worktrees =
|
||||
@@ -1975,6 +2000,25 @@ const char *setup_git_directory_gently(int *nongit_ok)
|
||||
setenv(GIT_PREFIX_ENVIRONMENT, "", 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* The env variable should override the repository config
|
||||
* for 'extensions.refStorage'.
|
||||
*/
|
||||
ref_backend_uri = getenv(GIT_REFERENCE_BACKEND_ENVIRONMENT);
|
||||
if (ref_backend_uri) {
|
||||
char *backend, *payload;
|
||||
enum ref_storage_format format;
|
||||
|
||||
parse_reference_uri(ref_backend_uri, &backend, &payload);
|
||||
format = ref_storage_format_by_name(backend);
|
||||
if (format == REF_STORAGE_FORMAT_UNKNOWN)
|
||||
die(_("unknown ref storage format: '%s'"), backend);
|
||||
repo_set_ref_storage_format(the_repository, format, payload);
|
||||
|
||||
free(backend);
|
||||
free(payload);
|
||||
}
|
||||
|
||||
setup_original_cwd();
|
||||
|
||||
strbuf_release(&dir);
|
||||
@@ -2046,7 +2090,8 @@ void check_repository_format(struct repository_format *fmt)
|
||||
repo_set_hash_algo(the_repository, fmt->hash_algo);
|
||||
repo_set_compat_hash_algo(the_repository, fmt->compat_hash_algo);
|
||||
repo_set_ref_storage_format(the_repository,
|
||||
fmt->ref_storage_format);
|
||||
fmt->ref_storage_format,
|
||||
fmt->ref_storage_payload);
|
||||
the_repository->repository_format_worktree_config =
|
||||
fmt->worktree_config;
|
||||
the_repository->repository_format_submodule_path_cfg =
|
||||
@@ -2319,7 +2364,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)
|
||||
@@ -2328,11 +2374,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;
|
||||
@@ -2375,14 +2430,12 @@ static int is_reinit(void)
|
||||
return ret;
|
||||
}
|
||||
|
||||
void create_reference_database(enum ref_storage_format ref_storage_format,
|
||||
const char *initial_branch, int quiet)
|
||||
void create_reference_database(const char *initial_branch, int quiet)
|
||||
{
|
||||
struct strbuf err = STRBUF_INIT;
|
||||
char *to_free = NULL;
|
||||
int reinit = is_reinit();
|
||||
|
||||
repo_set_ref_storage_format(the_repository, ref_storage_format);
|
||||
if (ref_store_create_on_disk(get_main_ref_store(the_repository), 0, &err))
|
||||
die("failed to set up refs db: %s", err.buf);
|
||||
|
||||
@@ -2616,6 +2669,7 @@ static void repository_format_configure(struct repository_format *repo_fmt,
|
||||
.ignore_repo = 1,
|
||||
.ignore_worktree = 1,
|
||||
};
|
||||
const char *ref_backend_uri;
|
||||
const char *env;
|
||||
|
||||
config_with_options(read_default_format_config, &cfg, NULL, NULL, &opts);
|
||||
@@ -2661,7 +2715,26 @@ static void repository_format_configure(struct repository_format *repo_fmt,
|
||||
} else {
|
||||
repo_fmt->ref_storage_format = REF_STORAGE_FORMAT_DEFAULT;
|
||||
}
|
||||
repo_set_ref_storage_format(the_repository, repo_fmt->ref_storage_format);
|
||||
|
||||
|
||||
ref_backend_uri = getenv(GIT_REFERENCE_BACKEND_ENVIRONMENT);
|
||||
if (ref_backend_uri) {
|
||||
char *backend, *payload;
|
||||
enum ref_storage_format format;
|
||||
|
||||
parse_reference_uri(ref_backend_uri, &backend, &payload);
|
||||
format = ref_storage_format_by_name(backend);
|
||||
if (format == REF_STORAGE_FORMAT_UNKNOWN)
|
||||
die(_("unknown ref storage format: '%s'"), backend);
|
||||
|
||||
repo_fmt->ref_storage_format = format;
|
||||
repo_fmt->ref_storage_payload = payload;
|
||||
|
||||
free(backend);
|
||||
}
|
||||
|
||||
repo_set_ref_storage_format(the_repository, repo_fmt->ref_storage_format,
|
||||
repo_fmt->ref_storage_payload);
|
||||
}
|
||||
|
||||
int init_db(const char *git_dir, const char *real_git_dir,
|
||||
@@ -2717,8 +2790,7 @@ int init_db(const char *git_dir, const char *real_git_dir,
|
||||
&repo_fmt, init_shared_repository);
|
||||
|
||||
if (!(flags & INIT_DB_SKIP_REFDB))
|
||||
create_reference_database(repo_fmt.ref_storage_format,
|
||||
initial_branch, flags & INIT_DB_QUIET);
|
||||
create_reference_database(initial_branch, flags & INIT_DB_QUIET);
|
||||
create_object_directory();
|
||||
|
||||
if (repo_settings_get_shared_repository(the_repository)) {
|
||||
|
||||
4
setup.h
4
setup.h
@@ -172,6 +172,7 @@ struct repository_format {
|
||||
int hash_algo;
|
||||
int compat_hash_algo;
|
||||
enum ref_storage_format ref_storage_format;
|
||||
char *ref_storage_payload;
|
||||
int sparse_index;
|
||||
char *work_tree;
|
||||
struct string_list unknown_extensions;
|
||||
@@ -241,8 +242,7 @@ int init_db(const char *git_dir, const char *real_git_dir,
|
||||
void initialize_repository_version(int hash_algo,
|
||||
enum ref_storage_format ref_storage_format,
|
||||
int reinit);
|
||||
void create_reference_database(enum ref_storage_format ref_storage_format,
|
||||
const char *initial_branch, int quiet);
|
||||
void create_reference_database(const char *initial_branch, int quiet);
|
||||
|
||||
/*
|
||||
* NOTE NOTE NOTE!!
|
||||
|
||||
@@ -213,6 +213,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',
|
||||
|
||||
280
t/t1423-ref-backend.sh
Executable file
280
t/t1423-ref-backend.sh
Executable file
@@ -0,0 +1,280 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='Test reference backend URIs'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
# Run a git command with the provided reference storage. Reset the backend
|
||||
# post running the command.
|
||||
# Usage: run_with_uri <repo> <backend> <uri> <cmd>
|
||||
# <repo> is the relative path to the repo to run the command in.
|
||||
# <backend> is the original ref storage of the repo.
|
||||
# <uri> is the new URI to be set for the ref storage.
|
||||
# <cmd> is the git subcommand to be run in the repository.
|
||||
# <via> if 'config', set the backend via the 'extensions.refStorage' config.
|
||||
# if 'env', set the backend via the 'GIT_REFERENCE_BACKEND' env.
|
||||
run_with_uri () {
|
||||
repo=$1 &&
|
||||
backend=$2 &&
|
||||
uri=$3 &&
|
||||
cmd=$4 &&
|
||||
via=$5 &&
|
||||
|
||||
git -C "$repo" config set core.repositoryformatversion 1 &&
|
||||
if test "$via" = "env"
|
||||
then
|
||||
test_env GIT_REFERENCE_BACKEND="$uri" git -C "$repo" $cmd
|
||||
elif test "$via" = "config"
|
||||
then
|
||||
git -C "$repo" config set extensions.refStorage "$uri" &&
|
||||
git -C "$repo" $cmd &&
|
||||
git -C "$repo" config set extensions.refStorage "$backend"
|
||||
fi
|
||||
}
|
||||
|
||||
# Test a repository with a given reference storage by running and comparing
|
||||
# 'git refs list' before and after setting the new reference backend. If
|
||||
# err_msg is set, expect the command to fail and grep for the provided err_msg.
|
||||
# Usage: run_with_uri <repo> <backend> <uri> <cmd>
|
||||
# <repo> is the relative path to the repo to run the command in.
|
||||
# <backend> is the original ref storage of the repo.
|
||||
# <uri> is the new URI to be set for the ref storage.
|
||||
# <via> if 'config', set the backend via the 'extensions.refStorage' config.
|
||||
# if 'env', set the backend via the 'GIT_REFERENCE_BACKEND' env.
|
||||
# <err_msg> (optional) if set, check if 'git-refs(1)' failed with the provided msg.
|
||||
test_refs_backend () {
|
||||
repo=$1 &&
|
||||
backend=$2 &&
|
||||
uri=$3 &&
|
||||
via=$4 &&
|
||||
err_msg=$5 &&
|
||||
|
||||
|
||||
if test -n "$err_msg";
|
||||
then
|
||||
if test "$via" = "env"
|
||||
then
|
||||
test_env GIT_REFERENCE_BACKEND="$uri" test_must_fail git -C "$repo" refs list 2>err
|
||||
elif test "$via" = "config"
|
||||
then
|
||||
git -C "$repo" config set extensions.refStorage "$uri" &&
|
||||
test_must_fail git -C "$repo" refs list 2>err &&
|
||||
test_grep "$err_msg" err
|
||||
fi
|
||||
else
|
||||
git -C "$repo" refs list >expect &&
|
||||
run_with_uri "$repo" "$backend" "$uri" "refs list" "$via">actual &&
|
||||
test_cmp expect actual
|
||||
fi
|
||||
}
|
||||
|
||||
# Verify that the expected files are present in the gitdir and the refsdir.
|
||||
# Usage: verify_files_exist <gitdir> <refdir>
|
||||
# <gitdir> is the path for the gitdir.
|
||||
# <refdir> is the path for the refdir.
|
||||
verify_files_exist () {
|
||||
gitdir=$1 &&
|
||||
refdir=$2 &&
|
||||
|
||||
# verify that the stubs were added to the $GITDIR.
|
||||
echo "repository uses alternate refs storage" >expect &&
|
||||
test_cmp expect $gitdir/refs/heads &&
|
||||
echo "ref: refs/heads/.invalid" >expect &&
|
||||
test_cmp expect $gitdir/HEAD
|
||||
|
||||
# verify that backend specific files exist.
|
||||
case "$GIT_DEFAULT_REF_FORMAT" in
|
||||
files)
|
||||
test_path_is_dir $refdir/refs/heads &&
|
||||
test_path_is_file $refdir/HEAD;;
|
||||
reftable)
|
||||
test_path_is_dir $refdir/reftable &&
|
||||
test_path_is_file $refdir/reftable/tables.list;;
|
||||
*)
|
||||
BUG "unhandled ref format $GIT_DEFAULT_REF_FORMAT";;
|
||||
esac
|
||||
}
|
||||
|
||||
methods="config env"
|
||||
for method in $methods
|
||||
do
|
||||
|
||||
test_expect_success "$method: URI is invalid" '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
git init repo &&
|
||||
test_refs_backend repo files "reftable@/home/reftable" "$method" \
|
||||
"invalid value for ${SQ}extensions.refstorage${SQ}"
|
||||
'
|
||||
|
||||
test_expect_success "$method: URI ends with colon" '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
git init repo &&
|
||||
test_refs_backend repo files "reftable:" "$method" \
|
||||
"invalid value for ${SQ}extensions.refstorage${SQ}"
|
||||
'
|
||||
|
||||
test_expect_success "$method: unknown reference backend" '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
git init repo &&
|
||||
test_refs_backend repo files "db://.git" "$method" \
|
||||
"invalid value for ${SQ}extensions.refstorage${SQ}"
|
||||
'
|
||||
|
||||
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
|
||||
|
||||
|
||||
for dir in "$(pwd)/repo/.git" "."
|
||||
do
|
||||
|
||||
test_expect_success "$method: read from $to_format backend, $dir dir" '
|
||||
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="$dir/$(sed "s/.* ${SQ}.git\/\(.*\)${SQ}/\1/" out)" &&
|
||||
test_refs_backend . $from_format "$to_format://$BACKEND_PATH" "$method"
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success "$method: write to $to_format backend, $dir dir" '
|
||||
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="$dir/$(sed "s/.* ${SQ}.git\/\(.*\)${SQ}/\1/" out)" &&
|
||||
|
||||
test_refs_backend . $from_format "$to_format://$BACKEND_PATH" "$method" &&
|
||||
|
||||
git refs list >expect &&
|
||||
run_with_uri . "$from_format" "$to_format://$BACKEND_PATH" \
|
||||
"tag -d 1" "$method" &&
|
||||
git refs list >actual &&
|
||||
test_cmp expect actual &&
|
||||
|
||||
git refs list | grep -v "refs/tags/1" >expect &&
|
||||
run_with_uri . "$from_format" "$to_format://$BACKEND_PATH" \
|
||||
"refs list" "$method" >actual &&
|
||||
test_cmp expect actual
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success "$method: with worktree and $to_format backend, $dir dir" '
|
||||
test_when_finished "rm -rf repo wt" &&
|
||||
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="$dir/$(sed "s/.* ${SQ}.git\/\(.*\)${SQ}/\1/" out)" &&
|
||||
|
||||
run_with_uri . "$from_format" "$to_format://$BACKEND_PATH" \
|
||||
"worktree add ../wt 2" "$method" &&
|
||||
|
||||
run_with_uri . "$from_format" "$to_format://$BACKEND_PATH" \
|
||||
"for-each-ref --include-root-refs" "$method" >actual &&
|
||||
run_with_uri ../wt "$from_format" "$to_format://$BACKEND_PATH" \
|
||||
"for-each-ref --include-root-refs" "$method" >expect &&
|
||||
! test_cmp expect actual &&
|
||||
|
||||
run_with_uri . "$from_format" "$to_format://$BACKEND_PATH" \
|
||||
"rev-parse 2" "$method" >actual &&
|
||||
run_with_uri ../wt "$from_format" "$to_format://$BACKEND_PATH" \
|
||||
"rev-parse HEAD" "$method" >expect &&
|
||||
test_cmp expect actual
|
||||
)
|
||||
'
|
||||
done # closes dir
|
||||
|
||||
test_expect_success "migrating repository to $to_format with alternate refs directory" '
|
||||
test_when_finished "rm -rf repo refdir" &&
|
||||
mkdir refdir &&
|
||||
GIT_REFERENCE_BACKEND="${from_format}://$(pwd)/refdir" git init repo &&
|
||||
(
|
||||
cd repo &&
|
||||
|
||||
test_commit 1 &&
|
||||
test_commit 2 &&
|
||||
test_commit 3 &&
|
||||
|
||||
git refs migrate --ref-format=$to_format &&
|
||||
git refs list >out &&
|
||||
test_grep "refs/tags/1" out &&
|
||||
test_grep "refs/tags/2" out &&
|
||||
test_grep "refs/tags/3" out
|
||||
)
|
||||
'
|
||||
|
||||
done # closes to_format
|
||||
done # closes from_format
|
||||
|
||||
done # closes method
|
||||
|
||||
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 &&
|
||||
verify_files_exist repo/.git refdir &&
|
||||
(
|
||||
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
|
||||
)
|
||||
'
|
||||
|
||||
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 &&
|
||||
|
||||
verify_files_exist repo/.git refdir &&
|
||||
|
||||
git -C source for-each-ref refs/tags/ >expect &&
|
||||
git -C repo for-each-ref refs/tags/ >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_done
|
||||
Reference in New Issue
Block a user