зеркало из https://github.com/microsoft/git.git
Merge branch 'jt/avoid-ls-refs'
Over some transports, fetching objects with an exact commit object name can be done without first seeing the ref advertisements. The code has been optimized to exploit this. * jt/avoid-ls-refs: fetch: do not list refs if fetching only hashes transport: list refs before fetch if necessary transport: do not list refs if possible transport: allow skipping of ref listing
This commit is contained in:
Коммит
0527fbab68
|
@ -1186,6 +1186,7 @@ static int do_fetch(struct transport *transport,
|
|||
int retcode = 0;
|
||||
const struct ref *remote_refs;
|
||||
struct argv_array ref_prefixes = ARGV_ARRAY_INIT;
|
||||
int must_list_refs = 1;
|
||||
|
||||
if (tags == TAGS_DEFAULT) {
|
||||
if (transport->remote->fetch_tags == 2)
|
||||
|
@ -1201,17 +1202,36 @@ static int do_fetch(struct transport *transport,
|
|||
goto cleanup;
|
||||
}
|
||||
|
||||
if (rs->nr)
|
||||
if (rs->nr) {
|
||||
int i;
|
||||
|
||||
refspec_ref_prefixes(rs, &ref_prefixes);
|
||||
else if (transport->remote && transport->remote->fetch.nr)
|
||||
|
||||
/*
|
||||
* We can avoid listing refs if all of them are exact
|
||||
* OIDs
|
||||
*/
|
||||
must_list_refs = 0;
|
||||
for (i = 0; i < rs->nr; i++) {
|
||||
if (!rs->items[i].exact_sha1) {
|
||||
must_list_refs = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (transport->remote && transport->remote->fetch.nr)
|
||||
refspec_ref_prefixes(&transport->remote->fetch, &ref_prefixes);
|
||||
|
||||
if (ref_prefixes.argc &&
|
||||
(tags == TAGS_SET || (tags == TAGS_DEFAULT))) {
|
||||
if (tags == TAGS_SET || tags == TAGS_DEFAULT) {
|
||||
must_list_refs = 1;
|
||||
if (ref_prefixes.argc)
|
||||
argv_array_push(&ref_prefixes, "refs/tags/");
|
||||
}
|
||||
|
||||
if (must_list_refs)
|
||||
remote_refs = transport_get_remote_refs(transport, &ref_prefixes);
|
||||
else
|
||||
remote_refs = NULL;
|
||||
|
||||
argv_array_clear(&ref_prefixes);
|
||||
|
||||
ref_map = get_ref_map(transport->remote, remote_refs, rs,
|
||||
|
|
|
@ -1626,7 +1626,7 @@ struct ref *fetch_pack(struct fetch_pack_args *args,
|
|||
parse_list_objects_filter(&args->filter_options, "blob:none");
|
||||
}
|
||||
|
||||
if (!ref) {
|
||||
if (version != protocol_v2 && !ref) {
|
||||
packet_flush(fd[1]);
|
||||
die(_("no matching remote head"));
|
||||
}
|
||||
|
|
|
@ -381,6 +381,21 @@ test_expect_success 'using fetch command in remote-curl updates refs' '
|
|||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'fetch by SHA-1 without tag following' '
|
||||
SERVER="$HTTPD_DOCUMENT_ROOT_PATH/server" &&
|
||||
rm -rf "$SERVER" client &&
|
||||
|
||||
git init "$SERVER" &&
|
||||
test_commit -C "$SERVER" foo &&
|
||||
|
||||
git clone $HTTPD_URL/smart/server client &&
|
||||
|
||||
test_commit -C "$SERVER" bar &&
|
||||
git -C "$SERVER" rev-parse bar >bar_hash &&
|
||||
git -C client -c protocol.version=0 fetch \
|
||||
--no-tags origin $(cat bar_hash)
|
||||
'
|
||||
|
||||
test_expect_success 'GIT_REDACT_COOKIES redacts cookies' '
|
||||
rm -rf clone &&
|
||||
echo "Set-Cookie: Foo=1" >cookies &&
|
||||
|
|
|
@ -79,6 +79,19 @@ test_expect_success 'fetch with git:// using protocol v2' '
|
|||
grep "fetch< version 2" log
|
||||
'
|
||||
|
||||
test_expect_success 'fetch by hash without tag following with protocol v2 does not list refs' '
|
||||
test_when_finished "rm -f log" &&
|
||||
|
||||
test_commit -C "$daemon_parent" two_a &&
|
||||
git -C "$daemon_parent" rev-parse two_a >two_a_hash &&
|
||||
|
||||
GIT_TRACE_PACKET="$(pwd)/log" git -C daemon_child -c protocol.version=2 \
|
||||
fetch --no-tags origin $(cat two_a_hash) &&
|
||||
|
||||
grep "fetch< version 2" log &&
|
||||
! grep "fetch> command=ls-refs" log
|
||||
'
|
||||
|
||||
test_expect_success 'pull with git:// using protocol v2' '
|
||||
test_when_finished "rm -f log" &&
|
||||
|
||||
|
@ -286,6 +299,10 @@ test_expect_success 'dynamically fetch missing object' '
|
|||
grep "version 2" trace
|
||||
'
|
||||
|
||||
test_expect_success 'when dynamically fetching missing object, do not list refs' '
|
||||
! grep "git> command=ls-refs" trace
|
||||
'
|
||||
|
||||
test_expect_success 'partial fetch' '
|
||||
rm -rf client "$(pwd)/trace" &&
|
||||
git init client &&
|
||||
|
|
|
@ -1105,6 +1105,7 @@ static struct ref *get_refs_list(struct transport *transport, int for_push,
|
|||
}
|
||||
|
||||
static struct transport_vtable vtable = {
|
||||
0,
|
||||
set_helper_option,
|
||||
get_refs_list,
|
||||
fetch,
|
||||
|
|
|
@ -6,6 +6,12 @@ struct transport;
|
|||
struct argv_array;
|
||||
|
||||
struct transport_vtable {
|
||||
/**
|
||||
* This transport supports the fetch() function being called
|
||||
* without get_refs_list() first being called.
|
||||
*/
|
||||
unsigned fetch_without_list : 1;
|
||||
|
||||
/**
|
||||
* Returns 0 if successful, positive if the option is not
|
||||
* recognized or is inapplicable, and negative if the option
|
||||
|
|
52
transport.c
52
transport.c
|
@ -252,8 +252,18 @@ static int connect_setup(struct transport *transport, int for_push)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct ref *get_refs_via_connect(struct transport *transport, int for_push,
|
||||
const struct argv_array *ref_prefixes)
|
||||
/*
|
||||
* Obtains the protocol version from the transport and writes it to
|
||||
* transport->data->version, first connecting if not already connected.
|
||||
*
|
||||
* If the protocol version is one that allows skipping the listing of remote
|
||||
* refs, and must_list_refs is 0, the listing of remote refs is skipped and
|
||||
* this function returns NULL. Otherwise, this function returns the list of
|
||||
* remote refs.
|
||||
*/
|
||||
static struct ref *handshake(struct transport *transport, int for_push,
|
||||
const struct argv_array *ref_prefixes,
|
||||
int must_list_refs)
|
||||
{
|
||||
struct git_transport_data *data = transport->data;
|
||||
struct ref *refs = NULL;
|
||||
|
@ -268,8 +278,10 @@ static struct ref *get_refs_via_connect(struct transport *transport, int for_pus
|
|||
data->version = discover_version(&reader);
|
||||
switch (data->version) {
|
||||
case protocol_v2:
|
||||
if (must_list_refs)
|
||||
get_remote_refs(data->fd[1], &reader, &refs, for_push,
|
||||
ref_prefixes, transport->server_options);
|
||||
ref_prefixes,
|
||||
transport->server_options);
|
||||
break;
|
||||
case protocol_v1:
|
||||
case protocol_v0:
|
||||
|
@ -283,9 +295,18 @@ static struct ref *get_refs_via_connect(struct transport *transport, int for_pus
|
|||
}
|
||||
data->got_remote_heads = 1;
|
||||
|
||||
if (reader.line_peeked)
|
||||
BUG("buffer must be empty at the end of handshake()");
|
||||
|
||||
return refs;
|
||||
}
|
||||
|
||||
static struct ref *get_refs_via_connect(struct transport *transport, int for_push,
|
||||
const struct argv_array *ref_prefixes)
|
||||
{
|
||||
return handshake(transport, for_push, ref_prefixes, 1);
|
||||
}
|
||||
|
||||
static int fetch_refs_via_pack(struct transport *transport,
|
||||
int nr_heads, struct ref **to_fetch)
|
||||
{
|
||||
|
@ -320,8 +341,17 @@ static int fetch_refs_via_pack(struct transport *transport,
|
|||
args.server_options = transport->server_options;
|
||||
args.negotiation_tips = data->options.negotiation_tips;
|
||||
|
||||
if (!data->got_remote_heads)
|
||||
refs_tmp = get_refs_via_connect(transport, 0, NULL);
|
||||
if (!data->got_remote_heads) {
|
||||
int i;
|
||||
int must_list_refs = 0;
|
||||
for (i = 0; i < nr_heads; i++) {
|
||||
if (!to_fetch[i]->exact_oid) {
|
||||
must_list_refs = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
refs_tmp = handshake(transport, 0, NULL, must_list_refs);
|
||||
}
|
||||
|
||||
switch (data->version) {
|
||||
case protocol_v2:
|
||||
|
@ -703,6 +733,7 @@ static int disconnect_git(struct transport *transport)
|
|||
}
|
||||
|
||||
static struct transport_vtable taken_over_vtable = {
|
||||
1,
|
||||
NULL,
|
||||
get_refs_via_connect,
|
||||
fetch_refs_via_pack,
|
||||
|
@ -852,6 +883,7 @@ void transport_check_allowed(const char *type)
|
|||
}
|
||||
|
||||
static struct transport_vtable bundle_vtable = {
|
||||
0,
|
||||
NULL,
|
||||
get_refs_from_bundle,
|
||||
fetch_refs_from_bundle,
|
||||
|
@ -861,6 +893,7 @@ static struct transport_vtable bundle_vtable = {
|
|||
};
|
||||
|
||||
static struct transport_vtable builtin_smart_vtable = {
|
||||
1,
|
||||
NULL,
|
||||
get_refs_via_connect,
|
||||
fetch_refs_via_pack,
|
||||
|
@ -1227,6 +1260,15 @@ int transport_fetch_refs(struct transport *transport, struct ref *refs)
|
|||
struct ref **heads = NULL;
|
||||
struct ref *rm;
|
||||
|
||||
if (!transport->vtable->fetch_without_list)
|
||||
/*
|
||||
* Some transports (e.g. the built-in bundle transport and the
|
||||
* transport helper interface) do not work when fetching is
|
||||
* done immediately after transport creation. List the remote
|
||||
* refs anyway (if not already listed) as a workaround.
|
||||
*/
|
||||
transport_get_remote_refs(transport, NULL);
|
||||
|
||||
for (rm = refs; rm; rm = rm->next) {
|
||||
nr_refs++;
|
||||
if (rm->peer_ref &&
|
||||
|
|
Загрузка…
Ссылка в новой задаче