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:
@@ -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
|
linkgit:git-clone[1]. Trying to change it after initialization will not
|
||||||
work and will produce hard-to-diagnose issues.
|
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::
|
extensions.worktreeConfig::
|
||||||
If enabled, then worktrees will load config settings from the
|
If enabled, then worktrees will load config settings from the
|
||||||
`$GIT_DIR/config.worktree` file in addition to 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
|
The result is Git repository can be separated from working
|
||||||
tree.
|
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>::
|
-j <n>::
|
||||||
--jobs <n>::
|
--jobs <n>::
|
||||||
The number of submodules fetched at the same time.
|
The number of submodules fetched at the same time.
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ SYNOPSIS
|
|||||||
[verse]
|
[verse]
|
||||||
'git init' [-q | --quiet] [--bare] [--template=<template-directory>]
|
'git init' [-q | --quiet] [--bare] [--template=<template-directory>]
|
||||||
[--separate-git-dir <git-dir>] [--object-format=<format>]
|
[--separate-git-dir <git-dir>] [--object-format=<format>]
|
||||||
|
[--ref-format=<format>]
|
||||||
[-b <branch-name> | --initial-branch=<branch-name>]
|
[-b <branch-name> | --initial-branch=<branch-name>]
|
||||||
[--shared[=<permissions>]] [<directory>]
|
[--shared[=<permissions>]] [<directory>]
|
||||||
|
|
||||||
@@ -57,6 +58,12 @@ values are 'sha1' and (if enabled) 'sha256'. 'sha1' is the default.
|
|||||||
+
|
+
|
||||||
include::object-format-disclaimer.txt[]
|
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>::
|
--template=<template-directory>::
|
||||||
|
|
||||||
Specify the directory from which templates will be used. (See the "TEMPLATE
|
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.
|
input, multiple algorithms may be printed, space-separated.
|
||||||
If not specified, the default is "storage".
|
If not specified, the default is "storage".
|
||||||
|
|
||||||
|
--show-ref-format::
|
||||||
|
Show the reference storage format used for the repository.
|
||||||
|
|
||||||
|
|
||||||
Other Options
|
Other Options
|
||||||
~~~~~~~~~~~~~
|
~~~~~~~~~~~~~
|
||||||
|
|||||||
@@ -556,6 +556,11 @@ double-quotes and respecting backslash escapes. E.g., the value
|
|||||||
is always used. The default is "sha1".
|
is always used. The default is "sha1".
|
||||||
See `--object-format` in linkgit:git-init[1].
|
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 Commits
|
||||||
~~~~~~~~~~~
|
~~~~~~~~~~~
|
||||||
`GIT_AUTHOR_NAME`::
|
`GIT_AUTHOR_NAME`::
|
||||||
|
|||||||
1
Documentation/ref-storage-format.txt
Normal file
1
Documentation/ref-storage-format.txt
Normal file
@@ -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
|
multiple working directory mode, "config" file is shared while
|
||||||
"config.worktree" is per-working directory (i.e., it's in
|
"config.worktree" is per-working directory (i.e., it's in
|
||||||
GIT_COMMON_DIR/worktrees/<id>/config.worktree)
|
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 char *option_branch = NULL;
|
||||||
static struct string_list option_not = STRING_LIST_INIT_NODUP;
|
static struct string_list option_not = STRING_LIST_INIT_NODUP;
|
||||||
static const char *real_git_dir;
|
static const char *real_git_dir;
|
||||||
|
static const char *ref_format;
|
||||||
static char *option_upload_pack = "git-upload-pack";
|
static char *option_upload_pack = "git-upload-pack";
|
||||||
static int option_verbosity;
|
static int option_verbosity;
|
||||||
static int option_progress = -1;
|
static int option_progress = -1;
|
||||||
@@ -156,6 +157,8 @@ static struct option builtin_clone_options[] = {
|
|||||||
N_("any cloned submodules will be shallow")),
|
N_("any cloned submodules will be shallow")),
|
||||||
OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"),
|
OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"),
|
||||||
N_("separate git dir from working tree")),
|
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"),
|
OPT_STRING_LIST('c', "config", &option_config, N_("key=value"),
|
||||||
N_("set config inside the new repository")),
|
N_("set config inside the new repository")),
|
||||||
OPT_STRING_LIST(0, "server-option", &server_options,
|
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 submodule_progress;
|
||||||
int filter_submodules = 0;
|
int filter_submodules = 0;
|
||||||
int hash_algo;
|
int hash_algo;
|
||||||
|
unsigned int ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN;
|
||||||
const int do_not_override_repo_unix_permissions = -1;
|
const int do_not_override_repo_unix_permissions = -1;
|
||||||
|
|
||||||
struct transport_ls_refs_options transport_ls_refs_options =
|
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)
|
if (option_single_branch == -1)
|
||||||
option_single_branch = deepen ? 1 : 0;
|
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)
|
if (option_mirror)
|
||||||
option_bare = 1;
|
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
|
* repository, and reference backends may persist that information into
|
||||||
* their on-disk data structures.
|
* 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);
|
do_not_override_repo_unix_permissions, INIT_DB_QUIET | INIT_DB_SKIP_REFDB);
|
||||||
|
|
||||||
if (real_git_dir) {
|
if (real_git_dir) {
|
||||||
@@ -1289,9 +1300,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
|
|||||||
* ours to the same thing.
|
* ours to the same thing.
|
||||||
*/
|
*/
|
||||||
hash_algo = hash_algo_by_ptr(transport_get_hash_algo(transport));
|
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);
|
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
|
* Before fetching from the remote, download and install bundle
|
||||||
|
|||||||
@@ -10,6 +10,8 @@
|
|||||||
#include "object-file.h"
|
#include "object-file.h"
|
||||||
#include "parse-options.h"
|
#include "parse-options.h"
|
||||||
#include "path.h"
|
#include "path.h"
|
||||||
|
#include "refs.h"
|
||||||
|
#include "repository.h"
|
||||||
#include "setup.h"
|
#include "setup.h"
|
||||||
#include "strbuf.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[] = {
|
static const char *const init_db_usage[] = {
|
||||||
N_("git init [-q | --quiet] [--bare] [--template=<template-directory>]\n"
|
N_("git init [-q | --quiet] [--bare] [--template=<template-directory>]\n"
|
||||||
" [--separate-git-dir <git-dir>] [--object-format=<format>]\n"
|
" [--separate-git-dir <git-dir>] [--object-format=<format>]\n"
|
||||||
|
" [--ref-format=<format>]\n"
|
||||||
" [-b <branch-name> | --initial-branch=<branch-name>]\n"
|
" [-b <branch-name> | --initial-branch=<branch-name>]\n"
|
||||||
" [--shared[=<permissions>]] [<directory>]"),
|
" [--shared[=<permissions>]] [<directory>]"),
|
||||||
NULL
|
NULL
|
||||||
@@ -75,8 +78,10 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
|
|||||||
const char *template_dir = NULL;
|
const char *template_dir = NULL;
|
||||||
unsigned int flags = 0;
|
unsigned int flags = 0;
|
||||||
const char *object_format = NULL;
|
const char *object_format = NULL;
|
||||||
|
const char *ref_format = NULL;
|
||||||
const char *initial_branch = NULL;
|
const char *initial_branch = NULL;
|
||||||
int hash_algo = GIT_HASH_UNKNOWN;
|
int hash_algo = GIT_HASH_UNKNOWN;
|
||||||
|
unsigned int ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN;
|
||||||
int init_shared_repository = -1;
|
int init_shared_repository = -1;
|
||||||
const struct option init_db_options[] = {
|
const struct option init_db_options[] = {
|
||||||
OPT_STRING(0, "template", &template_dir, N_("template-directory"),
|
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")),
|
N_("override the name of the initial branch")),
|
||||||
OPT_STRING(0, "object-format", &object_format, N_("hash"),
|
OPT_STRING(0, "object-format", &object_format, N_("hash"),
|
||||||
N_("specify the hash algorithm to use")),
|
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()
|
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);
|
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)
|
if (init_shared_repository != -1)
|
||||||
set_shared_repository(init_shared_repository);
|
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;
|
flags |= INIT_DB_EXIST_OK;
|
||||||
return init_db(git_dir, real_git_dir, template_dir, hash_algo,
|
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);
|
puts(the_hash_algo->name);
|
||||||
continue;
|
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")) {
|
if (!strcmp(arg, "--end-of-options")) {
|
||||||
seen_end_of_options = 1;
|
seen_end_of_options = 1;
|
||||||
if (filter & (DO_FLAGS | DO_REVS))
|
if (filter & (DO_FLAGS | DO_REVS))
|
||||||
|
|||||||
34
refs.c
34
refs.c
@@ -33,17 +33,33 @@
|
|||||||
/*
|
/*
|
||||||
* List of all available backends
|
* 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;
|
if (ref_storage_format < ARRAY_SIZE(refs_backends))
|
||||||
for (be = refs_backends; be; be = be->next)
|
return refs_backends[ref_storage_format];
|
||||||
if (!strcmp(be->name, name))
|
|
||||||
return be;
|
|
||||||
return NULL;
|
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:
|
* How to handle various characters in refnames:
|
||||||
* 0: An acceptable character for refs
|
* 0: An acceptable character for refs
|
||||||
@@ -2082,12 +2098,12 @@ static struct ref_store *ref_store_init(struct repository *repo,
|
|||||||
const char *gitdir,
|
const char *gitdir,
|
||||||
unsigned int flags)
|
unsigned int flags)
|
||||||
{
|
{
|
||||||
const char *be_name = "files";
|
const struct ref_storage_be *be;
|
||||||
struct ref_storage_be *be = find_ref_storage_backend(be_name);
|
|
||||||
struct ref_store *refs;
|
struct ref_store *refs;
|
||||||
|
|
||||||
|
be = find_ref_storage_backend(repo->ref_storage_format);
|
||||||
if (!be)
|
if (!be)
|
||||||
BUG("reference backend %s is unknown", be_name);
|
BUG("reference backend is unknown");
|
||||||
|
|
||||||
refs = be->init(repo, gitdir, flags);
|
refs = be->init(repo, gitdir, flags);
|
||||||
return refs;
|
return refs;
|
||||||
|
|||||||
3
refs.h
3
refs.h
@@ -11,6 +11,9 @@ struct string_list;
|
|||||||
struct string_list_item;
|
struct string_list_item;
|
||||||
struct worktree;
|
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.
|
* 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 = {
|
struct ref_storage_be refs_be_debug = {
|
||||||
.next = NULL,
|
|
||||||
.name = "debug",
|
.name = "debug",
|
||||||
.init = NULL,
|
.init = NULL,
|
||||||
.init_db = debug_init_db,
|
.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 = {
|
struct ref_storage_be refs_be_files = {
|
||||||
.next = NULL,
|
|
||||||
.name = "files",
|
.name = "files",
|
||||||
.init = files_ref_store_create,
|
.init = files_ref_store_create,
|
||||||
.init_db = files_init_db,
|
.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 = {
|
struct ref_storage_be refs_be_packed = {
|
||||||
.next = NULL,
|
|
||||||
.name = "packed",
|
.name = "packed",
|
||||||
.init = packed_ref_store_create,
|
.init = packed_ref_store_create,
|
||||||
.init_db = packed_init_db,
|
.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 strbuf *referent);
|
||||||
|
|
||||||
struct ref_storage_be {
|
struct ref_storage_be {
|
||||||
struct ref_storage_be *next;
|
|
||||||
const char *name;
|
const char *name;
|
||||||
ref_store_init_fn *init;
|
ref_store_init_fn *init;
|
||||||
ref_init_db_fn *init_db;
|
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];
|
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'.
|
* Attempt to resolve and set the provided 'gitdir' for repository 'repo'.
|
||||||
* Return 0 upon success and a non-zero value upon failure.
|
* Return 0 upon success and a non-zero value upon failure.
|
||||||
@@ -184,6 +189,7 @@ int repo_init(struct repository *repo,
|
|||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
repo_set_hash_algo(repo, format.hash_algo);
|
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;
|
repo->repository_format_worktree_config = format.worktree_config;
|
||||||
|
|
||||||
/* take ownership of format.partial_clone */
|
/* take ownership of format.partial_clone */
|
||||||
|
|||||||
@@ -24,6 +24,9 @@ enum fetch_negotiation_setting {
|
|||||||
FETCH_NEGOTIATION_NOOP,
|
FETCH_NEGOTIATION_NOOP,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define REF_STORAGE_FORMAT_UNKNOWN 0
|
||||||
|
#define REF_STORAGE_FORMAT_FILES 1
|
||||||
|
|
||||||
struct repo_settings {
|
struct repo_settings {
|
||||||
int initialized;
|
int initialized;
|
||||||
|
|
||||||
@@ -160,6 +163,9 @@ struct repository {
|
|||||||
/* Repository's current hash algorithm, as serialized on disk. */
|
/* Repository's current hash algorithm, as serialized on disk. */
|
||||||
const struct git_hash_algo *hash_algo;
|
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. */
|
/* A unique-id for tracing purposes. */
|
||||||
int trace2_repo_id;
|
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);
|
const struct set_gitdir_args *extra_args);
|
||||||
void repo_set_worktree(struct repository *repo, const char *path);
|
void repo_set_worktree(struct repository *repo, const char *path);
|
||||||
void repo_set_hash_algo(struct repository *repo, int algo);
|
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);
|
void initialize_the_repository(void);
|
||||||
RESULT_MUST_BE_USED
|
RESULT_MUST_BE_USED
|
||||||
int repo_init(struct repository *r, const char *gitdir, const char *worktree);
|
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);
|
"extensions.objectformat", value);
|
||||||
data->hash_algo = format;
|
data->hash_algo = format;
|
||||||
return EXTENSION_OK;
|
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;
|
return EXTENSION_UNKNOWN;
|
||||||
}
|
}
|
||||||
@@ -1565,6 +1576,8 @@ const char *setup_git_directory_gently(int *nongit_ok)
|
|||||||
}
|
}
|
||||||
if (startup_info->have_repository) {
|
if (startup_info->have_repository) {
|
||||||
repo_set_hash_algo(the_repository, repo_fmt.hash_algo);
|
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 =
|
the_repository->repository_format_worktree_config =
|
||||||
repo_fmt.worktree_config;
|
repo_fmt.worktree_config;
|
||||||
/* take ownership of repo_fmt.partial_clone */
|
/* 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);
|
check_repository_format_gently(get_git_dir(), fmt, NULL);
|
||||||
startup_info->have_repository = 1;
|
startup_info->have_repository = 1;
|
||||||
repo_set_hash_algo(the_repository, fmt->hash_algo);
|
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 =
|
the_repository->repository_format_worktree_config =
|
||||||
fmt->worktree_config;
|
fmt->worktree_config;
|
||||||
the_repository->repository_format_partial_clone =
|
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;
|
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];
|
char repo_version_string[10];
|
||||||
int repo_version = GIT_REPO_VERSION;
|
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;
|
repo_version = GIT_REPO_VERSION_READ;
|
||||||
|
|
||||||
/* This forces creation of new config file */
|
/* 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);
|
hash_algos[hash_algo].name);
|
||||||
else if (reinit)
|
else if (reinit)
|
||||||
git_config_set_gently("extensions.objectformat", NULL);
|
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)
|
static int is_reinit(void)
|
||||||
@@ -1898,7 +1920,8 @@ static int is_reinit(void)
|
|||||||
return ret;
|
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;
|
struct strbuf err = STRBUF_INIT;
|
||||||
int reinit = is_reinit();
|
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);
|
safe_create_dir(git_path("refs"), 1);
|
||||||
adjust_shared_perm(git_path("refs"));
|
adjust_shared_perm(git_path("refs"));
|
||||||
|
|
||||||
|
repo_set_ref_storage_format(the_repository, ref_storage_format);
|
||||||
if (refs_init_db(&err))
|
if (refs_init_db(&err))
|
||||||
die("failed to set up refs db: %s", err.buf);
|
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());
|
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 */
|
/* Check filemode trustability */
|
||||||
path = git_path_buf(&buf, "config");
|
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,
|
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 init_shared_repository, unsigned int flags)
|
||||||
{
|
{
|
||||||
int reinit;
|
int reinit;
|
||||||
@@ -2180,13 +2225,22 @@ int init_db(const char *git_dir, const char *real_git_dir,
|
|||||||
check_repository_format(&repo_fmt);
|
check_repository_format(&repo_fmt);
|
||||||
|
|
||||||
validate_hash_algorithm(&repo_fmt, hash);
|
validate_hash_algorithm(&repo_fmt, hash);
|
||||||
|
validate_ref_storage_format(&repo_fmt, ref_storage_format);
|
||||||
|
|
||||||
reinit = create_default_files(template_dir, original_git_dir,
|
reinit = create_default_files(template_dir, original_git_dir,
|
||||||
&repo_fmt, prev_bare_repository,
|
&repo_fmt, prev_bare_repository,
|
||||||
init_shared_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))
|
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();
|
create_object_directory();
|
||||||
|
|
||||||
if (get_shared_repository()) {
|
if (get_shared_repository()) {
|
||||||
|
|||||||
10
setup.h
10
setup.h
@@ -115,6 +115,7 @@ struct repository_format {
|
|||||||
int worktree_config;
|
int worktree_config;
|
||||||
int is_bare;
|
int is_bare;
|
||||||
int hash_algo;
|
int hash_algo;
|
||||||
|
unsigned int ref_storage_format;
|
||||||
int sparse_index;
|
int sparse_index;
|
||||||
char *work_tree;
|
char *work_tree;
|
||||||
struct string_list unknown_extensions;
|
struct string_list unknown_extensions;
|
||||||
@@ -131,6 +132,7 @@ struct repository_format {
|
|||||||
.version = -1, \
|
.version = -1, \
|
||||||
.is_bare = -1, \
|
.is_bare = -1, \
|
||||||
.hash_algo = GIT_HASH_SHA1, \
|
.hash_algo = GIT_HASH_SHA1, \
|
||||||
|
.ref_storage_format = REF_STORAGE_FORMAT_FILES, \
|
||||||
.unknown_extensions = STRING_LIST_INIT_DUP, \
|
.unknown_extensions = STRING_LIST_INIT_DUP, \
|
||||||
.v1_only_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,
|
int init_db(const char *git_dir, const char *real_git_dir,
|
||||||
const char *template_dir, int hash_algo,
|
const char *template_dir, int hash_algo,
|
||||||
|
unsigned int ref_storage_format,
|
||||||
const char *initial_branch, int init_shared_repository,
|
const char *initial_branch, int init_shared_repository,
|
||||||
unsigned int flags);
|
unsigned int flags);
|
||||||
void initialize_repository_version(int hash_algo, int reinit);
|
void initialize_repository_version(int hash_algo,
|
||||||
void create_reference_database(const char *initial_branch, int quiet);
|
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!!
|
* 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"
|
use in the test scripts. Recognized values for <hash-algo> are "sha1"
|
||||||
and "sha256".
|
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
|
GIT_TEST_NO_WRITE_REV_INDEX=<boolean>, when true disables the
|
||||||
'pack.writeReverseIndex' setting.
|
'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_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' '
|
test_expect_success MINGW 'core.hidedotfiles = false' '
|
||||||
git config --global core.hidedotfiles false &&
|
git config --global core.hidedotfiles false &&
|
||||||
rm -rf newdir &&
|
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
|
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' '
|
test_expect_success '--show-toplevel from subdir of working tree' '
|
||||||
pwd >expect &&
|
pwd >expect &&
|
||||||
git -C sub/dir rev-parse --show-toplevel >actual &&
|
git -C sub/dir rev-parse --show-toplevel >actual &&
|
||||||
|
|||||||
@@ -519,7 +519,7 @@ EOF
|
|||||||
|
|
||||||
mv .git/config .git/config-saved
|
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 q q2 &&
|
||||||
git branch -m q2 q
|
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 /' '
|
test_expect_success 'clone to destination with trailing /' '
|
||||||
|
|
||||||
git clone src target-1/ &&
|
git clone src target-1/ &&
|
||||||
|
|||||||
@@ -627,6 +627,7 @@ test_expect_success \
|
|||||||
test_expect_success 'setup' '
|
test_expect_success 'setup' '
|
||||||
version=$(git config core.repositoryformatversion) &&
|
version=$(git config core.repositoryformatversion) &&
|
||||||
algo=$(test_might_fail git config extensions.objectformat) &&
|
algo=$(test_might_fail git config extensions.objectformat) &&
|
||||||
|
refstorage=$(test_might_fail git config extensions.refstorage) &&
|
||||||
cat >.git/config <<-\EOF &&
|
cat >.git/config <<-\EOF &&
|
||||||
# testing noval and alternate separator
|
# testing noval and alternate separator
|
||||||
[gitweb]
|
[gitweb]
|
||||||
@@ -637,6 +638,10 @@ test_expect_success 'setup' '
|
|||||||
if test -n "$algo"
|
if test -n "$algo"
|
||||||
then
|
then
|
||||||
git config extensions.objectformat "$algo"
|
git config extensions.objectformat "$algo"
|
||||||
|
fi &&
|
||||||
|
if test -n "$refstorage"
|
||||||
|
then
|
||||||
|
git config extensions.refstorage "$refstorage"
|
||||||
fi
|
fi
|
||||||
'
|
'
|
||||||
|
|
||||||
|
|||||||
@@ -1659,6 +1659,11 @@ test_detect_hash () {
|
|||||||
test_hash_algo="${GIT_TEST_DEFAULT_HASH:-sha1}"
|
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
|
# Load common hash metadata and common placeholder object IDs for use with
|
||||||
# test_oid.
|
# test_oid.
|
||||||
test_oid_init () {
|
test_oid_init () {
|
||||||
|
|||||||
@@ -542,6 +542,8 @@ export EDITOR
|
|||||||
|
|
||||||
GIT_DEFAULT_HASH="${GIT_TEST_DEFAULT_HASH:-sha1}"
|
GIT_DEFAULT_HASH="${GIT_TEST_DEFAULT_HASH:-sha1}"
|
||||||
export GIT_DEFAULT_HASH
|
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}"
|
GIT_TEST_MERGE_ALGORITHM="${GIT_TEST_MERGE_ALGORITHM:-ort}"
|
||||||
export GIT_TEST_MERGE_ALGORITHM
|
export GIT_TEST_MERGE_ALGORITHM
|
||||||
|
|
||||||
@@ -1745,7 +1747,14 @@ parisc* | hppa*)
|
|||||||
;;
|
;;
|
||||||
esac
|
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
|
( COLUMNS=1 && test $COLUMNS = 1 ) && test_set_prereq COLUMNS_CAN_BE_1
|
||||||
test -z "$NO_CURL" && test_set_prereq LIBCURL
|
test -z "$NO_CURL" && test_set_prereq LIBCURL
|
||||||
@@ -1936,6 +1945,10 @@ test_lazy_prereq SHA1 '
|
|||||||
esac
|
esac
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_lazy_prereq DEFAULT_REPO_FORMAT '
|
||||||
|
test_have_prereq SHA1,REFFILES
|
||||||
|
'
|
||||||
|
|
||||||
# Ensure that no test accidentally triggers a Git command
|
# Ensure that no test accidentally triggers a Git command
|
||||||
# that runs the actual maintenance scheduler, affecting a user's
|
# that runs the actual maintenance scheduler, affecting a user's
|
||||||
# system permanently.
|
# system permanently.
|
||||||
|
|||||||
31
worktree.c
31
worktree.c
@@ -51,7 +51,7 @@ static void add_head_info(struct worktree *wt)
|
|||||||
/**
|
/**
|
||||||
* get the main worktree
|
* 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 worktree *worktree = NULL;
|
||||||
struct strbuf worktree_path = STRBUF_INIT;
|
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) ||
|
worktree->is_bare = (is_bare_repository_cfg == 1) ||
|
||||||
is_bare_repository();
|
is_bare_repository();
|
||||||
add_head_info(worktree);
|
if (!skip_reading_head)
|
||||||
|
add_head_info(worktree);
|
||||||
return 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 worktree *worktree = NULL;
|
||||||
struct strbuf path = STRBUF_INIT;
|
struct strbuf path = STRBUF_INIT;
|
||||||
@@ -93,7 +95,8 @@ static struct worktree *get_linked_worktree(const char *id)
|
|||||||
CALLOC_ARRAY(worktree, 1);
|
CALLOC_ARRAY(worktree, 1);
|
||||||
worktree->path = strbuf_detach(&worktree_path, NULL);
|
worktree->path = strbuf_detach(&worktree_path, NULL);
|
||||||
worktree->id = xstrdup(id);
|
worktree->id = xstrdup(id);
|
||||||
add_head_info(worktree);
|
if (!skip_reading_head)
|
||||||
|
add_head_info(worktree);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
strbuf_release(&path);
|
strbuf_release(&path);
|
||||||
@@ -118,7 +121,14 @@ static void mark_current_worktree(struct worktree **worktrees)
|
|||||||
free(git_dir);
|
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 worktree **list = NULL;
|
||||||
struct strbuf path = STRBUF_INIT;
|
struct strbuf path = STRBUF_INIT;
|
||||||
@@ -128,7 +138,7 @@ struct worktree **get_worktrees(void)
|
|||||||
|
|
||||||
ALLOC_ARRAY(list, alloc);
|
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());
|
strbuf_addf(&path, "%s/worktrees", get_git_common_dir());
|
||||||
dir = opendir(path.buf);
|
dir = opendir(path.buf);
|
||||||
@@ -137,7 +147,7 @@ struct worktree **get_worktrees(void)
|
|||||||
while ((d = readdir_skip_dot_and_dotdot(dir)) != NULL) {
|
while ((d = readdir_skip_dot_and_dotdot(dir)) != NULL) {
|
||||||
struct worktree *linked = 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);
|
ALLOC_GROW(list, counter + 1, alloc);
|
||||||
list[counter++] = linked;
|
list[counter++] = linked;
|
||||||
}
|
}
|
||||||
@@ -151,6 +161,11 @@ struct worktree **get_worktrees(void)
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct worktree **get_worktrees(void)
|
||||||
|
{
|
||||||
|
return get_worktrees_internal(0);
|
||||||
|
}
|
||||||
|
|
||||||
const char *get_worktree_git_dir(const struct worktree *wt)
|
const char *get_worktree_git_dir(const struct worktree *wt)
|
||||||
{
|
{
|
||||||
if (!wt)
|
if (!wt)
|
||||||
@@ -591,7 +606,7 @@ static void repair_noop(int iserr UNUSED,
|
|||||||
|
|
||||||
void repair_worktrees(worktree_repair_fn fn, void *cb_data)
|
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 */
|
struct worktree **wt = worktrees + 1; /* +1 skips main worktree */
|
||||||
|
|
||||||
if (!fn)
|
if (!fn)
|
||||||
|
|||||||
Reference in New Issue
Block a user