ls-refs.c: traverse prefixes of disjoint "ref-prefix" sets
commitb3970c702cb0acc0551d88a5f34ad4ad2e2a6d39
authorTaylor Blau <me@ttaylorr.com>
Wed, 20 Jan 2021 16:04:30 +0000 (20 11:04 -0500)
committerJunio C Hamano <gitster@pobox.com>
Sat, 23 Jan 2021 02:57:27 +0000 (22 18:57 -0800)
treef542287db174eb086f05257946f2e65643a2dc17
parent83befd37249726f6a94e55f5aad1113fd18102a0
ls-refs.c: traverse prefixes of disjoint "ref-prefix" sets

ls-refs performs a single revision walk over the whole ref namespace,
and sends ones that match with one of the given ref prefixes down to the
user.

This can be expensive if there are many refs overall, but the portion of
them covered by the given prefixes is small by comparison.

To attempt to reduce the difference between the number of refs
traversed, and the number of refs sent, only traverse references which
are in the longest common prefix of the given prefixes. This is very
reminiscent of the approach taken in b31e2680c4 (ref-filter.c: find
disjoint pattern prefixes, 2019-06-26) which does an analogous thing for
multi-patterned 'git for-each-ref' invocations.

The callback 'send_ref' is resilient to ignore extra patterns by
discarding any arguments which do not begin with at least one of the
specified prefixes.

Similarly, the code introduced in b31e2680c4 is resilient to stop early
at metacharacters, but we only pass strict prefixes here. At worst we
would return too many results, but the double checking done by send_ref
will throw away anything that doesn't start with something in the prefix
list.

Finally, if no prefixes were provided, then implicitly add the empty
string (which will match all references) since this matches the existing
behavior (see the "no restrictions" comment in "ls-refs.c:ref_match()").

Original-patch-by: Jacob Vosmaer <jacob@gitlab.com>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
ls-refs.c