Merge branch 'ps/refstorage-extension' into ps/worktree-refdb-initialization
* 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 builtin/clone: create the refdb with the correct object format builtin/clone: skip reading HEAD when retrieving remote builtin/clone: set up sparse checkout later builtin/clone: fix bundle URIs with mismatching object formats remote-curl: rediscover repository when fetching refs setup: allow skipping creation of the refdb setup: extract function to create the refdb
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
|
||||
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`::
|
||||
|
||||
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
|
||||
"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).
|
||||
|
||||
@@ -72,6 +72,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;
|
||||
@@ -157,6 +158,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,
|
||||
@@ -932,6 +935,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 =
|
||||
@@ -957,6 +961,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;
|
||||
|
||||
@@ -1101,8 +1111,15 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
|
||||
}
|
||||
}
|
||||
|
||||
init_db(git_dir, real_git_dir, option_template, GIT_HASH_UNKNOWN, NULL,
|
||||
do_not_override_repo_unix_permissions, INIT_DB_QUIET);
|
||||
/*
|
||||
* Initialize the repository, but skip initializing the reference
|
||||
* database. We do not yet know about the object format of the
|
||||
* 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,
|
||||
ref_storage_format, NULL,
|
||||
do_not_override_repo_unix_permissions, INIT_DB_QUIET | INIT_DB_SKIP_REFDB);
|
||||
|
||||
if (real_git_dir) {
|
||||
free((char *)git_dir);
|
||||
@@ -1189,10 +1206,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
|
||||
if (option_required_reference.nr || option_optional_reference.nr)
|
||||
setup_reference();
|
||||
|
||||
if (option_sparse_checkout && git_sparse_checkout_init(dir))
|
||||
return 1;
|
||||
|
||||
remote = remote_get(remote_name);
|
||||
remote = remote_get_early(remote_name);
|
||||
|
||||
refspec_appendf(&remote->fetch, "+%s*:%s*", src_ref_prefix,
|
||||
branch_top.buf);
|
||||
@@ -1270,6 +1284,27 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
|
||||
if (transport->smart_options && !deepen && !filter_options.choice)
|
||||
transport->smart_options->check_self_contained_and_connected = 1;
|
||||
|
||||
strvec_push(&transport_ls_refs_options.ref_prefixes, "HEAD");
|
||||
refspec_ref_prefixes(&remote->fetch,
|
||||
&transport_ls_refs_options.ref_prefixes);
|
||||
if (option_branch)
|
||||
expand_ref_prefix(&transport_ls_refs_options.ref_prefixes,
|
||||
option_branch);
|
||||
if (!option_no_tags)
|
||||
strvec_push(&transport_ls_refs_options.ref_prefixes,
|
||||
"refs/tags/");
|
||||
|
||||
refs = transport_get_remote_refs(transport, &transport_ls_refs_options);
|
||||
|
||||
/*
|
||||
* Now that we know what algorithm the remote side is using, let's set
|
||||
* ours to the same thing.
|
||||
*/
|
||||
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);
|
||||
|
||||
/*
|
||||
* Before fetching from the remote, download and install bundle
|
||||
* data from the --bundle-uri option.
|
||||
@@ -1285,24 +1320,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
|
||||
bundle_uri);
|
||||
else if (has_heuristic)
|
||||
git_config_set_gently("fetch.bundleuri", bundle_uri);
|
||||
}
|
||||
|
||||
strvec_push(&transport_ls_refs_options.ref_prefixes, "HEAD");
|
||||
refspec_ref_prefixes(&remote->fetch,
|
||||
&transport_ls_refs_options.ref_prefixes);
|
||||
if (option_branch)
|
||||
expand_ref_prefix(&transport_ls_refs_options.ref_prefixes,
|
||||
option_branch);
|
||||
if (!option_no_tags)
|
||||
strvec_push(&transport_ls_refs_options.ref_prefixes,
|
||||
"refs/tags/");
|
||||
|
||||
refs = transport_get_remote_refs(transport, &transport_ls_refs_options);
|
||||
|
||||
if (refs)
|
||||
mapped_refs = wanted_peer_refs(refs, &remote->fetch);
|
||||
|
||||
if (!bundle_uri) {
|
||||
} else {
|
||||
/*
|
||||
* Populate transport->got_remote_bundle_uri and
|
||||
* transport->bundle_uri. We might get nothing.
|
||||
@@ -1323,13 +1341,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Now that we know what algorithm the remote side is using,
|
||||
* let's set ours to the same thing.
|
||||
*/
|
||||
hash_algo = hash_algo_by_ptr(transport_get_hash_algo(transport));
|
||||
initialize_repository_version(hash_algo, 1);
|
||||
repo_set_hash_algo(the_repository, hash_algo);
|
||||
if (refs)
|
||||
mapped_refs = wanted_peer_refs(refs, &remote->fetch);
|
||||
|
||||
if (mapped_refs) {
|
||||
/*
|
||||
@@ -1432,6 +1445,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
|
||||
dissociate_from_references();
|
||||
}
|
||||
|
||||
if (option_sparse_checkout && git_sparse_checkout_init(dir))
|
||||
return 1;
|
||||
|
||||
junk_mode = JUNK_LEAVE_REPO;
|
||||
err = checkout(submodule_progress, filter_submodules);
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "object-file.h"
|
||||
#include "parse-options.h"
|
||||
#include "path.h"
|
||||
#include "refs.h"
|
||||
#include "setup.h"
|
||||
#include "strbuf.h"
|
||||
|
||||
@@ -57,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
|
||||
@@ -76,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"),
|
||||
@@ -95,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()
|
||||
};
|
||||
|
||||
@@ -158,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);
|
||||
|
||||
@@ -236,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
|
||||
@@ -2029,12 +2045,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,
|
||||
|
||||
@@ -3241,7 +3241,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,
|
||||
|
||||
@@ -1705,7 +1705,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;
|
||||
|
||||
@@ -1564,8 +1564,11 @@ int cmd_main(int argc, const char **argv)
|
||||
if (buf.len == 0)
|
||||
break;
|
||||
if (starts_with(buf.buf, "fetch ")) {
|
||||
if (nongit)
|
||||
die(_("remote-curl: fetch attempted without a local repo"));
|
||||
if (nongit) {
|
||||
setup_git_directory_gently(&nongit);
|
||||
if (nongit)
|
||||
die(_("remote-curl: fetch attempted without a local repo"));
|
||||
}
|
||||
parse_fetch(&buf);
|
||||
|
||||
} else if (!strcmp(buf.buf, "list") || starts_with(buf.buf, "list ")) {
|
||||
|
||||
26
remote.c
26
remote.c
@@ -509,7 +509,7 @@ static void alias_all_urls(struct remote_state *remote_state)
|
||||
}
|
||||
}
|
||||
|
||||
static void read_config(struct repository *repo)
|
||||
static void read_config(struct repository *repo, int early)
|
||||
{
|
||||
int flag;
|
||||
|
||||
@@ -518,7 +518,7 @@ static void read_config(struct repository *repo)
|
||||
repo->remote_state->initialized = 1;
|
||||
|
||||
repo->remote_state->current_branch = NULL;
|
||||
if (startup_info->have_repository) {
|
||||
if (startup_info->have_repository && !early) {
|
||||
const char *head_ref = refs_resolve_ref_unsafe(
|
||||
get_main_ref_store(repo), "HEAD", 0, NULL, &flag);
|
||||
if (head_ref && (flag & REF_ISSYMREF) &&
|
||||
@@ -561,7 +561,7 @@ static const char *remotes_remote_for_branch(struct remote_state *remote_state,
|
||||
|
||||
const char *remote_for_branch(struct branch *branch, int *explicit)
|
||||
{
|
||||
read_config(the_repository);
|
||||
read_config(the_repository, 0);
|
||||
die_on_missing_branch(the_repository, branch);
|
||||
|
||||
return remotes_remote_for_branch(the_repository->remote_state, branch,
|
||||
@@ -587,7 +587,7 @@ remotes_pushremote_for_branch(struct remote_state *remote_state,
|
||||
|
||||
const char *pushremote_for_branch(struct branch *branch, int *explicit)
|
||||
{
|
||||
read_config(the_repository);
|
||||
read_config(the_repository, 0);
|
||||
die_on_missing_branch(the_repository, branch);
|
||||
|
||||
return remotes_pushremote_for_branch(the_repository->remote_state,
|
||||
@@ -599,7 +599,7 @@ static struct remote *remotes_remote_get(struct remote_state *remote_state,
|
||||
|
||||
const char *remote_ref_for_branch(struct branch *branch, int for_push)
|
||||
{
|
||||
read_config(the_repository);
|
||||
read_config(the_repository, 0);
|
||||
die_on_missing_branch(the_repository, branch);
|
||||
|
||||
if (branch) {
|
||||
@@ -709,7 +709,13 @@ remotes_remote_get(struct remote_state *remote_state, const char *name)
|
||||
|
||||
struct remote *remote_get(const char *name)
|
||||
{
|
||||
read_config(the_repository);
|
||||
read_config(the_repository, 0);
|
||||
return remotes_remote_get(the_repository->remote_state, name);
|
||||
}
|
||||
|
||||
struct remote *remote_get_early(const char *name)
|
||||
{
|
||||
read_config(the_repository, 1);
|
||||
return remotes_remote_get(the_repository->remote_state, name);
|
||||
}
|
||||
|
||||
@@ -722,7 +728,7 @@ remotes_pushremote_get(struct remote_state *remote_state, const char *name)
|
||||
|
||||
struct remote *pushremote_get(const char *name)
|
||||
{
|
||||
read_config(the_repository);
|
||||
read_config(the_repository, 0);
|
||||
return remotes_pushremote_get(the_repository->remote_state, name);
|
||||
}
|
||||
|
||||
@@ -738,7 +744,7 @@ int remote_is_configured(struct remote *remote, int in_repo)
|
||||
int for_each_remote(each_remote_fn fn, void *priv)
|
||||
{
|
||||
int i, result = 0;
|
||||
read_config(the_repository);
|
||||
read_config(the_repository, 0);
|
||||
for (i = 0; i < the_repository->remote_state->remotes_nr && !result;
|
||||
i++) {
|
||||
struct remote *remote =
|
||||
@@ -1831,7 +1837,7 @@ struct branch *branch_get(const char *name)
|
||||
{
|
||||
struct branch *ret;
|
||||
|
||||
read_config(the_repository);
|
||||
read_config(the_repository, 0);
|
||||
if (!name || !*name || !strcmp(name, "HEAD"))
|
||||
ret = the_repository->remote_state->current_branch;
|
||||
else
|
||||
@@ -1973,7 +1979,7 @@ static const char *branch_get_push_1(struct remote_state *remote_state,
|
||||
|
||||
const char *branch_get_push(struct branch *branch, struct strbuf *err)
|
||||
{
|
||||
read_config(the_repository);
|
||||
read_config(the_repository, 0);
|
||||
die_on_missing_branch(the_repository, branch);
|
||||
|
||||
if (!branch)
|
||||
|
||||
1
remote.h
1
remote.h
@@ -118,6 +118,7 @@ struct remote {
|
||||
* and configuration.
|
||||
*/
|
||||
struct remote *remote_get(const char *name);
|
||||
struct remote *remote_get_early(const char *name);
|
||||
|
||||
struct remote *pushremote_get(const char *name);
|
||||
int remote_is_configured(struct remote *remote, int in_repo);
|
||||
|
||||
@@ -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);
|
||||
|
||||
176
setup.c
176
setup.c
@@ -592,6 +592,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;
|
||||
}
|
||||
@@ -1566,6 +1577,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 */
|
||||
@@ -1659,6 +1672,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 =
|
||||
@@ -1867,12 +1882,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 */
|
||||
@@ -1885,23 +1903,87 @@ 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)
|
||||
{
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
char junk[2];
|
||||
int ret;
|
||||
|
||||
git_path_buf(&buf, "HEAD");
|
||||
ret = !access(buf.buf, R_OK) || readlink(buf.buf, junk, sizeof(junk) - 1) != -1;
|
||||
strbuf_release(&buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void create_reference_database(unsigned int ref_storage_format,
|
||||
const char *initial_branch, int quiet)
|
||||
{
|
||||
struct strbuf err = STRBUF_INIT;
|
||||
int reinit = is_reinit();
|
||||
|
||||
/*
|
||||
* We need to create a "refs" dir in any case so that older versions of
|
||||
* Git can tell that this is a repository. This serves two main purposes:
|
||||
*
|
||||
* - Clients will know to stop walking the parent-directory chain when
|
||||
* detecting the Git repository. Otherwise they may end up detecting
|
||||
* a Git repository in a parent directory instead.
|
||||
*
|
||||
* - Instead of failing to detect a repository with unknown reference
|
||||
* format altogether, old clients will print an error saying that
|
||||
* they do not understand the reference format extension.
|
||||
*/
|
||||
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);
|
||||
|
||||
/*
|
||||
* Point the HEAD symref to the initial branch with if HEAD does
|
||||
* not yet exist.
|
||||
*/
|
||||
if (!reinit) {
|
||||
char *ref;
|
||||
|
||||
if (!initial_branch)
|
||||
initial_branch = git_default_branch_name(quiet);
|
||||
|
||||
ref = xstrfmt("refs/heads/%s", initial_branch);
|
||||
if (check_refname_format(ref, 0) < 0)
|
||||
die(_("invalid initial branch name: '%s'"),
|
||||
initial_branch);
|
||||
|
||||
if (create_symref("HEAD", ref, NULL) < 0)
|
||||
exit(1);
|
||||
free(ref);
|
||||
}
|
||||
|
||||
if (reinit && initial_branch)
|
||||
warning(_("re-init: ignored --initial-branch=%s"),
|
||||
initial_branch);
|
||||
|
||||
strbuf_release(&err);
|
||||
}
|
||||
|
||||
static int create_default_files(const char *template_path,
|
||||
const char *original_git_dir,
|
||||
const char *initial_branch,
|
||||
const struct repository_format *fmt,
|
||||
int prev_bare_repository,
|
||||
int init_shared_repository,
|
||||
int quiet)
|
||||
int init_shared_repository)
|
||||
{
|
||||
struct stat st1;
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
char *path;
|
||||
char junk[2];
|
||||
int reinit;
|
||||
int filemode;
|
||||
struct strbuf err = STRBUF_INIT;
|
||||
const char *init_template_dir = NULL;
|
||||
const char *work_tree = get_git_work_tree();
|
||||
|
||||
@@ -1921,6 +2003,8 @@ static int create_default_files(const char *template_path,
|
||||
reset_shared_repository();
|
||||
git_config(git_default_config, NULL);
|
||||
|
||||
reinit = is_reinit();
|
||||
|
||||
/*
|
||||
* We must make sure command-line options continue to override any
|
||||
* values we might have just re-read from the config.
|
||||
@@ -1964,40 +2048,7 @@ static int create_default_files(const char *template_path,
|
||||
adjust_shared_perm(get_git_dir());
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to create a "refs" dir in any case so that older
|
||||
* versions of git can tell that this is a repository.
|
||||
*/
|
||||
safe_create_dir(git_path("refs"), 1);
|
||||
adjust_shared_perm(git_path("refs"));
|
||||
|
||||
if (refs_init_db(&err))
|
||||
die("failed to set up refs db: %s", err.buf);
|
||||
|
||||
/*
|
||||
* Point the HEAD symref to the initial branch with if HEAD does
|
||||
* not yet exist.
|
||||
*/
|
||||
path = git_path_buf(&buf, "HEAD");
|
||||
reinit = (!access(path, R_OK)
|
||||
|| readlink(path, junk, sizeof(junk)-1) != -1);
|
||||
if (!reinit) {
|
||||
char *ref;
|
||||
|
||||
if (!initial_branch)
|
||||
initial_branch = git_default_branch_name(quiet);
|
||||
|
||||
ref = xstrfmt("refs/heads/%s", initial_branch);
|
||||
if (check_refname_format(ref, 0) < 0)
|
||||
die(_("invalid initial branch name: '%s'"),
|
||||
initial_branch);
|
||||
|
||||
if (create_symref("HEAD", ref, NULL) < 0)
|
||||
exit(1);
|
||||
free(ref);
|
||||
}
|
||||
|
||||
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");
|
||||
@@ -2110,8 +2161,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;
|
||||
@@ -2154,16 +2226,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,
|
||||
initial_branch, &repo_fmt,
|
||||
prev_bare_repository,
|
||||
init_shared_repository,
|
||||
flags & INIT_DB_QUIET);
|
||||
if (reinit && initial_branch)
|
||||
warning(_("re-init: ignored --initial-branch=%s"),
|
||||
initial_branch);
|
||||
&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(repo_fmt.ref_storage_format,
|
||||
initial_branch, flags & INIT_DB_QUIET);
|
||||
create_object_directory();
|
||||
|
||||
if (get_shared_repository()) {
|
||||
|
||||
14
setup.h
14
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, \
|
||||
}
|
||||
@@ -169,14 +171,20 @@ int verify_repository_format(const struct repository_format *format,
|
||||
*/
|
||||
void check_repository_format(struct repository_format *fmt);
|
||||
|
||||
#define INIT_DB_QUIET 0x0001
|
||||
#define INIT_DB_EXIST_OK 0x0002
|
||||
#define INIT_DB_QUIET (1 << 0)
|
||||
#define INIT_DB_EXIST_OK (1 << 1)
|
||||
#define INIT_DB_SKIP_REFDB (1 << 2)
|
||||
|
||||
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 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
|
||||
'
|
||||
|
||||
@@ -66,11 +66,11 @@ test_expect_success 'create empty remote repository' '
|
||||
setup_post_update_server_info_hook "$HTTPD_DOCUMENT_ROOT_PATH/empty.git"
|
||||
'
|
||||
|
||||
test_expect_success 'empty dumb HTTP repository has default hash algorithm' '
|
||||
test_expect_success 'empty dumb HTTP repository falls back to SHA1' '
|
||||
test_when_finished "rm -fr clone-empty" &&
|
||||
git clone $HTTPD_URL/dumb/empty.git clone-empty &&
|
||||
git -C clone-empty rev-parse --show-object-format >empty-format &&
|
||||
test "$(cat empty-format)" = "$(test_oid algo)"
|
||||
test "$(cat empty-format)" = sha1
|
||||
'
|
||||
|
||||
setup_askpass_helper
|
||||
|
||||
@@ -33,6 +33,15 @@ test_expect_success 'clone with path bundle' '
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'clone with path bundle and non-default hash' '
|
||||
test_when_finished "rm -rf clone-path-non-default-hash" &&
|
||||
GIT_DEFAULT_HASH=sha256 git clone --bundle-uri="clone-from/B.bundle" \
|
||||
clone-from clone-path-non-default-hash &&
|
||||
git -C clone-path-non-default-hash rev-parse refs/bundles/topic >actual &&
|
||||
git -C clone-from rev-parse topic >expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'clone with file:// bundle' '
|
||||
git clone --bundle-uri="file://$(pwd)/clone-from/B.bundle" \
|
||||
clone-from clone-file &&
|
||||
@@ -284,6 +293,15 @@ test_expect_success 'clone HTTP bundle' '
|
||||
test_config -C clone-http log.excludedecoration refs/bundle/
|
||||
'
|
||||
|
||||
test_expect_success 'clone HTTP bundle with non-default hash' '
|
||||
test_when_finished "rm -rf clone-http-non-default-hash" &&
|
||||
GIT_DEFAULT_HASH=sha256 git clone --bundle-uri="$HTTPD_URL/B.bundle" \
|
||||
"$HTTPD_URL/smart/fetch.git" clone-http-non-default-hash &&
|
||||
git -C clone-http-non-default-hash rev-parse refs/bundles/topic >actual &&
|
||||
git -C clone-from rev-parse topic >expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'clone bundle list (HTTP, no heuristic)' '
|
||||
test_when_finished rm -f trace*.txt &&
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user