mirror of https://github.com/git/git.git
Merge branch 'ps/refstorage-extension'
Introduce a new extension "refstorage" so that we can mark a repository that uses a non-default ref backend, like reftable. * ps/refstorage-extension: t9500: write "extensions.refstorage" into config builtin/clone: introduce `--ref-format=` value flag builtin/init: introduce `--ref-format=` value flag builtin/rev-parse: introduce `--show-ref-format` flag t: introduce GIT_TEST_DEFAULT_REF_FORMAT envvar setup: introduce GIT_DEFAULT_REF_FORMAT envvar setup: introduce "extensions.refStorage" extension setup: set repository's formats on init setup: start tracking ref storage format refs: refactor logic to look up storage backends worktree: skip reading HEAD when repairing worktrees t: introduce DEFAULT_REPO_FORMAT prereq
This commit is contained in:
commit
32c6fc3e30
|
@ -7,6 +7,17 @@ Note that this setting should only be set by linkgit:git-init[1] or
|
|||
linkgit:git-clone[1]. Trying to change it after initialization will not
|
||||
work and will produce hard-to-diagnose issues.
|
||||
|
||||
extensions.refStorage::
|
||||
Specify the ref storage format to use. The acceptable values are:
|
||||
+
|
||||
include::../ref-storage-format.txt[]
|
||||
+
|
||||
It is an error to specify this key unless `core.repositoryFormatVersion` is 1.
|
||||
+
|
||||
Note that this setting should only be set by linkgit:git-init[1] or
|
||||
linkgit:git-clone[1]. Trying to change it after initialization will not
|
||||
work and will produce hard-to-diagnose issues.
|
||||
|
||||
extensions.worktreeConfig::
|
||||
If enabled, then worktrees will load config settings from the
|
||||
`$GIT_DIR/config.worktree` file in addition to the
|
||||
|
|
|
@ -311,6 +311,12 @@ or `--mirror` is given)
|
|||
The result is Git repository can be separated from working
|
||||
tree.
|
||||
|
||||
--ref-format=<ref-format::
|
||||
|
||||
Specify the given ref storage format for the repository. The valid values are:
|
||||
+
|
||||
include::ref-storage-format.txt[]
|
||||
|
||||
-j <n>::
|
||||
--jobs <n>::
|
||||
The number of submodules fetched at the same time.
|
||||
|
|
|
@ -11,6 +11,7 @@ SYNOPSIS
|
|||
[verse]
|
||||
'git init' [-q | --quiet] [--bare] [--template=<template-directory>]
|
||||
[--separate-git-dir <git-dir>] [--object-format=<format>]
|
||||
[--ref-format=<format>]
|
||||
[-b <branch-name> | --initial-branch=<branch-name>]
|
||||
[--shared[=<permissions>]] [<directory>]
|
||||
|
||||
|
@ -57,6 +58,12 @@ values are 'sha1' and (if enabled) 'sha256'. 'sha1' is the default.
|
|||
+
|
||||
include::object-format-disclaimer.txt[]
|
||||
|
||||
--ref-format=<format>::
|
||||
|
||||
Specify the given ref storage format for the repository. The valid values are:
|
||||
+
|
||||
include::ref-storage-format.txt[]
|
||||
|
||||
--template=<template-directory>::
|
||||
|
||||
Specify the directory from which templates will be used. (See the "TEMPLATE
|
||||
|
|
|
@ -307,6 +307,9 @@ The following options are unaffected by `--path-format`:
|
|||
input, multiple algorithms may be printed, space-separated.
|
||||
If not specified, the default is "storage".
|
||||
|
||||
--show-ref-format::
|
||||
Show the reference storage format used for the repository.
|
||||
|
||||
|
||||
Other Options
|
||||
~~~~~~~~~~~~~
|
||||
|
|
|
@ -556,6 +556,11 @@ double-quotes and respecting backslash escapes. E.g., the value
|
|||
is always used. The default is "sha1".
|
||||
See `--object-format` in linkgit:git-init[1].
|
||||
|
||||
`GIT_DEFAULT_REF_FORMAT`::
|
||||
If this variable is set, the default reference backend format for new
|
||||
repositories will be set to this value. The default is "files".
|
||||
See `--ref-format` in linkgit:git-init[1].
|
||||
|
||||
Git Commits
|
||||
~~~~~~~~~~~
|
||||
`GIT_AUTHOR_NAME`::
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
* `files` for loose files with packed-refs. This is the default.
|
|
@ -100,3 +100,8 @@ If set, by default "git config" reads from both "config" and
|
|||
multiple working directory mode, "config" file is shared while
|
||||
"config.worktree" is per-working directory (i.e., it's in
|
||||
GIT_COMMON_DIR/worktrees/<id>/config.worktree)
|
||||
|
||||
==== `refStorage`
|
||||
|
||||
Specifies the file format for the ref database. The only valid value
|
||||
is `files` (loose references with a packed-refs file).
|
||||
|
|
|
@ -71,6 +71,7 @@ static char *remote_name = NULL;
|
|||
static char *option_branch = NULL;
|
||||
static struct string_list option_not = STRING_LIST_INIT_NODUP;
|
||||
static const char *real_git_dir;
|
||||
static const char *ref_format;
|
||||
static char *option_upload_pack = "git-upload-pack";
|
||||
static int option_verbosity;
|
||||
static int option_progress = -1;
|
||||
|
@ -156,6 +157,8 @@ static struct option builtin_clone_options[] = {
|
|||
N_("any cloned submodules will be shallow")),
|
||||
OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"),
|
||||
N_("separate git dir from working tree")),
|
||||
OPT_STRING(0, "ref-format", &ref_format, N_("format"),
|
||||
N_("specify the reference format to use")),
|
||||
OPT_STRING_LIST('c', "config", &option_config, N_("key=value"),
|
||||
N_("set config inside the new repository")),
|
||||
OPT_STRING_LIST(0, "server-option", &server_options,
|
||||
|
@ -931,6 +934,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
|
|||
int submodule_progress;
|
||||
int filter_submodules = 0;
|
||||
int hash_algo;
|
||||
unsigned int ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN;
|
||||
const int do_not_override_repo_unix_permissions = -1;
|
||||
|
||||
struct transport_ls_refs_options transport_ls_refs_options =
|
||||
|
@ -956,6 +960,12 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
|
|||
if (option_single_branch == -1)
|
||||
option_single_branch = deepen ? 1 : 0;
|
||||
|
||||
if (ref_format) {
|
||||
ref_storage_format = ref_storage_format_by_name(ref_format);
|
||||
if (ref_storage_format == REF_STORAGE_FORMAT_UNKNOWN)
|
||||
die(_("unknown ref storage format '%s'"), ref_format);
|
||||
}
|
||||
|
||||
if (option_mirror)
|
||||
option_bare = 1;
|
||||
|
||||
|
@ -1106,7 +1116,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
|
|||
* repository, and reference backends may persist that information into
|
||||
* their on-disk data structures.
|
||||
*/
|
||||
init_db(git_dir, real_git_dir, option_template, GIT_HASH_UNKNOWN, NULL,
|
||||
init_db(git_dir, real_git_dir, option_template, GIT_HASH_UNKNOWN,
|
||||
ref_storage_format, NULL,
|
||||
do_not_override_repo_unix_permissions, INIT_DB_QUIET | INIT_DB_SKIP_REFDB);
|
||||
|
||||
if (real_git_dir) {
|
||||
|
@ -1289,9 +1300,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
|
|||
* ours to the same thing.
|
||||
*/
|
||||
hash_algo = hash_algo_by_ptr(transport_get_hash_algo(transport));
|
||||
initialize_repository_version(hash_algo, 1);
|
||||
initialize_repository_version(hash_algo, the_repository->ref_storage_format, 1);
|
||||
repo_set_hash_algo(the_repository, hash_algo);
|
||||
create_reference_database(NULL, 1);
|
||||
create_reference_database(the_repository->ref_storage_format, NULL, 1);
|
||||
|
||||
/*
|
||||
* Before fetching from the remote, download and install bundle
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
#include "object-file.h"
|
||||
#include "parse-options.h"
|
||||
#include "path.h"
|
||||
#include "refs.h"
|
||||
#include "repository.h"
|
||||
#include "setup.h"
|
||||
#include "strbuf.h"
|
||||
|
||||
|
@ -56,6 +58,7 @@ static int shared_callback(const struct option *opt, const char *arg, int unset)
|
|||
static const char *const init_db_usage[] = {
|
||||
N_("git init [-q | --quiet] [--bare] [--template=<template-directory>]\n"
|
||||
" [--separate-git-dir <git-dir>] [--object-format=<format>]\n"
|
||||
" [--ref-format=<format>]\n"
|
||||
" [-b <branch-name> | --initial-branch=<branch-name>]\n"
|
||||
" [--shared[=<permissions>]] [<directory>]"),
|
||||
NULL
|
||||
|
@ -75,8 +78,10 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
|
|||
const char *template_dir = NULL;
|
||||
unsigned int flags = 0;
|
||||
const char *object_format = NULL;
|
||||
const char *ref_format = NULL;
|
||||
const char *initial_branch = NULL;
|
||||
int hash_algo = GIT_HASH_UNKNOWN;
|
||||
unsigned int ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN;
|
||||
int init_shared_repository = -1;
|
||||
const struct option init_db_options[] = {
|
||||
OPT_STRING(0, "template", &template_dir, N_("template-directory"),
|
||||
|
@ -94,6 +99,8 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
|
|||
N_("override the name of the initial branch")),
|
||||
OPT_STRING(0, "object-format", &object_format, N_("hash"),
|
||||
N_("specify the hash algorithm to use")),
|
||||
OPT_STRING(0, "ref-format", &ref_format, N_("format"),
|
||||
N_("specify the reference format to use")),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
|
@ -157,6 +164,12 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
|
|||
die(_("unknown hash algorithm '%s'"), object_format);
|
||||
}
|
||||
|
||||
if (ref_format) {
|
||||
ref_storage_format = ref_storage_format_by_name(ref_format);
|
||||
if (ref_storage_format == REF_STORAGE_FORMAT_UNKNOWN)
|
||||
die(_("unknown ref storage format '%s'"), ref_format);
|
||||
}
|
||||
|
||||
if (init_shared_repository != -1)
|
||||
set_shared_repository(init_shared_repository);
|
||||
|
||||
|
@ -235,5 +248,6 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
|
|||
|
||||
flags |= INIT_DB_EXIST_OK;
|
||||
return init_db(git_dir, real_git_dir, template_dir, hash_algo,
|
||||
initial_branch, init_shared_repository, flags);
|
||||
ref_storage_format, initial_branch,
|
||||
init_shared_repository, flags);
|
||||
}
|
||||
|
|
|
@ -1062,6 +1062,10 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
|
|||
puts(the_hash_algo->name);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--show-ref-format")) {
|
||||
puts(ref_storage_format_to_name(the_repository->ref_storage_format));
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--end-of-options")) {
|
||||
seen_end_of_options = 1;
|
||||
if (filter & (DO_FLAGS | DO_REVS))
|
||||
|
|
34
refs.c
34
refs.c
|
@ -33,17 +33,33 @@
|
|||
/*
|
||||
* List of all available backends
|
||||
*/
|
||||
static struct ref_storage_be *refs_backends = &refs_be_files;
|
||||
static const struct ref_storage_be *refs_backends[] = {
|
||||
[REF_STORAGE_FORMAT_FILES] = &refs_be_files,
|
||||
};
|
||||
|
||||
static struct ref_storage_be *find_ref_storage_backend(const char *name)
|
||||
static const struct ref_storage_be *find_ref_storage_backend(unsigned int ref_storage_format)
|
||||
{
|
||||
struct ref_storage_be *be;
|
||||
for (be = refs_backends; be; be = be->next)
|
||||
if (!strcmp(be->name, name))
|
||||
return be;
|
||||
if (ref_storage_format < ARRAY_SIZE(refs_backends))
|
||||
return refs_backends[ref_storage_format];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned int ref_storage_format_by_name(const char *name)
|
||||
{
|
||||
for (unsigned int i = 0; i < ARRAY_SIZE(refs_backends); i++)
|
||||
if (refs_backends[i] && !strcmp(refs_backends[i]->name, name))
|
||||
return i;
|
||||
return REF_STORAGE_FORMAT_UNKNOWN;
|
||||
}
|
||||
|
||||
const char *ref_storage_format_to_name(unsigned int ref_storage_format)
|
||||
{
|
||||
const struct ref_storage_be *be = find_ref_storage_backend(ref_storage_format);
|
||||
if (!be)
|
||||
return "unknown";
|
||||
return be->name;
|
||||
}
|
||||
|
||||
/*
|
||||
* How to handle various characters in refnames:
|
||||
* 0: An acceptable character for refs
|
||||
|
@ -2082,12 +2098,12 @@ static struct ref_store *ref_store_init(struct repository *repo,
|
|||
const char *gitdir,
|
||||
unsigned int flags)
|
||||
{
|
||||
const char *be_name = "files";
|
||||
struct ref_storage_be *be = find_ref_storage_backend(be_name);
|
||||
const struct ref_storage_be *be;
|
||||
struct ref_store *refs;
|
||||
|
||||
be = find_ref_storage_backend(repo->ref_storage_format);
|
||||
if (!be)
|
||||
BUG("reference backend %s is unknown", be_name);
|
||||
BUG("reference backend is unknown");
|
||||
|
||||
refs = be->init(repo, gitdir, flags);
|
||||
return refs;
|
||||
|
|
3
refs.h
3
refs.h
|
@ -11,6 +11,9 @@ struct string_list;
|
|||
struct string_list_item;
|
||||
struct worktree;
|
||||
|
||||
unsigned int ref_storage_format_by_name(const char *name);
|
||||
const char *ref_storage_format_to_name(unsigned int ref_storage_format);
|
||||
|
||||
/*
|
||||
* Resolve a reference, recursively following symbolic refererences.
|
||||
*
|
||||
|
|
|
@ -426,7 +426,6 @@ static int debug_reflog_expire(struct ref_store *ref_store, const char *refname,
|
|||
}
|
||||
|
||||
struct ref_storage_be refs_be_debug = {
|
||||
.next = NULL,
|
||||
.name = "debug",
|
||||
.init = NULL,
|
||||
.init_db = debug_init_db,
|
||||
|
|
|
@ -3239,7 +3239,6 @@ static int files_init_db(struct ref_store *ref_store, struct strbuf *err UNUSED)
|
|||
}
|
||||
|
||||
struct ref_storage_be refs_be_files = {
|
||||
.next = NULL,
|
||||
.name = "files",
|
||||
.init = files_ref_store_create,
|
||||
.init_db = files_init_db,
|
||||
|
|
|
@ -1704,7 +1704,6 @@ static struct ref_iterator *packed_reflog_iterator_begin(struct ref_store *ref_s
|
|||
}
|
||||
|
||||
struct ref_storage_be refs_be_packed = {
|
||||
.next = NULL,
|
||||
.name = "packed",
|
||||
.init = packed_ref_store_create,
|
||||
.init_db = packed_init_db,
|
||||
|
|
|
@ -663,7 +663,6 @@ typedef int read_symbolic_ref_fn(struct ref_store *ref_store, const char *refnam
|
|||
struct strbuf *referent);
|
||||
|
||||
struct ref_storage_be {
|
||||
struct ref_storage_be *next;
|
||||
const char *name;
|
||||
ref_store_init_fn *init;
|
||||
ref_init_db_fn *init_db;
|
||||
|
|
|
@ -104,6 +104,11 @@ void repo_set_hash_algo(struct repository *repo, int hash_algo)
|
|||
repo->hash_algo = &hash_algos[hash_algo];
|
||||
}
|
||||
|
||||
void repo_set_ref_storage_format(struct repository *repo, unsigned int format)
|
||||
{
|
||||
repo->ref_storage_format = format;
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempt to resolve and set the provided 'gitdir' for repository 'repo'.
|
||||
* Return 0 upon success and a non-zero value upon failure.
|
||||
|
@ -184,6 +189,7 @@ int repo_init(struct repository *repo,
|
|||
goto error;
|
||||
|
||||
repo_set_hash_algo(repo, format.hash_algo);
|
||||
repo_set_ref_storage_format(repo, format.ref_storage_format);
|
||||
repo->repository_format_worktree_config = format.worktree_config;
|
||||
|
||||
/* take ownership of format.partial_clone */
|
||||
|
|
|
@ -24,6 +24,9 @@ enum fetch_negotiation_setting {
|
|||
FETCH_NEGOTIATION_NOOP,
|
||||
};
|
||||
|
||||
#define REF_STORAGE_FORMAT_UNKNOWN 0
|
||||
#define REF_STORAGE_FORMAT_FILES 1
|
||||
|
||||
struct repo_settings {
|
||||
int initialized;
|
||||
|
||||
|
@ -160,6 +163,9 @@ struct repository {
|
|||
/* Repository's current hash algorithm, as serialized on disk. */
|
||||
const struct git_hash_algo *hash_algo;
|
||||
|
||||
/* Repository's reference storage format, as serialized on disk. */
|
||||
unsigned int ref_storage_format;
|
||||
|
||||
/* A unique-id for tracing purposes. */
|
||||
int trace2_repo_id;
|
||||
|
||||
|
@ -199,6 +205,7 @@ void repo_set_gitdir(struct repository *repo, const char *root,
|
|||
const struct set_gitdir_args *extra_args);
|
||||
void repo_set_worktree(struct repository *repo, const char *path);
|
||||
void repo_set_hash_algo(struct repository *repo, int algo);
|
||||
void repo_set_ref_storage_format(struct repository *repo, unsigned int format);
|
||||
void initialize_the_repository(void);
|
||||
RESULT_MUST_BE_USED
|
||||
int repo_init(struct repository *r, const char *gitdir, const char *worktree);
|
||||
|
|
66
setup.c
66
setup.c
|
@ -591,6 +591,17 @@ static enum extension_result handle_extension(const char *var,
|
|||
"extensions.objectformat", value);
|
||||
data->hash_algo = format;
|
||||
return EXTENSION_OK;
|
||||
} else if (!strcmp(ext, "refstorage")) {
|
||||
unsigned int format;
|
||||
|
||||
if (!value)
|
||||
return config_error_nonbool(var);
|
||||
format = ref_storage_format_by_name(value);
|
||||
if (format == REF_STORAGE_FORMAT_UNKNOWN)
|
||||
return error(_("invalid value for '%s': '%s'"),
|
||||
"extensions.refstorage", value);
|
||||
data->ref_storage_format = format;
|
||||
return EXTENSION_OK;
|
||||
}
|
||||
return EXTENSION_UNKNOWN;
|
||||
}
|
||||
|
@ -1565,6 +1576,8 @@ const char *setup_git_directory_gently(int *nongit_ok)
|
|||
}
|
||||
if (startup_info->have_repository) {
|
||||
repo_set_hash_algo(the_repository, repo_fmt.hash_algo);
|
||||
repo_set_ref_storage_format(the_repository,
|
||||
repo_fmt.ref_storage_format);
|
||||
the_repository->repository_format_worktree_config =
|
||||
repo_fmt.worktree_config;
|
||||
/* take ownership of repo_fmt.partial_clone */
|
||||
|
@ -1658,6 +1671,8 @@ void check_repository_format(struct repository_format *fmt)
|
|||
check_repository_format_gently(get_git_dir(), fmt, NULL);
|
||||
startup_info->have_repository = 1;
|
||||
repo_set_hash_algo(the_repository, fmt->hash_algo);
|
||||
repo_set_ref_storage_format(the_repository,
|
||||
fmt->ref_storage_format);
|
||||
the_repository->repository_format_worktree_config =
|
||||
fmt->worktree_config;
|
||||
the_repository->repository_format_partial_clone =
|
||||
|
@ -1866,12 +1881,15 @@ static int needs_work_tree_config(const char *git_dir, const char *work_tree)
|
|||
return 1;
|
||||
}
|
||||
|
||||
void initialize_repository_version(int hash_algo, int reinit)
|
||||
void initialize_repository_version(int hash_algo,
|
||||
unsigned int ref_storage_format,
|
||||
int reinit)
|
||||
{
|
||||
char repo_version_string[10];
|
||||
int repo_version = GIT_REPO_VERSION;
|
||||
|
||||
if (hash_algo != GIT_HASH_SHA1)
|
||||
if (hash_algo != GIT_HASH_SHA1 ||
|
||||
ref_storage_format != REF_STORAGE_FORMAT_FILES)
|
||||
repo_version = GIT_REPO_VERSION_READ;
|
||||
|
||||
/* This forces creation of new config file */
|
||||
|
@ -1884,6 +1902,10 @@ void initialize_repository_version(int hash_algo, int reinit)
|
|||
hash_algos[hash_algo].name);
|
||||
else if (reinit)
|
||||
git_config_set_gently("extensions.objectformat", NULL);
|
||||
|
||||
if (ref_storage_format != REF_STORAGE_FORMAT_FILES)
|
||||
git_config_set("extensions.refstorage",
|
||||
ref_storage_format_to_name(ref_storage_format));
|
||||
}
|
||||
|
||||
static int is_reinit(void)
|
||||
|
@ -1898,7 +1920,8 @@ static int is_reinit(void)
|
|||
return ret;
|
||||
}
|
||||
|
||||
void create_reference_database(const char *initial_branch, int quiet)
|
||||
void create_reference_database(unsigned int ref_storage_format,
|
||||
const char *initial_branch, int quiet)
|
||||
{
|
||||
struct strbuf err = STRBUF_INIT;
|
||||
int reinit = is_reinit();
|
||||
|
@ -1918,6 +1941,7 @@ void create_reference_database(const char *initial_branch, int quiet)
|
|||
safe_create_dir(git_path("refs"), 1);
|
||||
adjust_shared_perm(git_path("refs"));
|
||||
|
||||
repo_set_ref_storage_format(the_repository, ref_storage_format);
|
||||
if (refs_init_db(&err))
|
||||
die("failed to set up refs db: %s", err.buf);
|
||||
|
||||
|
@ -2023,7 +2047,7 @@ static int create_default_files(const char *template_path,
|
|||
adjust_shared_perm(get_git_dir());
|
||||
}
|
||||
|
||||
initialize_repository_version(fmt->hash_algo, 0);
|
||||
initialize_repository_version(fmt->hash_algo, fmt->ref_storage_format, 0);
|
||||
|
||||
/* Check filemode trustability */
|
||||
path = git_path_buf(&buf, "config");
|
||||
|
@ -2136,8 +2160,29 @@ static void validate_hash_algorithm(struct repository_format *repo_fmt, int hash
|
|||
}
|
||||
}
|
||||
|
||||
static void validate_ref_storage_format(struct repository_format *repo_fmt,
|
||||
unsigned int format)
|
||||
{
|
||||
const char *name = getenv("GIT_DEFAULT_REF_FORMAT");
|
||||
|
||||
if (repo_fmt->version >= 0 &&
|
||||
format != REF_STORAGE_FORMAT_UNKNOWN &&
|
||||
format != repo_fmt->ref_storage_format) {
|
||||
die(_("attempt to reinitialize repository with different reference storage format"));
|
||||
} else if (format != REF_STORAGE_FORMAT_UNKNOWN) {
|
||||
repo_fmt->ref_storage_format = format;
|
||||
} else if (name) {
|
||||
format = ref_storage_format_by_name(name);
|
||||
if (format == REF_STORAGE_FORMAT_UNKNOWN)
|
||||
die(_("unknown ref storage format '%s'"), name);
|
||||
repo_fmt->ref_storage_format = format;
|
||||
}
|
||||
}
|
||||
|
||||
int init_db(const char *git_dir, const char *real_git_dir,
|
||||
const char *template_dir, int hash, const char *initial_branch,
|
||||
const char *template_dir, int hash,
|
||||
unsigned int ref_storage_format,
|
||||
const char *initial_branch,
|
||||
int init_shared_repository, unsigned int flags)
|
||||
{
|
||||
int reinit;
|
||||
|
@ -2180,13 +2225,22 @@ int init_db(const char *git_dir, const char *real_git_dir,
|
|||
check_repository_format(&repo_fmt);
|
||||
|
||||
validate_hash_algorithm(&repo_fmt, hash);
|
||||
validate_ref_storage_format(&repo_fmt, ref_storage_format);
|
||||
|
||||
reinit = create_default_files(template_dir, original_git_dir,
|
||||
&repo_fmt, prev_bare_repository,
|
||||
init_shared_repository);
|
||||
|
||||
/*
|
||||
* Now that we have set up both the hash algorithm and the ref storage
|
||||
* format we can update the repository's settings accordingly.
|
||||
*/
|
||||
repo_set_hash_algo(the_repository, repo_fmt.hash_algo);
|
||||
repo_set_ref_storage_format(the_repository, repo_fmt.ref_storage_format);
|
||||
|
||||
if (!(flags & INIT_DB_SKIP_REFDB))
|
||||
create_reference_database(initial_branch, flags & INIT_DB_QUIET);
|
||||
create_reference_database(repo_fmt.ref_storage_format,
|
||||
initial_branch, flags & INIT_DB_QUIET);
|
||||
create_object_directory();
|
||||
|
||||
if (get_shared_repository()) {
|
||||
|
|
10
setup.h
10
setup.h
|
@ -115,6 +115,7 @@ struct repository_format {
|
|||
int worktree_config;
|
||||
int is_bare;
|
||||
int hash_algo;
|
||||
unsigned int ref_storage_format;
|
||||
int sparse_index;
|
||||
char *work_tree;
|
||||
struct string_list unknown_extensions;
|
||||
|
@ -131,6 +132,7 @@ struct repository_format {
|
|||
.version = -1, \
|
||||
.is_bare = -1, \
|
||||
.hash_algo = GIT_HASH_SHA1, \
|
||||
.ref_storage_format = REF_STORAGE_FORMAT_FILES, \
|
||||
.unknown_extensions = STRING_LIST_INIT_DUP, \
|
||||
.v1_only_extensions = STRING_LIST_INIT_DUP, \
|
||||
}
|
||||
|
@ -175,10 +177,14 @@ void check_repository_format(struct repository_format *fmt);
|
|||
|
||||
int init_db(const char *git_dir, const char *real_git_dir,
|
||||
const char *template_dir, int hash_algo,
|
||||
unsigned int ref_storage_format,
|
||||
const char *initial_branch, int init_shared_repository,
|
||||
unsigned int flags);
|
||||
void initialize_repository_version(int hash_algo, int reinit);
|
||||
void create_reference_database(const char *initial_branch, int quiet);
|
||||
void initialize_repository_version(int hash_algo,
|
||||
unsigned int ref_storage_format,
|
||||
int reinit);
|
||||
void create_reference_database(unsigned int ref_storage_format,
|
||||
const char *initial_branch, int quiet);
|
||||
|
||||
/*
|
||||
* NOTE NOTE NOTE!!
|
||||
|
|
3
t/README
3
t/README
|
@ -479,6 +479,9 @@ GIT_TEST_DEFAULT_HASH=<hash-algo> specifies which hash algorithm to
|
|||
use in the test scripts. Recognized values for <hash-algo> are "sha1"
|
||||
and "sha256".
|
||||
|
||||
GIT_TEST_DEFAULT_REF_FORMAT=<format> specifies which ref storage format
|
||||
to use in the test scripts. Recognized values for <format> are "files".
|
||||
|
||||
GIT_TEST_NO_WRITE_REV_INDEX=<boolean>, when true disables the
|
||||
'pack.writeReverseIndex' setting.
|
||||
|
||||
|
|
|
@ -532,6 +532,76 @@ test_expect_success 'init rejects attempts to initialize with different hash' '
|
|||
test_must_fail git -C sha256 init --object-format=sha1
|
||||
'
|
||||
|
||||
test_expect_success DEFAULT_REPO_FORMAT 'extensions.refStorage is not allowed with repo version 0' '
|
||||
test_when_finished "rm -rf refstorage" &&
|
||||
git init refstorage &&
|
||||
git -C refstorage config extensions.refStorage files &&
|
||||
test_must_fail git -C refstorage rev-parse 2>err &&
|
||||
grep "repo version is 0, but v1-only extension found" err
|
||||
'
|
||||
|
||||
test_expect_success DEFAULT_REPO_FORMAT 'extensions.refStorage with files backend' '
|
||||
test_when_finished "rm -rf refstorage" &&
|
||||
git init refstorage &&
|
||||
git -C refstorage config core.repositoryformatversion 1 &&
|
||||
git -C refstorage config extensions.refStorage files &&
|
||||
test_commit -C refstorage A &&
|
||||
git -C refstorage rev-parse --verify HEAD
|
||||
'
|
||||
|
||||
test_expect_success DEFAULT_REPO_FORMAT 'extensions.refStorage with unknown backend' '
|
||||
test_when_finished "rm -rf refstorage" &&
|
||||
git init refstorage &&
|
||||
git -C refstorage config core.repositoryformatversion 1 &&
|
||||
git -C refstorage config extensions.refStorage garbage &&
|
||||
test_must_fail git -C refstorage rev-parse 2>err &&
|
||||
grep "invalid value for ${SQ}extensions.refstorage${SQ}: ${SQ}garbage${SQ}" err
|
||||
'
|
||||
|
||||
test_expect_success DEFAULT_REPO_FORMAT 'init with GIT_DEFAULT_REF_FORMAT=files' '
|
||||
test_when_finished "rm -rf refformat" &&
|
||||
GIT_DEFAULT_REF_FORMAT=files git init refformat &&
|
||||
echo 0 >expect &&
|
||||
git -C refformat config core.repositoryformatversion >actual &&
|
||||
test_cmp expect actual &&
|
||||
test_must_fail git -C refformat config extensions.refstorage
|
||||
'
|
||||
|
||||
test_expect_success 'init with GIT_DEFAULT_REF_FORMAT=garbage' '
|
||||
test_when_finished "rm -rf refformat" &&
|
||||
cat >expect <<-EOF &&
|
||||
fatal: unknown ref storage format ${SQ}garbage${SQ}
|
||||
EOF
|
||||
test_must_fail env GIT_DEFAULT_REF_FORMAT=garbage git init refformat 2>err &&
|
||||
test_cmp expect err
|
||||
'
|
||||
|
||||
test_expect_success 'init with --ref-format=files' '
|
||||
test_when_finished "rm -rf refformat" &&
|
||||
git init --ref-format=files refformat &&
|
||||
echo files >expect &&
|
||||
git -C refformat rev-parse --show-ref-format >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 're-init with same format' '
|
||||
test_when_finished "rm -rf refformat" &&
|
||||
git init --ref-format=files refformat &&
|
||||
git init --ref-format=files refformat &&
|
||||
echo files >expect &&
|
||||
git -C refformat rev-parse --show-ref-format >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'init with --ref-format=garbage' '
|
||||
test_when_finished "rm -rf refformat" &&
|
||||
cat >expect <<-EOF &&
|
||||
fatal: unknown ref storage format ${SQ}garbage${SQ}
|
||||
EOF
|
||||
test_must_fail git init --ref-format=garbage refformat 2>err &&
|
||||
test_cmp expect err
|
||||
'
|
||||
|
||||
test_expect_success MINGW 'core.hidedotfiles = false' '
|
||||
git config --global core.hidedotfiles false &&
|
||||
rm -rf newdir &&
|
||||
|
|
|
@ -208,6 +208,23 @@ test_expect_success 'rev-parse --show-object-format in repo' '
|
|||
grep "unknown mode for --show-object-format: squeamish-ossifrage" err
|
||||
'
|
||||
|
||||
test_expect_success 'rev-parse --show-ref-format' '
|
||||
test_detect_ref_format >expect &&
|
||||
git rev-parse --show-ref-format >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'rev-parse --show-ref-format with invalid storage' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
git init repo &&
|
||||
(
|
||||
cd repo &&
|
||||
git config extensions.refstorage broken &&
|
||||
test_must_fail git rev-parse --show-ref-format 2>err &&
|
||||
grep "error: invalid value for ${SQ}extensions.refstorage${SQ}: ${SQ}broken${SQ}" err
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success '--show-toplevel from subdir of working tree' '
|
||||
pwd >expect &&
|
||||
git -C sub/dir rev-parse --show-toplevel >actual &&
|
||||
|
|
|
@ -519,7 +519,7 @@ EOF
|
|||
|
||||
mv .git/config .git/config-saved
|
||||
|
||||
test_expect_success SHA1 'git branch -m q q2 without config should succeed' '
|
||||
test_expect_success DEFAULT_REPO_FORMAT 'git branch -m q q2 without config should succeed' '
|
||||
git branch -m q q2 &&
|
||||
git branch -m q2 q
|
||||
'
|
||||
|
|
|
@ -157,6 +157,23 @@ test_expect_success 'clone --mirror does not repeat tags' '
|
|||
|
||||
'
|
||||
|
||||
test_expect_success 'clone with files ref format' '
|
||||
test_when_finished "rm -rf ref-storage" &&
|
||||
git clone --ref-format=files --mirror src ref-storage &&
|
||||
echo files >expect &&
|
||||
git -C ref-storage rev-parse --show-ref-format >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'clone with garbage ref format' '
|
||||
cat >expect <<-EOF &&
|
||||
fatal: unknown ref storage format ${SQ}garbage${SQ}
|
||||
EOF
|
||||
test_must_fail git clone --ref-format=garbage --mirror src ref-storage 2>err &&
|
||||
test_cmp expect err &&
|
||||
test_path_is_missing ref-storage
|
||||
'
|
||||
|
||||
test_expect_success 'clone to destination with trailing /' '
|
||||
|
||||
git clone src target-1/ &&
|
||||
|
|
|
@ -627,6 +627,7 @@ test_expect_success \
|
|||
test_expect_success 'setup' '
|
||||
version=$(git config core.repositoryformatversion) &&
|
||||
algo=$(test_might_fail git config extensions.objectformat) &&
|
||||
refstorage=$(test_might_fail git config extensions.refstorage) &&
|
||||
cat >.git/config <<-\EOF &&
|
||||
# testing noval and alternate separator
|
||||
[gitweb]
|
||||
|
@ -637,6 +638,10 @@ test_expect_success 'setup' '
|
|||
if test -n "$algo"
|
||||
then
|
||||
git config extensions.objectformat "$algo"
|
||||
fi &&
|
||||
if test -n "$refstorage"
|
||||
then
|
||||
git config extensions.refstorage "$refstorage"
|
||||
fi
|
||||
'
|
||||
|
||||
|
|
|
@ -1659,6 +1659,11 @@ test_detect_hash () {
|
|||
test_hash_algo="${GIT_TEST_DEFAULT_HASH:-sha1}"
|
||||
}
|
||||
|
||||
# Detect the hash algorithm in use.
|
||||
test_detect_ref_format () {
|
||||
echo "${GIT_TEST_DEFAULT_REF_FORMAT:-files}"
|
||||
}
|
||||
|
||||
# Load common hash metadata and common placeholder object IDs for use with
|
||||
# test_oid.
|
||||
test_oid_init () {
|
||||
|
|
|
@ -542,6 +542,8 @@ export EDITOR
|
|||
|
||||
GIT_DEFAULT_HASH="${GIT_TEST_DEFAULT_HASH:-sha1}"
|
||||
export GIT_DEFAULT_HASH
|
||||
GIT_DEFAULT_REF_FORMAT="${GIT_TEST_DEFAULT_REF_FORMAT:-files}"
|
||||
export GIT_DEFAULT_REF_FORMAT
|
||||
GIT_TEST_MERGE_ALGORITHM="${GIT_TEST_MERGE_ALGORITHM:-ort}"
|
||||
export GIT_TEST_MERGE_ALGORITHM
|
||||
|
||||
|
@ -1745,7 +1747,14 @@ parisc* | hppa*)
|
|||
;;
|
||||
esac
|
||||
|
||||
test_set_prereq REFFILES
|
||||
case "$GIT_DEFAULT_REF_FORMAT" in
|
||||
files)
|
||||
test_set_prereq REFFILES;;
|
||||
*)
|
||||
echo 2>&1 "error: unknown ref format $GIT_DEFAULT_REF_FORMAT"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
( COLUMNS=1 && test $COLUMNS = 1 ) && test_set_prereq COLUMNS_CAN_BE_1
|
||||
test -z "$NO_CURL" && test_set_prereq LIBCURL
|
||||
|
@ -1936,6 +1945,10 @@ test_lazy_prereq SHA1 '
|
|||
esac
|
||||
'
|
||||
|
||||
test_lazy_prereq DEFAULT_REPO_FORMAT '
|
||||
test_have_prereq SHA1,REFFILES
|
||||
'
|
||||
|
||||
# Ensure that no test accidentally triggers a Git command
|
||||
# that runs the actual maintenance scheduler, affecting a user's
|
||||
# system permanently.
|
||||
|
|
31
worktree.c
31
worktree.c
|
@ -51,7 +51,7 @@ static void add_head_info(struct worktree *wt)
|
|||
/**
|
||||
* get the main worktree
|
||||
*/
|
||||
static struct worktree *get_main_worktree(void)
|
||||
static struct worktree *get_main_worktree(int skip_reading_head)
|
||||
{
|
||||
struct worktree *worktree = NULL;
|
||||
struct strbuf worktree_path = STRBUF_INIT;
|
||||
|
@ -70,11 +70,13 @@ static struct worktree *get_main_worktree(void)
|
|||
*/
|
||||
worktree->is_bare = (is_bare_repository_cfg == 1) ||
|
||||
is_bare_repository();
|
||||
add_head_info(worktree);
|
||||
if (!skip_reading_head)
|
||||
add_head_info(worktree);
|
||||
return worktree;
|
||||
}
|
||||
|
||||
static struct worktree *get_linked_worktree(const char *id)
|
||||
static struct worktree *get_linked_worktree(const char *id,
|
||||
int skip_reading_head)
|
||||
{
|
||||
struct worktree *worktree = NULL;
|
||||
struct strbuf path = STRBUF_INIT;
|
||||
|
@ -93,7 +95,8 @@ static struct worktree *get_linked_worktree(const char *id)
|
|||
CALLOC_ARRAY(worktree, 1);
|
||||
worktree->path = strbuf_detach(&worktree_path, NULL);
|
||||
worktree->id = xstrdup(id);
|
||||
add_head_info(worktree);
|
||||
if (!skip_reading_head)
|
||||
add_head_info(worktree);
|
||||
|
||||
done:
|
||||
strbuf_release(&path);
|
||||
|
@ -118,7 +121,14 @@ static void mark_current_worktree(struct worktree **worktrees)
|
|||
free(git_dir);
|
||||
}
|
||||
|
||||
struct worktree **get_worktrees(void)
|
||||
/*
|
||||
* NEEDSWORK: This function exists so that we can look up metadata of a
|
||||
* worktree without trying to access any of its internals like the refdb. It
|
||||
* would be preferable to instead have a corruption-tolerant function for
|
||||
* retrieving worktree metadata that could be used when the worktree is known
|
||||
* to not be in a healthy state, e.g. when creating or repairing it.
|
||||
*/
|
||||
static struct worktree **get_worktrees_internal(int skip_reading_head)
|
||||
{
|
||||
struct worktree **list = NULL;
|
||||
struct strbuf path = STRBUF_INIT;
|
||||
|
@ -128,7 +138,7 @@ struct worktree **get_worktrees(void)
|
|||
|
||||
ALLOC_ARRAY(list, alloc);
|
||||
|
||||
list[counter++] = get_main_worktree();
|
||||
list[counter++] = get_main_worktree(skip_reading_head);
|
||||
|
||||
strbuf_addf(&path, "%s/worktrees", get_git_common_dir());
|
||||
dir = opendir(path.buf);
|
||||
|
@ -137,7 +147,7 @@ struct worktree **get_worktrees(void)
|
|||
while ((d = readdir_skip_dot_and_dotdot(dir)) != NULL) {
|
||||
struct worktree *linked = NULL;
|
||||
|
||||
if ((linked = get_linked_worktree(d->d_name))) {
|
||||
if ((linked = get_linked_worktree(d->d_name, skip_reading_head))) {
|
||||
ALLOC_GROW(list, counter + 1, alloc);
|
||||
list[counter++] = linked;
|
||||
}
|
||||
|
@ -151,6 +161,11 @@ struct worktree **get_worktrees(void)
|
|||
return list;
|
||||
}
|
||||
|
||||
struct worktree **get_worktrees(void)
|
||||
{
|
||||
return get_worktrees_internal(0);
|
||||
}
|
||||
|
||||
const char *get_worktree_git_dir(const struct worktree *wt)
|
||||
{
|
||||
if (!wt)
|
||||
|
@ -591,7 +606,7 @@ static void repair_noop(int iserr UNUSED,
|
|||
|
||||
void repair_worktrees(worktree_repair_fn fn, void *cb_data)
|
||||
{
|
||||
struct worktree **worktrees = get_worktrees();
|
||||
struct worktree **worktrees = get_worktrees_internal(1);
|
||||
struct worktree **wt = worktrees + 1; /* +1 skips main worktree */
|
||||
|
||||
if (!fn)
|
||||
|
|
Loading…
Reference in New Issue