Skip to content

Commit c702dd4

Browse files
peffgitster
authored andcommitted
fetch: use ref prefix list to skip ls-refs
In git-fetch we have an optimization to avoid issuing an ls-refs command to the server if we don't care about the value of any refs (e.g., because we are fetching exact object ids), saving a round-trip to the server. This comes from e70a303 (fetch: do not list refs if fetching only hashes, 2018-09-27). It uses an explicit flag "must_list_refs" to decide when we need to do so. That was needed back then, because the list of ref-prefixes was not always complete. If it was empty, it did not necessarily mean that we were not interested in any refs). But that is no longer the case; an empty list of prefixes means that we truly do not care about any refs. And so rather than an explicit flag, we can just check whether we are interested in any ref prefixes. This simplifies the code slightly, as there is now a single source of truth for the decision. It also fixes a bug in / optimizes a very unlikely case, which is: git fetch $remote ^foo $oid I.e., a negative refspec combined with an exact oid fetch. This is somewhat nonsense, in that there are no positive refspecs mentioning refs to countermand with the negative one. But we should be able to do this without issuing an ls-refs command (excluding "foo" from the empty set will obviously still be the empty set). However, the current code does not do so. The negative refspec is not counted as a noop in un-setting the must_list_refs flag (hardly the fault of e70a303, as negative refspecs did not appear until much later). But by using the prefix list as a source of truth, this naturally just works; the negative refspec does not add a prefix to ask about, and hence does not trigger the ls-refs call. This is esoteric enough that I didn't bother adding a test. The real value here is in the code simplification. Signed-off-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 20010b8 commit c702dd4

File tree

1 file changed

+7
-20
lines changed

1 file changed

+7
-20
lines changed

builtin/fetch.c

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1718,7 +1718,6 @@ static int do_fetch(struct transport *transport,
17181718
const struct ref *remote_refs;
17191719
struct transport_ls_refs_options transport_ls_refs_options =
17201720
TRANSPORT_LS_REFS_OPTIONS_INIT;
1721-
int must_list_refs = 1;
17221721
struct fetch_head fetch_head = { 0 };
17231722
struct strbuf err = STRBUF_INIT;
17241723

@@ -1737,21 +1736,7 @@ static int do_fetch(struct transport *transport,
17371736
}
17381737

17391738
if (rs->nr) {
1740-
int i;
1741-
17421739
refspec_ref_prefixes(rs, &transport_ls_refs_options.ref_prefixes);
1743-
1744-
/*
1745-
* We can avoid listing refs if all of them are exact
1746-
* OIDs
1747-
*/
1748-
must_list_refs = 0;
1749-
for (i = 0; i < rs->nr; i++) {
1750-
if (!rs->items[i].exact_sha1) {
1751-
must_list_refs = 1;
1752-
break;
1753-
}
1754-
}
17551740
} else {
17561741
struct branch *branch = branch_get(NULL);
17571742

@@ -1776,18 +1761,20 @@ static int do_fetch(struct transport *transport,
17761761
"HEAD");
17771762
}
17781763

1779-
if (tags == TAGS_SET || tags == TAGS_DEFAULT) {
1780-
must_list_refs = 1;
1764+
if (tags == TAGS_SET || tags == TAGS_DEFAULT)
17811765
strvec_push(&transport_ls_refs_options.ref_prefixes,
17821766
"refs/tags/");
1783-
}
17841767

1785-
if (must_list_refs &&
1768+
if (transport_ls_refs_options.ref_prefixes.nr &&
17861769
uses_remote_tracking(transport, rs))
17871770
strvec_push(&transport_ls_refs_options.ref_prefixes,
17881771
"HEAD");
17891772

1790-
if (must_list_refs) {
1773+
/*
1774+
* Only initiate ref listing if we have at least one ref we want to
1775+
* know about.
1776+
*/
1777+
if (transport_ls_refs_options.ref_prefixes.nr) {
17911778
trace2_region_enter("fetch", "remote_refs", the_repository);
17921779
remote_refs = transport_get_remote_refs(transport,
17931780
&transport_ls_refs_options);

0 commit comments

Comments
 (0)