1
0
mirror of https://github.com/git/git synced 2024-07-05 00:58:49 +00:00

Merge branch 'ps/remote-helper-repo-initialization-fix'

A custom remote helper no longer cannot access the newly created
repository during "git clone", which is a regression in Git 2.44.
This has been corrected.

* ps/remote-helper-repo-initialization-fix:
  builtin/clone: allow remote helpers to detect repo
This commit is contained in:
Junio C Hamano 2024-03-07 15:59:42 -08:00
commit ce65a188b1
3 changed files with 59 additions and 1 deletions

View File

@ -927,6 +927,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
struct ref *mapped_refs = NULL;
const struct ref *ref;
struct strbuf key = STRBUF_INIT;
struct strbuf buf = STRBUF_INIT;
struct strbuf branch_top = STRBUF_INIT, reflog_msg = STRBUF_INIT;
struct transport *transport = NULL;
const char *src_ref_prefix = "refs/heads/";
@ -1126,6 +1127,50 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
git_dir = real_git_dir;
}
/*
* We have a chicken-and-egg situation between initializing the refdb
* and spawning transport helpers:
*
* - Initializing the refdb requires us to know about the object
* format. We thus have to spawn the transport helper to learn
* about it.
*
* - The transport helper may want to access the Git repository. But
* because the refdb has not been initialized, we don't have "HEAD"
* or "refs/". Thus, the helper cannot find the Git repository.
*
* Ideally, we would have structured the helper protocol such that it's
* mandatory for the helper to first announce its capabilities without
* yet assuming a fully initialized repository. Like that, we could
* have added a "lazy-refdb-init" capability that announces whether the
* helper is ready to handle not-yet-initialized refdbs. If any helper
* didn't support them, we would have fully initialized the refdb with
* the SHA1 object format, but later on bailed out if we found out that
* the remote repository used a different object format.
*
* But we didn't, and thus we use the following workaround to partially
* initialize the repository's refdb such that it can be discovered by
* Git commands. To do so, we:
*
* - Create an invalid HEAD ref pointing at "refs/heads/.invalid".
*
* - Create the "refs/" directory.
*
* - Set up the ref storage format and repository version as
* required.
*
* This is sufficient for Git commands to discover the Git directory.
*/
initialize_repository_version(GIT_HASH_UNKNOWN,
the_repository->ref_storage_format, 1);
strbuf_addf(&buf, "%s/HEAD", git_dir);
write_file(buf.buf, "ref: refs/heads/.invalid");
strbuf_reset(&buf);
strbuf_addf(&buf, "%s/refs", git_dir);
safe_create_dir(buf.buf, 1);
/*
* additional config can be injected with -c, make sure it's included
* after init_db, which clears the entire config environment.
@ -1454,6 +1499,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
free(remote_name);
strbuf_release(&reflog_msg);
strbuf_release(&branch_top);
strbuf_release(&buf);
strbuf_release(&key);
free_refs(mapped_refs);
free_refs(remote_head_points_at);

View File

@ -1889,6 +1889,13 @@ void initialize_repository_version(int hash_algo,
char repo_version_string[10];
int repo_version = GIT_REPO_VERSION;
/*
* Note that we initialize the repository version to 1 when the ref
* storage format is unknown. This is on purpose so that we can add the
* correct object format to the config during git-clone(1). The format
* version will get adjusted by git-clone(1) once it has learned about
* the remote repository's format.
*/
if (hash_algo != GIT_HASH_SHA1 ||
ref_storage_format != REF_STORAGE_FORMAT_FILES)
repo_version = GIT_REPO_VERSION_READ;
@ -1898,7 +1905,7 @@ void initialize_repository_version(int hash_algo,
"%d", repo_version);
git_config_set("core.repositoryformatversion", repo_version_string);
if (hash_algo != GIT_HASH_SHA1)
if (hash_algo != GIT_HASH_SHA1 && hash_algo != GIT_HASH_UNKNOWN)
git_config_set("extensions.objectformat",
hash_algos[hash_algo].name);
else if (reinit)

View File

@ -12,6 +12,11 @@ url=$2
dir="$GIT_DIR/testgit/$alias"
if ! git rev-parse --is-inside-git-dir
then
exit 1
fi
h_refspec="refs/heads/*:refs/testgit/$alias/heads/*"
t_refspec="refs/tags/*:refs/testgit/$alias/tags/*"