Skip to content

Commit

Permalink
Merge branch 'ps/clone-into-reftable-repository'
Browse files Browse the repository at this point in the history
"git clone" has been prepared to allow cloning a repository with
non-default hash function into a repository that uses the reftable
backend.

* ps/clone-into-reftable-repository:
  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
  • Loading branch information
gitster committed Dec 27, 2023
2 parents 6db745e + 18c9cb7 commit 94e8e40
Show file tree
Hide file tree
Showing 8 changed files with 150 additions and 91 deletions.
65 changes: 35 additions & 30 deletions builtin/clone.c
Original file line number Diff line number Diff line change
Expand Up @@ -1101,8 +1101,14 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
}
}

/*
* 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, NULL,
do_not_override_repo_unix_permissions, INIT_DB_QUIET);
do_not_override_repo_unix_permissions, INIT_DB_QUIET | INIT_DB_SKIP_REFDB);

if (real_git_dir) {
free((char *)git_dir);
Expand Down Expand Up @@ -1189,10 +1195,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);
Expand Down Expand Up @@ -1270,6 +1273,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, 1);
repo_set_hash_algo(the_repository, hash_algo);
create_reference_database(NULL, 1);

/*
* Before fetching from the remote, download and install bundle
* data from the --bundle-uri option.
Expand All @@ -1285,24 +1309,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.
Expand All @@ -1323,13 +1330,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) {
/*
Expand Down Expand Up @@ -1432,6 +1434,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);

Expand Down
7 changes: 5 additions & 2 deletions remote-curl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 ")) {
Expand Down
26 changes: 16 additions & 10 deletions remote.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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) &&
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand All @@ -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) {
Expand Down Expand Up @@ -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);
}

Expand All @@ -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);
}

Expand All @@ -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 =
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions remote.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
114 changes: 69 additions & 45 deletions setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -1887,21 +1887,79 @@ void initialize_repository_version(int hash_algo, int reinit)
git_config_set_gently("extensions.objectformat", NULL);
}

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(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"));

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();

Expand All @@ -1921,6 +1979,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.
Expand Down Expand Up @@ -1964,39 +2024,6 @@ 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);

/* Check filemode trustability */
Expand Down Expand Up @@ -2156,14 +2183,11 @@ int init_db(const char *git_dir, const char *real_git_dir,
validate_hash_algorithm(&repo_fmt, hash);

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);

if (!(flags & INIT_DB_SKIP_REFDB))
create_reference_database(initial_branch, flags & INIT_DB_QUIET);
create_object_directory();

if (get_shared_repository()) {
Expand Down
6 changes: 4 additions & 2 deletions setup.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,14 +169,16 @@ 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,
const char *initial_branch, int init_shared_repository,
unsigned int flags);
void initialize_repository_version(int hash_algo, int reinit);
void create_reference_database(const char *initial_branch, int quiet);

/*
* NOTE NOTE NOTE!!
Expand Down
Loading

0 comments on commit 94e8e40

Please sign in to comment.