1
0
Fork 0
mirror of https://github.com/git/git.git synced 2024-05-24 04:56:09 +02:00

remote-curl: fix parsing of detached SHA256 heads

The dumb HTTP transport tries to read the remote HEAD reference by
downloading the "HEAD" file and then parsing it via `http_fetch_ref()`.
This function will either parse the file as an object ID in case it is
exactly `the_hash_algo->hexsz` long, or otherwise it will check whether
the reference starts with "ref :" and parse it as a symbolic ref.

This is broken when parsing detached HEADs of a remote SHA256 repository
because we never update `the_hash_algo` to the discovered remote object
hash. Consequently, `the_hash_algo` will always be the fallback SHA1
hash algorithm, which will cause us to fail parsing HEAD altogteher when
it contains a SHA256 object ID.

Fix this issue by setting up `the_hash_algo` via `repo_set_hash_algo()`.
While at it, let's make the expected SHA1 fallback explicit in our code,
which also addresses an upcoming issue where we are going to remove the
SHA1 fallback for `the_hash_algo`.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Patrick Steinhardt 2024-05-07 06:53:10 +02:00 committed by Junio C Hamano
parent 813f17fd6b
commit bd455cec37
2 changed files with 33 additions and 1 deletions

View File

@ -266,12 +266,23 @@ static struct ref *parse_git_refs(struct discovery *heads, int for_push)
return list;
}
/*
* Try to detect the hash algorithm used by the remote repository when using
* the dumb HTTP transport. As dumb transports cannot tell us the object hash
* directly have to derive it from the advertised ref lengths.
*/
static const struct git_hash_algo *detect_hash_algo(struct discovery *heads)
{
const char *p = memchr(heads->buf, '\t', heads->len);
int algo;
/*
* In case the remote has no refs we have no way to reliably determine
* the object hash used by that repository. In that case we simply fall
* back to SHA1, which may or may not be correct.
*/
if (!p)
return the_hash_algo;
return &hash_algos[GIT_HASH_SHA1];
algo = hash_algo_by_length((p - heads->buf) / 2);
if (algo == GIT_HASH_UNKNOWN)
@ -295,6 +306,12 @@ static struct ref *parse_info_refs(struct discovery *heads)
"is this a git repository?",
transport_anonymize_url(url.buf));
/*
* Set the repository's hash algo to whatever we have just detected.
* This ensures that we can correctly parse the remote references.
*/
repo_set_hash_algo(the_repository, hash_algo_by_ptr(options.hash_algo));
data = heads->buf;
start = NULL;
mid = data;

View File

@ -55,6 +55,21 @@ test_expect_success 'list refs from outside any repository' '
test_cmp expect actual
'
test_expect_success 'list detached HEAD from outside any repository' '
git clone --mirror "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \
"$HTTPD_DOCUMENT_ROOT_PATH/repo-detached.git" &&
git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo-detached.git" \
update-ref --no-deref HEAD refs/heads/main &&
git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo-detached.git" update-server-info &&
cat >expect <<-EOF &&
$(git rev-parse main) HEAD
$(git rev-parse main) refs/heads/main
EOF
nongit git ls-remote "$HTTPD_URL/dumb/repo-detached.git" >actual &&
test_cmp expect actual
'
test_expect_success 'create password-protected repository' '
mkdir -p "$HTTPD_DOCUMENT_ROOT_PATH/auth/dumb/" &&
cp -Rf "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \