Skip to content

Commit

Permalink
clone: unbundle the advertised bundles
Browse files Browse the repository at this point in the history
A previous change introduced the transport methods to acquire a bundle
list from the 'bundle-uri' protocol v2 command, when advertised _and_
when the client has chosen to enable the feature.

Teach Git to download and unbundle the data advertised by those bundles
during 'git clone'. This takes place between the ref advertisement and
the object data download, and stateful connections will linger while
the client downloads bundles. In the future, we should consider closing
the remote connection during this process.

Also, since the --bundle-uri option exists, we do not want to mix the
advertised bundles with the user-specified bundles.

Signed-off-by: Derrick Stolee <derrickstolee@github.com>
  • Loading branch information
derrickstolee committed Dec 21, 2022
1 parent 72ca6f4 commit 46ab2b0
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 7 deletions.
25 changes: 20 additions & 5 deletions builtin/clone.c
Original file line number Diff line number Diff line change
Expand Up @@ -1266,11 +1266,26 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (refs)
mapped_refs = wanted_peer_refs(refs, &remote->fetch);

/*
* Populate transport->got_remote_bundle_uri and
* transport->bundle_uri. We might get nothing.
*/
transport_get_remote_bundle_uri(transport);
if (!bundle_uri) {
/*
* Populate transport->got_remote_bundle_uri and
* transport->bundle_uri. We might get nothing.
*/
transport_get_remote_bundle_uri(transport);

if (transport->bundles &&
hashmap_get_size(&transport->bundles->bundles)) {
/* At this point, we need the_repository to match the cloned repo. */
if (repo_init(the_repository, git_dir, work_tree))
warning(_("failed to initialize the repo, skipping bundle URI"));
else if (fetch_bundle_list(the_repository,
transport->bundles))
warning(_("failed to fetch advertised bundles"));
} else {
clear_bundle_list(transport->bundles);
FREE_AND_NULL(transport->bundles);
}
}

if (mapped_refs) {
int hash_algo = hash_algo_by_ptr(transport_get_hash_algo(transport));
Expand Down
21 changes: 19 additions & 2 deletions t/lib-bundle-uri-protocol.sh
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ test_expect_success "connect with $BUNDLE_URI_PROTOCOL:// using protocol v2: hav
'

test_expect_success "clone with $BUNDLE_URI_PROTOCOL:// using protocol v2: request bundle-uris" '
test_when_finished "rm -rf log cloned cloned2" &&
test_when_finished "rm -rf log* cloned*" &&
GIT_TRACE_PACKET="$PWD/log" \
git \
Expand Down Expand Up @@ -117,7 +117,24 @@ test_expect_success "clone with $BUNDLE_URI_PROTOCOL:// using protocol v2: reque
grep "< bundle-uri" log &&
# Client issued bundle-uri command
grep "> command=bundle-uri" log
grep "> command=bundle-uri" log &&
GIT_TRACE_PACKET="$PWD/log3" \
git \
-c transfer.bundleURI=true \
-c protocol.version=2 \
clone --bundle-uri="$BUNDLE_URI_BUNDLE_URI" \
"$BUNDLE_URI_REPO_URI" cloned3 \
>actual 2>err &&
# Server responded using protocol v2
grep "< version 2" log3 &&
# Server advertised bundle-uri capability
grep "< bundle-uri" log3 &&
# Client did not issue bundle-uri command (--bundle-uri override)
! grep "> command=bundle-uri" log3
'

# The remaining tests will all assume transfer.bundleURI=true
Expand Down
59 changes: 59 additions & 0 deletions t/t5601-clone.sh
Original file line number Diff line number Diff line change
Expand Up @@ -795,6 +795,65 @@ test_expect_success 'reject cloning shallow repository using HTTP' '
git clone --no-reject-shallow $HTTPD_URL/smart/repo.git repo
'

test_expect_success 'auto-discover bundle URI from HTTP clone' '
test_when_finished rm -rf trace.txt repo2 "$HTTPD_DOCUMENT_ROOT_PATH/repo2.git" &&
git -C src bundle create "$HTTPD_DOCUMENT_ROOT_PATH/everything.bundle" --all &&
git clone --bare --no-local src "$HTTPD_DOCUMENT_ROOT_PATH/repo2.git" &&
git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo2.git" config \
uploadpack.advertiseBundleURIs true &&
git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo2.git" config \
bundle.version 1 &&
git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo2.git" config \
bundle.mode all &&
git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo2.git" config \
bundle.everything.uri "$HTTPD_URL/everything.bundle" &&
GIT_TRACE2_EVENT="$(pwd)/trace.txt" \
git -c protocol.version=2 \
-c transfer.bundleURI=true clone \
$HTTPD_URL/smart/repo2.git repo2 &&
cat >pattern <<-EOF &&
"event":"child_start".*"argv":\["git-remote-https","$HTTPD_URL/everything.bundle"\]
EOF
grep -f pattern trace.txt
'

test_expect_success 'auto-discover multiple bundles from HTTP clone' '
test_when_finished rm -rf trace.txt repo3 "$HTTPD_DOCUMENT_ROOT_PATH/repo3.git" &&
test_commit -C src new &&
git -C src bundle create "$HTTPD_DOCUMENT_ROOT_PATH/new.bundle" HEAD~1..HEAD &&
git clone --bare --no-local src "$HTTPD_DOCUMENT_ROOT_PATH/repo3.git" &&
git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo3.git" config \
uploadpack.advertiseBundleURIs true &&
git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo3.git" config \
bundle.version 1 &&
git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo3.git" config \
bundle.mode all &&
git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo3.git" config \
bundle.everything.uri "$HTTPD_URL/everything.bundle" &&
git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo3.git" config \
bundle.new.uri "$HTTPD_URL/new.bundle" &&
GIT_TRACE2_EVENT="$(pwd)/trace.txt" \
git -c protocol.version=2 \
-c transfer.bundleURI=true clone \
$HTTPD_URL/smart/repo3.git repo3 &&
# We should fetch _both_ bundles
cat >pattern <<-EOF &&
"event":"child_start".*"argv":\["git-remote-https","$HTTPD_URL/everything.bundle"\]
EOF
grep -f pattern trace.txt &&
cat >pattern <<-EOF &&
"event":"child_start".*"argv":\["git-remote-https","$HTTPD_URL/new.bundle"\]
EOF
grep -f pattern trace.txt
'

# DO NOT add non-httpd-specific tests here, because the last part of this
# test script is only executed when httpd is available and enabled.

Expand Down

0 comments on commit 46ab2b0

Please sign in to comment.