Skip to content

Commit

Permalink
Merge branch 'tb/refs-exclusion-and-packed-refs'
Browse files Browse the repository at this point in the history
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`
  • Loading branch information
gitster committed Jul 21, 2023
2 parents cba07a3 + 98456ef commit 39fe402
Show file tree
Hide file tree
Showing 26 changed files with 579 additions and 106 deletions.
6 changes: 6 additions & 0 deletions Documentation/git-for-each-ref.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ SYNOPSIS
[--points-at=<object>]
[--merged[=<object>]] [--no-merged[=<object>]]
[--contains[=<object>]] [--no-contains[=<object>]]
[--exclude=<pattern> ...]

DESCRIPTION
-----------
Expand Down Expand Up @@ -102,6 +103,11 @@ OPTIONS
Do not print a newline after formatted refs where the format expands
to the empty string.

--exclude=<pattern>::
If one or more patterns are given, only refs which do not match
any excluded pattern(s) are shown. Matching is done using the
same rules as `<pattern>` above.

FIELD NAMES
-----------

Expand Down
4 changes: 2 additions & 2 deletions builtin/branch.c
Original file line number Diff line number Diff line change
Expand Up @@ -701,7 +701,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
int reflog = 0, quiet = 0, icase = 0, force = 0,
recurse_submodules_explicit = 0;
enum branch_track track;
struct ref_filter filter;
struct ref_filter filter = REF_FILTER_INIT;
static struct ref_sorting *sorting;
struct string_list sorting_options = STRING_LIST_INIT_DUP;
struct ref_format format = REF_FORMAT_INIT;
Expand Down Expand Up @@ -759,7 +759,6 @@ int cmd_branch(int argc, const char **argv, const char *prefix)

setup_ref_filter_porcelain_msg();

memset(&filter, 0, sizeof(filter));
filter.kind = FILTER_REFS_BRANCHES;
filter.abbrev = -1;

Expand Down Expand Up @@ -855,6 +854,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
print_columns(&output, colopts, NULL);
string_list_clear(&output, 0);
ref_sorting_release(sorting);
ref_filter_clear(&filter);
return 0;
} else if (edit_description) {
const char *branch_name;
Expand Down
7 changes: 3 additions & 4 deletions builtin/for-each-ref.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
struct string_list sorting_options = STRING_LIST_INIT_DUP;
int maxcount = 0, icase = 0, omit_empty = 0;
struct ref_array array;
struct ref_filter filter;
struct ref_filter filter = REF_FILTER_INIT;
struct ref_format format = REF_FORMAT_INIT;
struct strbuf output = STRBUF_INIT;
struct strbuf err = STRBUF_INIT;
Expand All @@ -47,6 +47,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
OPT_INTEGER( 0 , "count", &maxcount, N_("show only <n> matched refs")),
OPT_STRING( 0 , "format", &format.format, N_("format"), N_("format to use for the output")),
OPT__COLOR(&format.use_color, N_("respect format colors")),
OPT_REF_FILTER_EXCLUDE(&filter),
OPT_REF_SORT(&sorting_options),
OPT_CALLBACK(0, "points-at", &filter.points_at,
N_("object"), N_("print only refs which points at the given object"),
Expand All @@ -61,7 +62,6 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
};

memset(&array, 0, sizeof(array));
memset(&filter, 0, sizeof(filter));

format.format = "%(objectname) %(objecttype)\t%(refname)";

Expand Down Expand Up @@ -121,8 +121,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
strbuf_release(&err);
strbuf_release(&output);
ref_array_clear(&array);
free_commit_list(filter.with_commit);
free_commit_list(filter.no_commit);
ref_filter_clear(&filter);
ref_sorting_release(sorting);
strvec_clear(&vec);
return 0;
Expand Down
8 changes: 5 additions & 3 deletions builtin/receive-pack.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ static struct object_id push_cert_oid;
static struct signature_check sigcheck;
static const char *push_cert_nonce;
static const char *cert_nonce_seed;
static struct string_list hidden_refs = STRING_LIST_INIT_DUP;
static struct strvec hidden_refs = STRVEC_INIT;

static const char *NONCE_UNSOLICITED = "UNSOLICITED";
static const char *NONCE_BAD = "BAD";
Expand Down Expand Up @@ -338,7 +338,9 @@ static void write_head_info(void)
{
static struct oidset seen = OIDSET_INIT;

for_each_ref(show_ref_cb, &seen);
refs_for_each_fullref_in(get_main_ref_store(the_repository), "",
hidden_refs_to_excludes(&hidden_refs),
show_ref_cb, &seen);
for_each_alternate_ref(show_one_alternate_ref, &seen);
oidset_clear(&seen);
if (!sent_capabilities)
Expand Down Expand Up @@ -2620,7 +2622,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
packet_flush(1);
oid_array_clear(&shallow);
oid_array_clear(&ref);
string_list_clear(&hidden_refs, 0);
strvec_clear(&hidden_refs);
free((void *)push_cert_nonce);
return 0;
}
4 changes: 2 additions & 2 deletions builtin/tag.c
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
struct msg_arg msg = { .buf = STRBUF_INIT };
struct ref_transaction *transaction;
struct strbuf err = STRBUF_INIT;
struct ref_filter filter;
struct ref_filter filter = REF_FILTER_INIT;
struct ref_sorting *sorting;
struct string_list sorting_options = STRING_LIST_INIT_DUP;
struct ref_format format = REF_FORMAT_INIT;
Expand Down Expand Up @@ -504,7 +504,6 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
git_config(git_tag_config, &sorting_options);

memset(&opt, 0, sizeof(opt));
memset(&filter, 0, sizeof(filter));
filter.lines = -1;
opt.sign = -1;

Expand Down Expand Up @@ -660,6 +659,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)

cleanup:
ref_sorting_release(sorting);
ref_filter_clear(&filter);
strbuf_release(&buf);
strbuf_release(&ref);
strbuf_release(&reflog_msg);
Expand Down
2 changes: 1 addition & 1 deletion http-backend.c
Original file line number Diff line number Diff line change
Expand Up @@ -558,7 +558,7 @@ static void get_info_refs(struct strbuf *hdr, char *arg UNUSED)

} else {
select_getanyfile(hdr);
for_each_namespaced_ref(show_text_ref, &buf);
for_each_namespaced_ref(NULL, show_text_ref, &buf);
send_strbuf(hdr, "text/plain", &buf);
}
strbuf_release(&buf);
Expand Down
7 changes: 4 additions & 3 deletions ls-refs.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ struct ls_refs_data {
unsigned symrefs;
struct strvec prefixes;
struct strbuf buf;
struct string_list hidden_refs;
struct strvec hidden_refs;
unsigned unborn : 1;
};

Expand Down Expand Up @@ -156,7 +156,7 @@ int ls_refs(struct repository *r, struct packet_reader *request)
memset(&data, 0, sizeof(data));
strvec_init(&data.prefixes);
strbuf_init(&data.buf, 0);
string_list_init_dup(&data.hidden_refs);
strvec_init(&data.hidden_refs);

git_config(ls_refs_config, &data);

Expand Down Expand Up @@ -194,11 +194,12 @@ int ls_refs(struct repository *r, struct packet_reader *request)
strvec_push(&data.prefixes, "");
refs_for_each_fullref_in_prefixes(get_main_ref_store(r),
get_git_namespace(), data.prefixes.v,
hidden_refs_to_excludes(&data.hidden_refs),
send_ref, &data);
packet_fflush(stdout);
strvec_clear(&data.prefixes);
strbuf_release(&data.buf);
string_list_clear(&data.hidden_refs, 0);
strvec_clear(&data.hidden_refs);
return 0;
}

Expand Down
66 changes: 50 additions & 16 deletions ref-filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -2225,12 +2225,12 @@ static int get_ref_atom_value(struct ref_array_item *ref, int atom,
* matches a pattern "refs/heads/mas") or a wildcard (e.g. the same ref
* matches "refs/heads/mas*", too).
*/
static int match_pattern(const struct ref_filter *filter, const char *refname)
static int match_pattern(const char **patterns, const char *refname,
int ignore_case)
{
const char **patterns = filter->name_patterns;
unsigned flags = 0;

if (filter->ignore_case)
if (ignore_case)
flags |= WM_CASEFOLD;

/*
Expand All @@ -2255,13 +2255,13 @@ static int match_pattern(const struct ref_filter *filter, const char *refname)
* matches a pattern "refs/heads/" but not "refs/heads/m") or a
* wildcard (e.g. the same ref matches "refs/heads/m*", too).
*/
static int match_name_as_path(const struct ref_filter *filter, const char *refname)
static int match_name_as_path(const char **pattern, const char *refname,
int ignore_case)
{
const char **pattern = filter->name_patterns;
int namelen = strlen(refname);
unsigned flags = WM_PATHNAME;

if (filter->ignore_case)
if (ignore_case)
flags |= WM_CASEFOLD;

for (; *pattern; pattern++) {
Expand All @@ -2286,8 +2286,20 @@ static int filter_pattern_match(struct ref_filter *filter, const char *refname)
if (!*filter->name_patterns)
return 1; /* No pattern always matches */
if (filter->match_as_path)
return match_name_as_path(filter, refname);
return match_pattern(filter, refname);
return match_name_as_path(filter->name_patterns, refname,
filter->ignore_case);
return match_pattern(filter->name_patterns, refname,
filter->ignore_case);
}

static int filter_exclude_match(struct ref_filter *filter, const char *refname)
{
if (!filter->exclude.nr)
return 0;
if (filter->match_as_path)
return match_name_as_path(filter->exclude.v, refname,
filter->ignore_case);
return match_pattern(filter->exclude.v, refname, filter->ignore_case);
}

/*
Expand Down Expand Up @@ -2319,11 +2331,13 @@ static int for_each_fullref_in_pattern(struct ref_filter *filter,

if (!filter->name_patterns[0]) {
/* no patterns; we have to look at everything */
return for_each_fullref_in("", cb, cb_data);
return refs_for_each_fullref_in(get_main_ref_store(the_repository),
"", filter->exclude.v, cb, cb_data);
}

return refs_for_each_fullref_in_prefixes(get_main_ref_store(the_repository),
NULL, filter->name_patterns,
filter->exclude.v,
cb, cb_data);
}

Expand Down Expand Up @@ -2457,6 +2471,9 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,
if (!filter_pattern_match(filter, refname))
return 0;

if (filter_exclude_match(filter, refname))
return 0;

if (filter->points_at.nr && !match_points_at(&filter->points_at, oid, refname))
return 0;

Expand Down Expand Up @@ -2539,13 +2556,13 @@ void ref_array_clear(struct ref_array *array)
#define EXCLUDE_REACHED 0
#define INCLUDE_REACHED 1
static void reach_filter(struct ref_array *array,
struct commit_list *check_reachable,
struct commit_list **check_reachable,
int include_reached)
{
int i, old_nr;
struct commit **to_clear;

if (!check_reachable)
if (!*check_reachable)
return;

CALLOC_ARRAY(to_clear, array->nr);
Expand All @@ -2555,7 +2572,7 @@ static void reach_filter(struct ref_array *array,
}

tips_reachable_from_bases(the_repository,
check_reachable,
*check_reachable,
to_clear, array->nr,
UNINTERESTING);

Expand All @@ -2576,8 +2593,8 @@ static void reach_filter(struct ref_array *array,

clear_commit_marks_many(old_nr, to_clear, ALL_REV_FLAGS);

while (check_reachable) {
struct commit *merge_commit = pop_commit(&check_reachable);
while (*check_reachable) {
struct commit *merge_commit = pop_commit(check_reachable);
clear_commit_marks(merge_commit, ALL_REV_FLAGS);
}

Expand Down Expand Up @@ -2674,8 +2691,8 @@ int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int
clear_contains_cache(&ref_cbdata.no_contains_cache);

/* Filters that need revision walking */
reach_filter(array, filter->reachable_from, INCLUDE_REACHED);
reach_filter(array, filter->unreachable_from, EXCLUDE_REACHED);
reach_filter(array, &filter->reachable_from, INCLUDE_REACHED);
reach_filter(array, &filter->unreachable_from, EXCLUDE_REACHED);

save_commit_buffer = save_commit_buffer_orig;
return ret;
Expand Down Expand Up @@ -2987,3 +3004,20 @@ int parse_opt_merge_filter(const struct option *opt, const char *arg, int unset)

return 0;
}

void ref_filter_init(struct ref_filter *filter)
{
struct ref_filter blank = REF_FILTER_INIT;
memcpy(filter, &blank, sizeof(blank));
}

void ref_filter_clear(struct ref_filter *filter)
{
strvec_clear(&filter->exclude);
oid_array_clear(&filter->points_at);
free_commit_list(filter->with_commit);
free_commit_list(filter->no_commit);
free_commit_list(filter->reachable_from);
free_commit_list(filter->unreachable_from);
ref_filter_init(filter);
}
12 changes: 12 additions & 0 deletions ref-filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "refs.h"
#include "commit.h"
#include "string-list.h"
#include "strvec.h"

/* Quoting styles */
#define QUOTE_NONE 0
Expand Down Expand Up @@ -59,6 +60,7 @@ struct ref_array {

struct ref_filter {
const char **name_patterns;
struct strvec exclude;
struct oid_array points_at;
struct commit_list *with_commit;
struct commit_list *no_commit;
Expand Down Expand Up @@ -92,6 +94,10 @@ struct ref_format {
struct string_list bases;
};

#define REF_FILTER_INIT { \
.points_at = OID_ARRAY_INIT, \
.exclude = STRVEC_INIT, \
}
#define REF_FORMAT_INIT { \
.use_color = -1, \
.bases = STRING_LIST_INIT_DUP, \
Expand All @@ -109,6 +115,9 @@ struct ref_format {
#define OPT_REF_SORT(var) \
OPT_STRING_LIST(0, "sort", (var), \
N_("key"), N_("field name to sort on"))
#define OPT_REF_FILTER_EXCLUDE(var) \
OPT_STRVEC(0, "exclude", &(var)->exclude, \
N_("pattern"), N_("exclude refs which match pattern"))

/*
* API for filtering a set of refs. Based on the type of refs the user
Expand Down Expand Up @@ -167,4 +176,7 @@ void filter_ahead_behind(struct repository *r,
struct ref_format *format,
struct ref_array *array);

void ref_filter_init(struct ref_filter *filter);
void ref_filter_clear(struct ref_filter *filter);

#endif /* REF_FILTER_H */
Loading

0 comments on commit 39fe402

Please sign in to comment.