Skip to content

Commit ce65a18

Browse files
committed
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
2 parents 6a887bd + 199f44c commit ce65a18

File tree

3 files changed

+59
-1
lines changed

3 files changed

+59
-1
lines changed

builtin/clone.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -927,6 +927,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
927927
struct ref *mapped_refs = NULL;
928928
const struct ref *ref;
929929
struct strbuf key = STRBUF_INIT;
930+
struct strbuf buf = STRBUF_INIT;
930931
struct strbuf branch_top = STRBUF_INIT, reflog_msg = STRBUF_INIT;
931932
struct transport *transport = NULL;
932933
const char *src_ref_prefix = "refs/heads/";
@@ -1126,6 +1127,50 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
11261127
git_dir = real_git_dir;
11271128
}
11281129

1130+
/*
1131+
* We have a chicken-and-egg situation between initializing the refdb
1132+
* and spawning transport helpers:
1133+
*
1134+
* - Initializing the refdb requires us to know about the object
1135+
* format. We thus have to spawn the transport helper to learn
1136+
* about it.
1137+
*
1138+
* - The transport helper may want to access the Git repository. But
1139+
* because the refdb has not been initialized, we don't have "HEAD"
1140+
* or "refs/". Thus, the helper cannot find the Git repository.
1141+
*
1142+
* Ideally, we would have structured the helper protocol such that it's
1143+
* mandatory for the helper to first announce its capabilities without
1144+
* yet assuming a fully initialized repository. Like that, we could
1145+
* have added a "lazy-refdb-init" capability that announces whether the
1146+
* helper is ready to handle not-yet-initialized refdbs. If any helper
1147+
* didn't support them, we would have fully initialized the refdb with
1148+
* the SHA1 object format, but later on bailed out if we found out that
1149+
* the remote repository used a different object format.
1150+
*
1151+
* But we didn't, and thus we use the following workaround to partially
1152+
* initialize the repository's refdb such that it can be discovered by
1153+
* Git commands. To do so, we:
1154+
*
1155+
* - Create an invalid HEAD ref pointing at "refs/heads/.invalid".
1156+
*
1157+
* - Create the "refs/" directory.
1158+
*
1159+
* - Set up the ref storage format and repository version as
1160+
* required.
1161+
*
1162+
* This is sufficient for Git commands to discover the Git directory.
1163+
*/
1164+
initialize_repository_version(GIT_HASH_UNKNOWN,
1165+
the_repository->ref_storage_format, 1);
1166+
1167+
strbuf_addf(&buf, "%s/HEAD", git_dir);
1168+
write_file(buf.buf, "ref: refs/heads/.invalid");
1169+
1170+
strbuf_reset(&buf);
1171+
strbuf_addf(&buf, "%s/refs", git_dir);
1172+
safe_create_dir(buf.buf, 1);
1173+
11291174
/*
11301175
* additional config can be injected with -c, make sure it's included
11311176
* after init_db, which clears the entire config environment.
@@ -1454,6 +1499,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
14541499
free(remote_name);
14551500
strbuf_release(&reflog_msg);
14561501
strbuf_release(&branch_top);
1502+
strbuf_release(&buf);
14571503
strbuf_release(&key);
14581504
free_refs(mapped_refs);
14591505
free_refs(remote_head_points_at);

setup.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1889,6 +1889,13 @@ void initialize_repository_version(int hash_algo,
18891889
char repo_version_string[10];
18901890
int repo_version = GIT_REPO_VERSION;
18911891

1892+
/*
1893+
* Note that we initialize the repository version to 1 when the ref
1894+
* storage format is unknown. This is on purpose so that we can add the
1895+
* correct object format to the config during git-clone(1). The format
1896+
* version will get adjusted by git-clone(1) once it has learned about
1897+
* the remote repository's format.
1898+
*/
18921899
if (hash_algo != GIT_HASH_SHA1 ||
18931900
ref_storage_format != REF_STORAGE_FORMAT_FILES)
18941901
repo_version = GIT_REPO_VERSION_READ;
@@ -1898,7 +1905,7 @@ void initialize_repository_version(int hash_algo,
18981905
"%d", repo_version);
18991906
git_config_set("core.repositoryformatversion", repo_version_string);
19001907

1901-
if (hash_algo != GIT_HASH_SHA1)
1908+
if (hash_algo != GIT_HASH_SHA1 && hash_algo != GIT_HASH_UNKNOWN)
19021909
git_config_set("extensions.objectformat",
19031910
hash_algos[hash_algo].name);
19041911
else if (reinit)

t/t5801/git-remote-testgit

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ url=$2
1212

1313
dir="$GIT_DIR/testgit/$alias"
1414

15+
if ! git rev-parse --is-inside-git-dir
16+
then
17+
exit 1
18+
fi
19+
1520
h_refspec="refs/heads/*:refs/testgit/$alias/heads/*"
1621
t_refspec="refs/tags/*:refs/testgit/$alias/tags/*"
1722

0 commit comments

Comments
 (0)