Merge branch 'tb/refs-exclusion-and-packed-refs' into next
Enumerating refs in the packed-refs file, while excluding refs that match certain patterns, has been optimized. * tb/refs-exclusion-and-packed-refs: ls-refs.c: avoid enumerating hidden refs where possible upload-pack.c: avoid enumerating hidden refs where possible builtin/receive-pack.c: avoid enumerating hidden references refs.h: implement `hidden_refs_to_excludes()` refs.h: let `for_each_namespaced_ref()` take excluded patterns revision.h: store hidden refs in a `strvec` refs/packed-backend.c: add trace2 counters for jump list refs/packed-backend.c: implement jump lists to avoid excluded pattern(s) refs/packed-backend.c: refactor `find_reference_location()` refs: plumb `exclude_patterns` argument throughout builtin/for-each-ref.c: add `--exclude` option ref-filter.c: parameterize match functions over patterns ref-filter: add `ref_filter_clear()` ref-filter: clear reachable list pointers after freeing ref-filter.h: provide `REF_FILTER_INIT` refs.c: rename `ref_filter`
This commit is contained in:
85
refs.c
85
refs.c
@ -375,8 +375,8 @@ char *resolve_refdup(const char *refname, int resolve_flags,
|
||||
oid, flags);
|
||||
}
|
||||
|
||||
/* The argument to filter_refs */
|
||||
struct ref_filter {
|
||||
/* The argument to for_each_filter_refs */
|
||||
struct for_each_ref_filter {
|
||||
const char *pattern;
|
||||
const char *prefix;
|
||||
each_ref_fn *fn;
|
||||
@ -409,10 +409,11 @@ int ref_exists(const char *refname)
|
||||
return refs_ref_exists(get_main_ref_store(the_repository), refname);
|
||||
}
|
||||
|
||||
static int filter_refs(const char *refname, const struct object_id *oid,
|
||||
int flags, void *data)
|
||||
static int for_each_filter_refs(const char *refname,
|
||||
const struct object_id *oid,
|
||||
int flags, void *data)
|
||||
{
|
||||
struct ref_filter *filter = (struct ref_filter *)data;
|
||||
struct for_each_ref_filter *filter = data;
|
||||
|
||||
if (wildmatch(filter->pattern, refname, 0))
|
||||
return 0;
|
||||
@ -569,7 +570,7 @@ int for_each_glob_ref_in(each_ref_fn fn, const char *pattern,
|
||||
const char *prefix, void *cb_data)
|
||||
{
|
||||
struct strbuf real_pattern = STRBUF_INIT;
|
||||
struct ref_filter filter;
|
||||
struct for_each_ref_filter filter;
|
||||
int ret;
|
||||
|
||||
if (!prefix && !starts_with(pattern, "refs/"))
|
||||
@ -589,7 +590,7 @@ int for_each_glob_ref_in(each_ref_fn fn, const char *pattern,
|
||||
filter.prefix = prefix;
|
||||
filter.fn = fn;
|
||||
filter.cb_data = cb_data;
|
||||
ret = for_each_ref(filter_refs, &filter);
|
||||
ret = for_each_ref(for_each_filter_refs, &filter);
|
||||
|
||||
strbuf_release(&real_pattern);
|
||||
return ret;
|
||||
@ -1426,7 +1427,7 @@ char *shorten_unambiguous_ref(const char *refname, int strict)
|
||||
}
|
||||
|
||||
int parse_hide_refs_config(const char *var, const char *value, const char *section,
|
||||
struct string_list *hide_refs)
|
||||
struct strvec *hide_refs)
|
||||
{
|
||||
const char *key;
|
||||
if (!strcmp("transfer.hiderefs", var) ||
|
||||
@ -1437,22 +1438,23 @@ int parse_hide_refs_config(const char *var, const char *value, const char *secti
|
||||
|
||||
if (!value)
|
||||
return config_error_nonbool(var);
|
||||
ref = xstrdup(value);
|
||||
|
||||
/* drop const to remove trailing '/' characters */
|
||||
ref = (char *)strvec_push(hide_refs, value);
|
||||
len = strlen(ref);
|
||||
while (len && ref[len - 1] == '/')
|
||||
ref[--len] = '\0';
|
||||
string_list_append_nodup(hide_refs, ref);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ref_is_hidden(const char *refname, const char *refname_full,
|
||||
const struct string_list *hide_refs)
|
||||
const struct strvec *hide_refs)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = hide_refs->nr - 1; i >= 0; i--) {
|
||||
const char *match = hide_refs->items[i].string;
|
||||
const char *match = hide_refs->v[i];
|
||||
const char *subject;
|
||||
int neg = 0;
|
||||
const char *p;
|
||||
@ -1478,6 +1480,30 @@ int ref_is_hidden(const char *refname, const char *refname_full,
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char **hidden_refs_to_excludes(const struct strvec *hide_refs)
|
||||
{
|
||||
const char **pattern;
|
||||
for (pattern = hide_refs->v; *pattern; pattern++) {
|
||||
/*
|
||||
* We can't feed any excludes from hidden refs config
|
||||
* sections, since later rules may override previous
|
||||
* ones. For example, with rules "refs/foo" and
|
||||
* "!refs/foo/bar", we should show "refs/foo/bar" (and
|
||||
* everything underneath it), but the earlier exclusion
|
||||
* would cause us to skip all of "refs/foo". We
|
||||
* likewise don't implement the namespace stripping
|
||||
* required for '^' rules.
|
||||
*
|
||||
* Both are possible to do, but complicated, so avoid
|
||||
* populating the jump list at all if we see either of
|
||||
* these patterns.
|
||||
*/
|
||||
if (**pattern == '!' || **pattern == '^')
|
||||
return NULL;
|
||||
}
|
||||
return hide_refs->v;
|
||||
}
|
||||
|
||||
const char *find_descendant_ref(const char *dirname,
|
||||
const struct string_list *extras,
|
||||
const struct string_list *skip)
|
||||
@ -1525,7 +1551,9 @@ int head_ref(each_ref_fn fn, void *cb_data)
|
||||
|
||||
struct ref_iterator *refs_ref_iterator_begin(
|
||||
struct ref_store *refs,
|
||||
const char *prefix, int trim,
|
||||
const char *prefix,
|
||||
const char **exclude_patterns,
|
||||
int trim,
|
||||
enum do_for_each_ref_flags flags)
|
||||
{
|
||||
struct ref_iterator *iter;
|
||||
@ -1541,8 +1569,7 @@ struct ref_iterator *refs_ref_iterator_begin(
|
||||
}
|
||||
}
|
||||
|
||||
iter = refs->be->iterator_begin(refs, prefix, flags);
|
||||
|
||||
iter = refs->be->iterator_begin(refs, prefix, exclude_patterns, flags);
|
||||
/*
|
||||
* `iterator_begin()` already takes care of prefix, but we
|
||||
* might need to do some trimming:
|
||||
@ -1576,7 +1603,7 @@ static int do_for_each_repo_ref(struct repository *r, const char *prefix,
|
||||
if (!refs)
|
||||
return 0;
|
||||
|
||||
iter = refs_ref_iterator_begin(refs, prefix, trim, flags);
|
||||
iter = refs_ref_iterator_begin(refs, prefix, NULL, trim, flags);
|
||||
|
||||
return do_for_each_repo_ref_iterator(r, iter, fn, cb_data);
|
||||
}
|
||||
@ -1598,6 +1625,7 @@ static int do_for_each_ref_helper(struct repository *r,
|
||||
}
|
||||
|
||||
static int do_for_each_ref(struct ref_store *refs, const char *prefix,
|
||||
const char **exclude_patterns,
|
||||
each_ref_fn fn, int trim,
|
||||
enum do_for_each_ref_flags flags, void *cb_data)
|
||||
{
|
||||
@ -1607,7 +1635,8 @@ static int do_for_each_ref(struct ref_store *refs, const char *prefix,
|
||||
if (!refs)
|
||||
return 0;
|
||||
|
||||
iter = refs_ref_iterator_begin(refs, prefix, trim, flags);
|
||||
iter = refs_ref_iterator_begin(refs, prefix, exclude_patterns, trim,
|
||||
flags);
|
||||
|
||||
return do_for_each_repo_ref_iterator(the_repository, iter,
|
||||
do_for_each_ref_helper, &hp);
|
||||
@ -1615,7 +1644,7 @@ static int do_for_each_ref(struct ref_store *refs, const char *prefix,
|
||||
|
||||
int refs_for_each_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
|
||||
{
|
||||
return do_for_each_ref(refs, "", fn, 0, 0, cb_data);
|
||||
return do_for_each_ref(refs, "", NULL, fn, 0, 0, cb_data);
|
||||
}
|
||||
|
||||
int for_each_ref(each_ref_fn fn, void *cb_data)
|
||||
@ -1626,7 +1655,7 @@ int for_each_ref(each_ref_fn fn, void *cb_data)
|
||||
int refs_for_each_ref_in(struct ref_store *refs, const char *prefix,
|
||||
each_ref_fn fn, void *cb_data)
|
||||
{
|
||||
return do_for_each_ref(refs, prefix, fn, strlen(prefix), 0, cb_data);
|
||||
return do_for_each_ref(refs, prefix, NULL, fn, strlen(prefix), 0, cb_data);
|
||||
}
|
||||
|
||||
int for_each_ref_in(const char *prefix, each_ref_fn fn, void *cb_data)
|
||||
@ -1637,13 +1666,14 @@ int for_each_ref_in(const char *prefix, each_ref_fn fn, void *cb_data)
|
||||
int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data)
|
||||
{
|
||||
return do_for_each_ref(get_main_ref_store(the_repository),
|
||||
prefix, fn, 0, 0, cb_data);
|
||||
prefix, NULL, fn, 0, 0, cb_data);
|
||||
}
|
||||
|
||||
int refs_for_each_fullref_in(struct ref_store *refs, const char *prefix,
|
||||
const char **exclude_patterns,
|
||||
each_ref_fn fn, void *cb_data)
|
||||
{
|
||||
return do_for_each_ref(refs, prefix, fn, 0, 0, cb_data);
|
||||
return do_for_each_ref(refs, prefix, exclude_patterns, fn, 0, 0, cb_data);
|
||||
}
|
||||
|
||||
int for_each_replace_ref(struct repository *r, each_repo_ref_fn fn, void *cb_data)
|
||||
@ -1654,20 +1684,21 @@ int for_each_replace_ref(struct repository *r, each_repo_ref_fn fn, void *cb_dat
|
||||
DO_FOR_EACH_INCLUDE_BROKEN, cb_data);
|
||||
}
|
||||
|
||||
int for_each_namespaced_ref(each_ref_fn fn, void *cb_data)
|
||||
int for_each_namespaced_ref(const char **exclude_patterns,
|
||||
each_ref_fn fn, void *cb_data)
|
||||
{
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
int ret;
|
||||
strbuf_addf(&buf, "%srefs/", get_git_namespace());
|
||||
ret = do_for_each_ref(get_main_ref_store(the_repository),
|
||||
buf.buf, fn, 0, 0, cb_data);
|
||||
buf.buf, exclude_patterns, fn, 0, 0, cb_data);
|
||||
strbuf_release(&buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int refs_for_each_rawref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
|
||||
{
|
||||
return do_for_each_ref(refs, "", fn, 0,
|
||||
return do_for_each_ref(refs, "", NULL, fn, 0,
|
||||
DO_FOR_EACH_INCLUDE_BROKEN, cb_data);
|
||||
}
|
||||
|
||||
@ -1737,6 +1768,7 @@ static void find_longest_prefixes(struct string_list *out,
|
||||
int refs_for_each_fullref_in_prefixes(struct ref_store *ref_store,
|
||||
const char *namespace,
|
||||
const char **patterns,
|
||||
const char **exclude_patterns,
|
||||
each_ref_fn fn, void *cb_data)
|
||||
{
|
||||
struct string_list prefixes = STRING_LIST_INIT_DUP;
|
||||
@ -1752,7 +1784,8 @@ int refs_for_each_fullref_in_prefixes(struct ref_store *ref_store,
|
||||
|
||||
for_each_string_list_item(prefix, &prefixes) {
|
||||
strbuf_addstr(&buf, prefix->string);
|
||||
ret = refs_for_each_fullref_in(ref_store, buf.buf, fn, cb_data);
|
||||
ret = refs_for_each_fullref_in(ref_store, buf.buf,
|
||||
exclude_patterns, fn, cb_data);
|
||||
if (ret)
|
||||
break;
|
||||
strbuf_setlen(&buf, namespace_len);
|
||||
@ -2407,7 +2440,7 @@ int refs_verify_refname_available(struct ref_store *refs,
|
||||
strbuf_addstr(&dirname, refname + dirname.len);
|
||||
strbuf_addch(&dirname, '/');
|
||||
|
||||
iter = refs_ref_iterator_begin(refs, dirname.buf, 0,
|
||||
iter = refs_ref_iterator_begin(refs, dirname.buf, NULL, 0,
|
||||
DO_FOR_EACH_INCLUDE_BROKEN);
|
||||
while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
|
||||
if (skip &&
|
||||
|
Reference in New Issue
Block a user