Merge branch 'ps/refs-for-each' into jch

Code refactoring around refs-for-each-* API functions.

* ps/refs-for-each:
  refs: replace `refs_for_each_fullref_in()`
  refs: replace `refs_for_each_namespaced_ref()`
  refs: replace `refs_for_each_glob_ref()`
  refs: replace `refs_for_each_glob_ref_in()`
  refs: replace `refs_for_each_rawref_in()`
  refs: replace `refs_for_each_rawref()`
  refs: replace `refs_for_each_ref_in()`
  refs: improve verification for-each-ref options
  refs: generalize `refs_for_each_fullref_in_prefixes()`
  refs: generalize `refs_for_each_namespaced_ref()`
  refs: speed up `refs_for_each_glob_ref_in()`
  refs: introduce `refs_for_each_ref_ext`
  refs: rename `each_ref_fn`
  refs: rename `do_for_each_ref_flags`
  refs: move `do_for_each_ref_flags` further up
  refs: move `refs_head_ref_namespaced()`
  refs: remove unused `refs_for_each_include_root_ref()`
This commit is contained in:
Junio C Hamano
2026-02-27 15:14:15 -08:00
28 changed files with 469 additions and 373 deletions

View File

@@ -473,8 +473,12 @@ static int register_ref(const struct reference *ref, void *cb_data UNUSED)
static int read_bisect_refs(void)
{
return refs_for_each_ref_in(get_main_ref_store(the_repository),
"refs/bisect/", register_ref, NULL);
struct refs_for_each_ref_options opts = {
.prefix = "refs/bisect/",
.trim_prefix = strlen("refs/bisect/"),
};
return refs_for_each_ref_ext(get_main_ref_store(the_repository),
register_ref, NULL, &opts);
}
static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
@@ -1186,13 +1190,15 @@ static int mark_for_removal(const struct reference *ref, void *cb_data)
int bisect_clean_state(void)
{
struct refs_for_each_ref_options opts = {
.prefix = "refs/bisect/",
};
int result = 0;
/* There may be some refs packed during bisection */
struct string_list refs_for_removal = STRING_LIST_INIT_DUP;
refs_for_each_fullref_in(get_main_ref_store(the_repository),
"refs/bisect/", NULL, mark_for_removal,
&refs_for_removal);
refs_for_each_ref_ext(get_main_ref_store(the_repository),
mark_for_removal, &refs_for_removal, &opts);
string_list_append(&refs_for_removal, "BISECT_HEAD");
string_list_append(&refs_for_removal, "BISECT_EXPECTED_REV");
result = refs_delete_refs(get_main_ref_store(the_repository),

View File

@@ -422,13 +422,17 @@ static void bisect_status(struct bisect_state *state,
{
char *bad_ref = xstrfmt("refs/bisect/%s", terms->term_bad);
char *good_glob = xstrfmt("%s-*", terms->term_good);
struct refs_for_each_ref_options opts = {
.pattern = good_glob,
.prefix = "refs/bisect/",
.trim_prefix = strlen("refs/bisect/"),
};
if (refs_ref_exists(get_main_ref_store(the_repository), bad_ref))
state->nr_bad = 1;
refs_for_each_glob_ref_in(get_main_ref_store(the_repository), inc_nr,
good_glob, "refs/bisect/",
(void *) &state->nr_good);
refs_for_each_ref_ext(get_main_ref_store(the_repository),
inc_nr, &state->nr_good, &opts);
free(good_glob);
free(bad_ref);
@@ -562,6 +566,10 @@ static int add_bisect_ref(const struct reference *ref, void *cb)
static int prepare_revs(struct bisect_terms *terms, struct rev_info *revs)
{
struct refs_for_each_ref_options opts = {
.prefix = "refs/bisect/",
.trim_prefix = strlen("refs/bisect/"),
};
int res = 0;
struct add_bisect_ref_data cb = { revs };
char *good = xstrfmt("%s-*", terms->term_good);
@@ -581,11 +589,16 @@ static int prepare_revs(struct bisect_terms *terms, struct rev_info *revs)
reset_revision_walk();
repo_init_revisions(the_repository, revs, NULL);
setup_revisions(0, NULL, revs, NULL);
refs_for_each_glob_ref_in(get_main_ref_store(the_repository),
add_bisect_ref, bad, "refs/bisect/", &cb);
opts.pattern = bad;
refs_for_each_ref_ext(get_main_ref_store(the_repository),
add_bisect_ref, &cb, &opts);
cb.object_flags = UNINTERESTING;
refs_for_each_glob_ref_in(get_main_ref_store(the_repository),
add_bisect_ref, good, "refs/bisect/", &cb);
opts.pattern = good;
refs_for_each_ref_ext(get_main_ref_store(the_repository),
add_bisect_ref, &cb, &opts);
if (prepare_revision_walk(revs))
res = error(_("revision walk setup failed"));
@@ -1191,10 +1204,14 @@ static int verify_good(const struct bisect_terms *terms, const char *command)
char *good_glob = xstrfmt("%s-*", terms->term_good);
int no_checkout = refs_ref_exists(get_main_ref_store(the_repository),
"BISECT_HEAD");
struct refs_for_each_ref_options opts = {
.pattern = good_glob,
.prefix = "refs/bisect/",
.trim_prefix = strlen("refs/bisect/"),
};
refs_for_each_glob_ref_in(get_main_ref_store(the_repository),
get_first_good, good_glob, "refs/bisect/",
&good_rev);
refs_for_each_ref_ext(get_main_ref_store(the_repository),
get_first_good, &good_rev, &opts);
free(good_glob);
if (refs_read_ref(get_main_ref_store(the_repository), no_checkout ? "BISECT_HEAD" : "HEAD", &current_rev))

View File

@@ -641,6 +641,9 @@ int cmd_describe(int argc,
const char *prefix,
struct repository *repo UNUSED )
{
struct refs_for_each_ref_options for_each_ref_opts = {
.flags = REFS_FOR_EACH_INCLUDE_BROKEN,
};
int contains = 0;
struct option options[] = {
OPT_BOOL(0, "contains", &contains, N_("find the tag that comes after the commit")),
@@ -738,8 +741,8 @@ int cmd_describe(int argc,
}
hashmap_init(&names, commit_name_neq, NULL, 0);
refs_for_each_rawref(get_main_ref_store(the_repository), get_name,
NULL);
refs_for_each_ref_ext(get_main_ref_store(the_repository),
get_name, NULL, &for_each_ref_opts);
if (!hashmap_get_size(&names) && !always)
die(_("No names found, cannot describe anything."));

View File

@@ -1541,6 +1541,9 @@ static void add_negotiation_tips(struct git_transport_options *smart_options)
for (i = 0; i < negotiation_tip.nr; i++) {
const char *s = negotiation_tip.items[i].string;
struct refs_for_each_ref_options opts = {
.pattern = s,
};
int old_nr;
if (!has_glob_specials(s)) {
struct object_id oid;
@@ -1552,8 +1555,8 @@ static void add_negotiation_tips(struct git_transport_options *smart_options)
continue;
}
old_nr = oids->nr;
refs_for_each_glob_ref(get_main_ref_store(the_repository),
add_oid, s, oids);
refs_for_each_ref_ext(get_main_ref_store(the_repository),
add_oid, oids, &opts);
if (old_nr == oids->nr)
warning("ignoring --negotiation-tip=%s because it does not match any refs",
s);

View File

@@ -582,6 +582,9 @@ static int fsck_handle_ref(const struct reference *ref, void *cb_data UNUSED)
static void snapshot_refs(struct snapshot *snap, int argc, const char **argv)
{
struct refs_for_each_ref_options opts = {
.flags = REFS_FOR_EACH_INCLUDE_BROKEN,
};
struct worktree **worktrees, **p;
const char *head_points_at;
struct object_id head_oid;
@@ -607,8 +610,8 @@ static void snapshot_refs(struct snapshot *snap, int argc, const char **argv)
return;
}
refs_for_each_rawref(get_main_ref_store(the_repository),
snapshot_ref, snap);
refs_for_each_ref_ext(get_main_ref_store(the_repository),
snapshot_ref, snap, &opts);
worktrees = get_worktrees();
for (p = worktrees; *p; p++) {

View File

@@ -343,9 +343,9 @@ static void show_one_alternate_ref(const struct object_id *oid,
static void write_head_info(void)
{
struct refs_for_each_ref_options opts = { 0 };
static struct oidset seen = OIDSET_INIT;
struct strvec excludes_vector = STRVEC_INIT;
const char **exclude_patterns;
/*
* We need access to the reference names both with and without their
@@ -353,12 +353,12 @@ static void write_head_info(void)
* thus have to adapt exclude patterns to carry the namespace prefix
* ourselves.
*/
exclude_patterns = get_namespaced_exclude_patterns(
opts.exclude_patterns = get_namespaced_exclude_patterns(
hidden_refs_to_excludes(&hidden_refs),
get_git_namespace(), &excludes_vector);
refs_for_each_fullref_in(get_main_ref_store(the_repository), "",
exclude_patterns, show_ref_cb, &seen);
refs_for_each_ref_ext(get_main_ref_store(the_repository),
show_ref_cb, &seen, &opts);
odb_for_each_alternate_ref(the_repository->objects,
show_one_alternate_ref, &seen);

View File

@@ -912,6 +912,9 @@ static int mv(int argc, const char **argv, const char *prefix,
old_remote_context.buf);
if (refspecs_need_update) {
struct refs_for_each_ref_options opts = {
.flags = REFS_FOR_EACH_INCLUDE_BROKEN,
};
rename.transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
0, &err);
if (!rename.transaction)
@@ -923,9 +926,10 @@ static int mv(int argc, const char **argv, const char *prefix,
strbuf_reset(&buf);
strbuf_addf(&buf, "refs/remotes/%s/", rename.old_name);
opts.prefix = buf.buf;
result = refs_for_each_rawref_in(get_main_ref_store(the_repository), buf.buf,
rename_one_ref, &rename);
result = refs_for_each_ref_ext(get_main_ref_store(the_repository),
rename_one_ref, &rename, &opts);
if (result < 0)
die(_("queueing remote ref renames failed: %s"), rename.err->buf);

View File

@@ -613,13 +613,22 @@ static int opt_with_value(const char *arg, const char *opt, const char **value)
static void handle_ref_opt(const char *pattern, const char *prefix)
{
if (pattern)
refs_for_each_glob_ref_in(get_main_ref_store(the_repository),
show_reference, pattern, prefix,
NULL);
else
refs_for_each_ref_in(get_main_ref_store(the_repository),
prefix, show_reference, NULL);
if (pattern) {
struct refs_for_each_ref_options opts = {
.pattern = pattern,
.prefix = prefix,
.trim_prefix = prefix ? strlen(prefix) : 0,
};
refs_for_each_ref_ext(get_main_ref_store(the_repository),
show_reference, NULL, &opts);
} else {
struct refs_for_each_ref_options opts = {
.prefix = prefix,
.trim_prefix = strlen(prefix),
};
refs_for_each_ref_ext(get_main_ref_store(the_repository),
show_reference, NULL, &opts);
}
clear_ref_exclusions(&ref_excludes);
}
@@ -931,14 +940,13 @@ int cmd_rev_parse(int argc,
continue;
}
if (!strcmp(arg, "--bisect")) {
refs_for_each_fullref_in(get_main_ref_store(the_repository),
"refs/bisect/bad",
NULL, show_reference,
NULL);
refs_for_each_fullref_in(get_main_ref_store(the_repository),
"refs/bisect/good",
NULL, anti_reference,
NULL);
struct refs_for_each_ref_options opts = { 0 };
opts.prefix = "refs/bisect/bad";
refs_for_each_ref_ext(get_main_ref_store(the_repository),
show_reference, NULL, &opts);
opts.prefix = "refs/bisect/good";
refs_for_each_ref_ext(get_main_ref_store(the_repository),
anti_reference, NULL, &opts);
continue;
}
if (opt_with_value(arg, "--branches", &arg)) {

View File

@@ -215,14 +215,19 @@ static int cmd_show_ref__patterns(const struct patterns_options *opts,
refs_head_ref(get_main_ref_store(the_repository), show_ref,
&show_ref_data);
if (opts->branches_only || opts->tags_only) {
if (opts->branches_only)
refs_for_each_fullref_in(get_main_ref_store(the_repository),
"refs/heads/", NULL,
show_ref, &show_ref_data);
if (opts->tags_only)
refs_for_each_fullref_in(get_main_ref_store(the_repository),
"refs/tags/", NULL, show_ref,
&show_ref_data);
struct refs_for_each_ref_options for_each_ref_opts = { 0 };
if (opts->branches_only) {
for_each_ref_opts.prefix = "refs/heads/";
refs_for_each_ref_ext(get_main_ref_store(the_repository),
show_ref, &show_ref_data, &for_each_ref_opts);
}
if (opts->tags_only) {
for_each_ref_opts.prefix = "refs/tags/";
refs_for_each_ref_ext(get_main_ref_store(the_repository),
show_ref, &show_ref_data, &for_each_ref_opts);
}
} else {
refs_for_each_ref(get_main_ref_store(the_repository),
show_ref, &show_ref_data);

View File

@@ -293,11 +293,14 @@ static int next_flush(int stateless_rpc, int count)
static void mark_tips(struct fetch_negotiator *negotiator,
const struct oid_array *negotiation_tips)
{
struct refs_for_each_ref_options opts = {
.flags = REFS_FOR_EACH_INCLUDE_BROKEN,
};
int i;
if (!negotiation_tips) {
refs_for_each_rawref(get_main_ref_store(the_repository),
rev_list_insert_ref_oid, negotiator);
refs_for_each_ref_ext(get_main_ref_store(the_repository),
rev_list_insert_ref_oid, negotiator, &opts);
return;
}
@@ -793,8 +796,12 @@ static void mark_complete_and_common_ref(struct fetch_negotiator *negotiator,
*/
trace2_region_enter("fetch-pack", "mark_complete_local_refs", NULL);
if (!args->deepen) {
refs_for_each_rawref(get_main_ref_store(the_repository),
mark_complete_oid, NULL);
struct refs_for_each_ref_options opts = {
.flags = REFS_FOR_EACH_INCLUDE_BROKEN,
};
refs_for_each_ref_ext(get_main_ref_store(the_repository),
mark_complete_oid, NULL, &opts);
for_each_cached_alternate(NULL, mark_alternate_complete);
if (cutoff)
mark_recent_complete_commits(args, cutoff);

View File

@@ -565,9 +565,13 @@ static void get_info_refs(struct strbuf *hdr, char *arg UNUSED)
run_service(argv, 0);
} else {
struct refs_for_each_ref_options opts = {
.namespace = get_git_namespace(),
};
select_getanyfile(hdr);
refs_for_each_namespaced_ref(get_main_ref_store(the_repository),
NULL, show_text_ref, &buf);
refs_for_each_ref_ext(get_main_ref_store(the_repository),
show_text_ref, &buf, &opts);
send_strbuf(hdr, "text/plain", &buf);
}
strbuf_release(&buf);

View File

@@ -160,6 +160,7 @@ static int ls_refs_config(const char *var, const char *value,
int ls_refs(struct repository *r, struct packet_reader *request)
{
struct refs_for_each_ref_options opts = { 0 };
struct ls_refs_data data;
memset(&data, 0, sizeof(data));
@@ -201,10 +202,12 @@ int ls_refs(struct repository *r, struct packet_reader *request)
send_possibly_unborn_head(&data);
if (!data.prefixes.nr)
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);
opts.exclude_patterns = hidden_refs_to_excludes(&data.hidden_refs);
opts.namespace = get_git_namespace();
refs_for_each_ref_in_prefixes(get_main_ref_store(r), data.prefixes.v,
&opts, send_ref, &data);
packet_fflush(stdout);
strvec_clear(&data.prefixes);
strbuf_release(&data.buf);

View File

@@ -952,8 +952,11 @@ void string_list_add_refs_by_glob(struct string_list *list, const char *glob)
{
assert(list->strdup_strings);
if (has_glob_specials(glob)) {
refs_for_each_glob_ref(get_main_ref_store(the_repository),
string_list_add_one_ref, glob, list);
struct refs_for_each_ref_options opts = {
.pattern = glob,
};
refs_for_each_ref_ext(get_main_ref_store(the_repository),
string_list_add_one_ref, list, &opts);
} else {
struct object_id oid;
if (repo_get_oid(the_repository, glob, &oid))

View File

@@ -3324,8 +3324,9 @@ static const struct string_list *bitmap_preferred_tips(struct repository *r)
}
void for_each_preferred_bitmap_tip(struct repository *repo,
each_ref_fn cb, void *cb_data)
refs_for_each_cb cb, void *cb_data)
{
struct refs_for_each_ref_options opts = { 0 };
struct string_list_item *item;
const struct string_list *preferred_tips;
struct strbuf buf = STRBUF_INIT;
@@ -3335,16 +3336,16 @@ void for_each_preferred_bitmap_tip(struct repository *repo,
return;
for_each_string_list_item(item, preferred_tips) {
const char *pattern = item->string;
opts.prefix = item->string;
if (!ends_with(pattern, "/")) {
if (!ends_with(opts.prefix, "/")) {
strbuf_reset(&buf);
strbuf_addf(&buf, "%s/", pattern);
pattern = buf.buf;
strbuf_addf(&buf, "%s/", opts.prefix);
opts.prefix = buf.buf;
}
refs_for_each_ref_in(get_main_ref_store(repo),
pattern, cb, cb_data);
refs_for_each_ref_ext(get_main_ref_store(repo),
cb, cb_data, &opts);
}
strbuf_release(&buf);

View File

@@ -105,7 +105,7 @@ int for_each_bitmapped_object(struct bitmap_index *bitmap_git,
* "pack.preferBitmapTips" and invoke the callback on each function.
*/
void for_each_preferred_bitmap_tip(struct repository *repo,
each_ref_fn cb, void *cb_data);
refs_for_each_cb cb, void *cb_data);
#define GIT_TEST_PACK_USE_BITMAP_BOUNDARY_TRAVERSAL \
"GIT_TEST_PACK_USE_BITMAP_BOUNDARY_TRAVERSAL"

View File

@@ -2762,7 +2762,7 @@ static int start_ref_iterator_after(struct ref_iterator *iter, const char *marke
return ret;
}
static int for_each_fullref_with_seek(struct ref_filter *filter, each_ref_fn cb,
static int for_each_fullref_with_seek(struct ref_filter *filter, refs_for_each_cb cb,
void *cb_data, unsigned int flags)
{
struct ref_iterator *iter;
@@ -2785,13 +2785,17 @@ static int for_each_fullref_with_seek(struct ref_filter *filter, each_ref_fn cb,
* pattern match, so the callback still has to match each ref individually.
*/
static int for_each_fullref_in_pattern(struct ref_filter *filter,
each_ref_fn cb,
refs_for_each_cb cb,
void *cb_data)
{
struct refs_for_each_ref_options opts = {
.exclude_patterns = filter->exclude.v,
};
if (filter->kind & FILTER_REFS_ROOT_REFS) {
/* In this case, we want to print all refs including root refs. */
return for_each_fullref_with_seek(filter, cb, cb_data,
DO_FOR_EACH_INCLUDE_ROOT_REFS);
REFS_FOR_EACH_INCLUDE_ROOT_REFS);
}
if (!filter->match_as_path) {
@@ -2817,10 +2821,9 @@ static int for_each_fullref_in_pattern(struct ref_filter *filter,
return for_each_fullref_with_seek(filter, cb, cb_data, 0);
}
return refs_for_each_fullref_in_prefixes(get_main_ref_store(the_repository),
NULL, filter->name_patterns,
filter->exclude.v,
cb, cb_data);
return refs_for_each_ref_in_prefixes(get_main_ref_store(the_repository),
filter->name_patterns, &opts,
cb, cb_data);
}
/*
@@ -3284,7 +3287,7 @@ void filter_is_base(struct repository *r,
free(bases);
}
static int do_filter_refs(struct ref_filter *filter, unsigned int type, each_ref_fn fn, void *cb_data)
static int do_filter_refs(struct ref_filter *filter, unsigned int type, refs_for_each_cb fn, void *cb_data)
{
const char *prefix = NULL;
int ret = 0;

287
refs.c
View File

@@ -443,8 +443,8 @@ char *refs_resolve_refdup(struct ref_store *refs,
/* The argument to for_each_filter_refs */
struct for_each_ref_filter {
const char *pattern;
const char *prefix;
each_ref_fn *fn;
size_t trim_prefix;
refs_for_each_cb *fn;
void *cb_data;
};
@@ -474,9 +474,11 @@ static int for_each_filter_refs(const struct reference *ref, void *data)
if (wildmatch(filter->pattern, ref->name, 0))
return 0;
if (filter->prefix) {
if (filter->trim_prefix) {
struct reference skipped = *ref;
skip_prefix(skipped.name, filter->prefix, &skipped.name);
if (strlen(skipped.name) <= filter->trim_prefix)
BUG("attempt to trim too many characters");
skipped.name += filter->trim_prefix;
return filter->fn(&skipped, filter->cb_data);
} else {
return filter->fn(ref, filter->cb_data);
@@ -523,25 +525,40 @@ void refs_warn_dangling_symrefs(struct ref_store *refs, FILE *fp,
.indent = indent,
.dry_run = dry_run,
};
refs_for_each_rawref(refs, warn_if_dangling_symref, &data);
struct refs_for_each_ref_options opts = {
.flags = REFS_FOR_EACH_INCLUDE_BROKEN,
};
refs_for_each_ref_ext(refs, warn_if_dangling_symref, &data, &opts);
}
int refs_for_each_tag_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
int refs_for_each_tag_ref(struct ref_store *refs, refs_for_each_cb cb, void *cb_data)
{
return refs_for_each_ref_in(refs, "refs/tags/", fn, cb_data);
struct refs_for_each_ref_options opts = {
.prefix = "refs/tags/",
.trim_prefix = strlen("refs/tags/"),
};
return refs_for_each_ref_ext(refs, cb, cb_data, &opts);
}
int refs_for_each_branch_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
int refs_for_each_branch_ref(struct ref_store *refs, refs_for_each_cb cb, void *cb_data)
{
return refs_for_each_ref_in(refs, "refs/heads/", fn, cb_data);
struct refs_for_each_ref_options opts = {
.prefix = "refs/heads/",
.trim_prefix = strlen("refs/heads/"),
};
return refs_for_each_ref_ext(refs, cb, cb_data, &opts);
}
int refs_for_each_remote_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
int refs_for_each_remote_ref(struct ref_store *refs, refs_for_each_cb cb, void *cb_data)
{
return refs_for_each_ref_in(refs, "refs/remotes/", fn, cb_data);
struct refs_for_each_ref_options opts = {
.prefix = "refs/remotes/",
.trim_prefix = strlen("refs/remotes/"),
};
return refs_for_each_ref_ext(refs, cb, cb_data, &opts);
}
int refs_head_ref_namespaced(struct ref_store *refs, each_ref_fn fn, void *cb_data)
int refs_head_ref_namespaced(struct ref_store *refs, refs_for_each_cb fn, void *cb_data)
{
struct strbuf buf = STRBUF_INIT;
int ret = 0;
@@ -589,42 +606,6 @@ void normalize_glob_ref(struct string_list_item *item, const char *prefix,
strbuf_release(&normalized_pattern);
}
int refs_for_each_glob_ref_in(struct ref_store *refs, each_ref_fn fn,
const char *pattern, const char *prefix, void *cb_data)
{
struct strbuf real_pattern = STRBUF_INIT;
struct for_each_ref_filter filter;
int ret;
if (!prefix && !starts_with(pattern, "refs/"))
strbuf_addstr(&real_pattern, "refs/");
else if (prefix)
strbuf_addstr(&real_pattern, prefix);
strbuf_addstr(&real_pattern, pattern);
if (!has_glob_specials(pattern)) {
/* Append implied '/' '*' if not present. */
strbuf_complete(&real_pattern, '/');
/* No need to check for '*', there is none. */
strbuf_addch(&real_pattern, '*');
}
filter.pattern = real_pattern.buf;
filter.prefix = prefix;
filter.fn = fn;
filter.cb_data = cb_data;
ret = refs_for_each_ref(refs, for_each_filter_refs, &filter);
strbuf_release(&real_pattern);
return ret;
}
int refs_for_each_glob_ref(struct ref_store *refs, each_ref_fn fn,
const char *pattern, void *cb_data)
{
return refs_for_each_glob_ref_in(refs, fn, pattern, NULL, cb_data);
}
const char *prettify_refname(const char *name)
{
if (skip_prefix(name, "refs/heads/", &name) ||
@@ -1787,7 +1768,7 @@ const char *find_descendant_ref(const char *dirname,
return NULL;
}
int refs_head_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
int refs_head_ref(struct ref_store *refs, refs_for_each_cb fn, void *cb_data)
{
struct object_id oid;
int flag;
@@ -1811,7 +1792,7 @@ struct ref_iterator *refs_ref_iterator_begin(
const char *prefix,
const char **exclude_patterns,
int trim,
enum do_for_each_ref_flags flags)
enum refs_for_each_flag flags)
{
struct ref_iterator *iter;
struct strvec normalized_exclude_patterns = STRVEC_INIT;
@@ -1833,14 +1814,14 @@ struct ref_iterator *refs_ref_iterator_begin(
exclude_patterns = normalized_exclude_patterns.v;
}
if (!(flags & DO_FOR_EACH_INCLUDE_BROKEN)) {
if (!(flags & REFS_FOR_EACH_INCLUDE_BROKEN)) {
static int ref_paranoia = -1;
if (ref_paranoia < 0)
ref_paranoia = git_env_bool("GIT_REF_PARANOIA", 1);
if (ref_paranoia) {
flags |= DO_FOR_EACH_INCLUDE_BROKEN;
flags |= DO_FOR_EACH_OMIT_DANGLING_SYMREFS;
flags |= REFS_FOR_EACH_INCLUDE_BROKEN;
flags |= REFS_FOR_EACH_OMIT_DANGLING_SYMREFS;
}
}
@@ -1857,85 +1838,105 @@ struct ref_iterator *refs_ref_iterator_begin(
return iter;
}
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)
{
struct ref_iterator *iter;
if (!refs)
return 0;
iter = refs_ref_iterator_begin(refs, prefix, exclude_patterns, trim,
flags);
return do_for_each_ref_iterator(iter, fn, cb_data);
}
int refs_for_each_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
{
return do_for_each_ref(refs, "", NULL, fn, 0, 0, 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, NULL, fn, strlen(prefix), 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, exclude_patterns, fn, 0, 0, cb_data);
}
int refs_for_each_replace_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
{
const char *git_replace_ref_base = ref_namespace[NAMESPACE_REPLACE].ref;
return do_for_each_ref(refs, git_replace_ref_base, NULL, fn,
strlen(git_replace_ref_base),
DO_FOR_EACH_INCLUDE_BROKEN, cb_data);
}
int refs_for_each_namespaced_ref(struct ref_store *refs,
const char **exclude_patterns,
each_ref_fn fn, void *cb_data)
int refs_for_each_ref_ext(struct ref_store *refs,
refs_for_each_cb cb, void *cb_data,
const struct refs_for_each_ref_options *opts)
{
struct strvec namespaced_exclude_patterns = STRVEC_INIT;
struct strbuf prefix = STRBUF_INIT;
struct strbuf namespaced_prefix = STRBUF_INIT;
struct strbuf real_pattern = STRBUF_INIT;
struct for_each_ref_filter filter;
struct ref_iterator *iter;
size_t trim_prefix = opts->trim_prefix;
const char **exclude_patterns;
const char *prefix;
int ret;
exclude_patterns = get_namespaced_exclude_patterns(exclude_patterns,
get_git_namespace(),
&namespaced_exclude_patterns);
if (!refs)
BUG("no ref store passed");
strbuf_addf(&prefix, "%srefs/", get_git_namespace());
ret = do_for_each_ref(refs, prefix.buf, exclude_patterns, fn, 0, 0, cb_data);
if (opts->trim_prefix) {
size_t prefix_len;
if (!opts->prefix)
BUG("trimming only allowed with a prefix");
prefix_len = strlen(opts->prefix);
if (prefix_len == opts->trim_prefix && opts->prefix[prefix_len - 1] != '/')
BUG("ref pattern must end in a trailing slash when trimming");
}
if (opts->pattern) {
if (!opts->prefix && !starts_with(opts->pattern, "refs/"))
strbuf_addstr(&real_pattern, "refs/");
else if (opts->prefix)
strbuf_addstr(&real_pattern, opts->prefix);
strbuf_addstr(&real_pattern, opts->pattern);
if (!has_glob_specials(opts->pattern)) {
/* Append implied '/' '*' if not present. */
strbuf_complete(&real_pattern, '/');
/* No need to check for '*', there is none. */
strbuf_addch(&real_pattern, '*');
}
filter.pattern = real_pattern.buf;
filter.trim_prefix = opts->trim_prefix;
filter.fn = cb;
filter.cb_data = cb_data;
/*
* We need to trim the prefix in the callback function as the
* pattern is expected to match on the full refname.
*/
trim_prefix = 0;
cb = for_each_filter_refs;
cb_data = &filter;
}
if (opts->namespace) {
strbuf_addstr(&namespaced_prefix, opts->namespace);
if (opts->prefix)
strbuf_addstr(&namespaced_prefix, opts->prefix);
else
strbuf_addstr(&namespaced_prefix, "refs/");
prefix = namespaced_prefix.buf;
exclude_patterns = get_namespaced_exclude_patterns(opts->exclude_patterns,
opts->namespace,
&namespaced_exclude_patterns);
} else {
prefix = opts->prefix ? opts->prefix : "";
exclude_patterns = opts->exclude_patterns;
}
iter = refs_ref_iterator_begin(refs, prefix, exclude_patterns,
trim_prefix, opts->flags);
ret = do_for_each_ref_iterator(iter, cb, cb_data);
strvec_clear(&namespaced_exclude_patterns);
strbuf_release(&prefix);
strbuf_release(&namespaced_prefix);
strbuf_release(&real_pattern);
return ret;
}
int refs_for_each_rawref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
int refs_for_each_ref(struct ref_store *refs, refs_for_each_cb cb, void *cb_data)
{
return refs_for_each_rawref_in(refs, "", fn, cb_data);
struct refs_for_each_ref_options opts = { 0 };
return refs_for_each_ref_ext(refs, cb, cb_data, &opts);
}
int refs_for_each_rawref_in(struct ref_store *refs, const char *prefix,
each_ref_fn fn, void *cb_data)
int refs_for_each_replace_ref(struct ref_store *refs, refs_for_each_cb cb, void *cb_data)
{
return do_for_each_ref(refs, prefix, NULL, fn, 0,
DO_FOR_EACH_INCLUDE_BROKEN, cb_data);
}
int refs_for_each_include_root_refs(struct ref_store *refs, each_ref_fn fn,
void *cb_data)
{
return do_for_each_ref(refs, "", NULL, fn, 0,
DO_FOR_EACH_INCLUDE_ROOT_REFS, cb_data);
const char *git_replace_ref_base = ref_namespace[NAMESPACE_REPLACE].ref;
struct refs_for_each_ref_options opts = {
.prefix = git_replace_ref_base,
.trim_prefix = strlen(git_replace_ref_base),
.flags = REFS_FOR_EACH_INCLUDE_BROKEN,
};
return refs_for_each_ref_ext(refs, cb, cb_data, &opts);
}
static int qsort_strcmp(const void *va, const void *vb)
@@ -1996,40 +1997,31 @@ static void find_longest_prefixes(struct string_list *out,
strbuf_release(&prefix);
}
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)
int refs_for_each_ref_in_prefixes(struct ref_store *ref_store,
const char **prefixes,
const struct refs_for_each_ref_options *opts,
refs_for_each_cb cb, void *cb_data)
{
struct strvec namespaced_exclude_patterns = STRVEC_INIT;
struct string_list prefixes = STRING_LIST_INIT_DUP;
struct string_list longest_prefixes = STRING_LIST_INIT_DUP;
struct string_list_item *prefix;
struct strbuf buf = STRBUF_INIT;
int ret = 0, namespace_len;
int ret = 0;
find_longest_prefixes(&prefixes, patterns);
if (opts->prefix)
BUG("refs_for_each_ref_in_prefixes called with specific prefix");
if (namespace)
strbuf_addstr(&buf, namespace);
namespace_len = buf.len;
find_longest_prefixes(&longest_prefixes, prefixes);
exclude_patterns = get_namespaced_exclude_patterns(exclude_patterns,
namespace,
&namespaced_exclude_patterns);
for_each_string_list_item(prefix, &longest_prefixes) {
struct refs_for_each_ref_options prefix_opts = *opts;
prefix_opts.prefix = prefix->string;
for_each_string_list_item(prefix, &prefixes) {
strbuf_addstr(&buf, prefix->string);
ret = refs_for_each_fullref_in(ref_store, buf.buf,
exclude_patterns, fn, cb_data);
ret = refs_for_each_ref_ext(ref_store, cb, cb_data,
&prefix_opts);
if (ret)
break;
strbuf_setlen(&buf, namespace_len);
}
strvec_clear(&namespaced_exclude_patterns);
string_list_clear(&prefixes, 0);
strbuf_release(&buf);
string_list_clear(&longest_prefixes, 0);
return ret;
}
@@ -2847,7 +2839,7 @@ enum ref_transaction_error refs_verify_refnames_available(struct ref_store *refs
if (!iter)
iter = refs_ref_iterator_begin(refs, dirname.buf, NULL, 0,
DO_FOR_EACH_INCLUDE_BROKEN);
REFS_FOR_EACH_INCLUDE_BROKEN);
else if (ref_iterator_seek(iter, dirname.buf,
REF_ITERATOR_SEEK_SET_PREFIX) < 0)
goto cleanup;
@@ -3293,6 +3285,9 @@ int repo_migrate_ref_storage_format(struct repository *repo,
struct strbuf *errbuf)
{
struct ref_store *old_refs = NULL, *new_refs = NULL;
struct refs_for_each_ref_options for_each_ref_opts = {
.flags = REFS_FOR_EACH_INCLUDE_ROOT_REFS | REFS_FOR_EACH_INCLUDE_BROKEN,
};
struct ref_transaction *transaction = NULL;
struct strbuf new_gitdir = STRBUF_INIT;
struct migration_data data = {
@@ -3376,7 +3371,7 @@ int repo_migrate_ref_storage_format(struct repository *repo,
data.errbuf = errbuf;
/*
* We need to use the internal `do_for_each_ref()` here so that we can
* We need to use `refs_for_each_ref_ext()` here so that we can
* also include broken refs and symrefs. These would otherwise be
* skipped silently.
*
@@ -3386,9 +3381,7 @@ int repo_migrate_ref_storage_format(struct repository *repo,
* allow for a central lock due to its design. It's thus on the user to
* ensure that there are no concurrent writes.
*/
ret = do_for_each_ref(old_refs, "", NULL, migrate_one_ref, 0,
DO_FOR_EACH_INCLUDE_ROOT_REFS | DO_FOR_EACH_INCLUDE_BROKEN,
&data);
ret = refs_for_each_ref_ext(old_refs, migrate_one_ref, &data, &for_each_ref_opts);
if (ret < 0)
goto done;

207
refs.h
View File

@@ -170,7 +170,7 @@ int ref_store_remove_on_disk(struct ref_store *refs, struct strbuf *err);
*
* peel_object(r, oid, &peeled);
*
* with the "oid" value given to the each_ref_fn callback, except
* with the "oid" value given to the refs_for_each_cb callback, except
* that some ref storage may be able to answer the query without
* actually loading the object in memory.
*/
@@ -329,7 +329,7 @@ int check_tag_ref(struct strbuf *sb, const char *name);
struct ref_transaction;
/*
* Bit values set in the flags argument passed to each_ref_fn() and
* Bit values set in the flags argument passed to refs_for_each_cb() and
* stored in ref_iterator::flags. Other bits are for internal use
* only:
*/
@@ -400,7 +400,44 @@ int reference_get_peeled_oid(struct repository *repo,
* argument is only guaranteed to be valid for the duration of a
* single callback invocation.
*/
typedef int each_ref_fn(const struct reference *ref, void *cb_data);
typedef int refs_for_each_cb(const struct reference *ref, void *cb_data);
/*
* These flags are passed to refs_ref_iterator_begin() (and do_for_each_ref(),
* which feeds it).
*/
enum refs_for_each_flag {
/*
* Include broken references in a do_for_each_ref*() iteration, which
* would normally be omitted. This includes both refs that point to
* missing objects (a true repository corruption), ones with illegal
* names (which we prefer not to expose to callers), as well as
* dangling symbolic refs (i.e., those that point to a non-existent
* ref; this is not a corruption, but as they have no valid oid, we
* omit them from normal iteration results).
*/
REFS_FOR_EACH_INCLUDE_BROKEN = (1 << 0),
/*
* Only include per-worktree refs in a do_for_each_ref*() iteration.
* Normally this will be used with a files ref_store, since that's
* where all reference backends will presumably store their
* per-worktree refs.
*/
REFS_FOR_EACH_PER_WORKTREE_ONLY = (1 << 1),
/*
* Omit dangling symrefs from output; this only has an effect with
* INCLUDE_BROKEN, since they are otherwise not included at all.
*/
REFS_FOR_EACH_OMIT_DANGLING_SYMREFS = (1 << 2),
/*
* Include root refs i.e. HEAD and pseudorefs along with the regular
* refs.
*/
REFS_FOR_EACH_INCLUDE_ROOT_REFS = (1 << 3),
};
/*
* The following functions invoke the specified callback function for
@@ -412,70 +449,75 @@ typedef int each_ref_fn(const struct reference *ref, void *cb_data);
* stop the iteration. Returned references are sorted.
*/
int refs_head_ref(struct ref_store *refs,
each_ref_fn fn, void *cb_data);
int refs_for_each_ref(struct ref_store *refs,
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);
int refs_for_each_tag_ref(struct ref_store *refs,
each_ref_fn fn, void *cb_data);
int refs_for_each_branch_ref(struct ref_store *refs,
each_ref_fn fn, void *cb_data);
int refs_for_each_remote_ref(struct ref_store *refs,
each_ref_fn fn, void *cb_data);
int refs_for_each_replace_ref(struct ref_store *refs,
each_ref_fn fn, void *cb_data);
refs_for_each_cb fn, void *cb_data);
int refs_head_ref_namespaced(struct ref_store *refs,
refs_for_each_cb fn, void *cb_data);
/*
* references matching any pattern in "exclude_patterns" are omitted from the
* result set on a best-effort basis.
*/
int refs_for_each_fullref_in(struct ref_store *refs, const char *prefix,
const char **exclude_patterns,
each_ref_fn fn, void *cb_data);
struct refs_for_each_ref_options {
/* Only iterate over references that have this given prefix. */
const char *prefix;
/*
* A globbing pattern that can be used to only yield refs that match.
* If given, refs will be matched against the pattern with
* `wildmatch()`.
*
* If the pattern doesn't contain any globbing characters then it is
* treated as if it was ending with "/" and "*".
*/
const char *pattern;
/*
* If set, only yield refs part of the configured namespace. Exclude
* patterns will be rewritten to apply to the namespace, and the prefix
* will be considered relative to the namespace.
*/
const char *namespace;
/*
* Exclude any references that match any of these patterns on a
* best-effort basis. The caller needs to be prepared for the exclude
* patterns to be ignored.
*
* The array must be terminated with a NULL sentinel value.
*/
const char **exclude_patterns;
/*
* The number of bytes to trim from the refname. Note that the trimmed
* bytes must not cause the reference to become empty. As such, this
* field should typically only be set when one uses a `prefix` ending
* in a slash.
*/
size_t trim_prefix;
/* Flags that change which refs will be included. */
enum refs_for_each_flag flags;
};
int refs_for_each_ref(struct ref_store *refs,
refs_for_each_cb fn, void *cb_data);
int refs_for_each_ref_ext(struct ref_store *refs,
refs_for_each_cb cb, void *cb_data,
const struct refs_for_each_ref_options *opts);
int refs_for_each_tag_ref(struct ref_store *refs,
refs_for_each_cb fn, void *cb_data);
int refs_for_each_branch_ref(struct ref_store *refs,
refs_for_each_cb fn, void *cb_data);
int refs_for_each_remote_ref(struct ref_store *refs,
refs_for_each_cb fn, void *cb_data);
int refs_for_each_replace_ref(struct ref_store *refs,
refs_for_each_cb fn, void *cb_data);
/**
* iterate all refs in "patterns" by partitioning patterns into disjoint sets
* Iterate all refs in "prefixes" by partitioning prefixes into disjoint sets
* and iterating the longest-common prefix of each set.
*
* references matching any pattern in "exclude_patterns" are omitted from the
* result set on a best-effort basis.
*
* callers should be prepared to ignore references that they did not ask for.
*/
int refs_for_each_fullref_in_prefixes(struct ref_store *refs,
const char *namespace,
const char **patterns,
const char **exclude_patterns,
each_ref_fn fn, void *cb_data);
/* iterates all refs that match the specified glob pattern. */
int refs_for_each_glob_ref(struct ref_store *refs, each_ref_fn fn,
const char *pattern, void *cb_data);
int refs_for_each_glob_ref_in(struct ref_store *refs, each_ref_fn fn,
const char *pattern, const char *prefix, void *cb_data);
int refs_head_ref_namespaced(struct ref_store *refs, each_ref_fn fn, void *cb_data);
/*
* references matching any pattern in "exclude_patterns" are omitted from the
* result set on a best-effort basis.
*/
int refs_for_each_namespaced_ref(struct ref_store *refs,
const char **exclude_patterns,
each_ref_fn fn, void *cb_data);
/* can be used to learn about broken ref and symref */
int refs_for_each_rawref(struct ref_store *refs, each_ref_fn fn, void *cb_data);
int refs_for_each_rawref_in(struct ref_store *refs, const char *prefix,
each_ref_fn fn, void *cb_data);
/*
* Iterates over all refs including root refs, i.e. pseudorefs and HEAD.
*/
int refs_for_each_include_root_refs(struct ref_store *refs, each_ref_fn fn,
void *cb_data);
int refs_for_each_ref_in_prefixes(struct ref_store *refs,
const char **prefixes,
const struct refs_for_each_ref_options *opts,
refs_for_each_cb cb, void *cb_data);
/*
* Normalizes partial refs to their fully qualified form.
@@ -1331,43 +1373,6 @@ int repo_migrate_ref_storage_format(struct repository *repo,
*/
struct ref_iterator;
/*
* These flags are passed to refs_ref_iterator_begin() (and do_for_each_ref(),
* which feeds it).
*/
enum do_for_each_ref_flags {
/*
* Include broken references in a do_for_each_ref*() iteration, which
* would normally be omitted. This includes both refs that point to
* missing objects (a true repository corruption), ones with illegal
* names (which we prefer not to expose to callers), as well as
* dangling symbolic refs (i.e., those that point to a non-existent
* ref; this is not a corruption, but as they have no valid oid, we
* omit them from normal iteration results).
*/
DO_FOR_EACH_INCLUDE_BROKEN = (1 << 0),
/*
* Only include per-worktree refs in a do_for_each_ref*() iteration.
* Normally this will be used with a files ref_store, since that's
* where all reference backends will presumably store their
* per-worktree refs.
*/
DO_FOR_EACH_PER_WORKTREE_ONLY = (1 << 1),
/*
* Omit dangling symrefs from output; this only has an effect with
* INCLUDE_BROKEN, since they are otherwise not included at all.
*/
DO_FOR_EACH_OMIT_DANGLING_SYMREFS = (1 << 2),
/*
* Include root refs i.e. HEAD and pseudorefs along with the regular
* refs.
*/
DO_FOR_EACH_INCLUDE_ROOT_REFS = (1 << 3),
};
/*
* Return an iterator that goes over each reference in `refs` for
* which the refname begins with prefix. If trim is non-zero, then
@@ -1377,7 +1382,7 @@ enum do_for_each_ref_flags {
struct ref_iterator *refs_ref_iterator_begin(
struct ref_store *refs,
const char *prefix, const char **exclude_patterns,
int trim, enum do_for_each_ref_flags flags);
int trim, enum refs_for_each_flag flags);
/*
* Advance the iterator to the first or next item and return ITER_OK.
@@ -1426,7 +1431,7 @@ void ref_iterator_free(struct ref_iterator *ref_iterator);
* iterator style.
*/
int do_for_each_ref_iterator(struct ref_iterator *iter,
each_ref_fn fn, void *cb_data);
refs_for_each_cb fn, void *cb_data);
/*
* Git only recognizes a directory as a repository if it contains:

View File

@@ -446,7 +446,7 @@ static struct ref_cache *get_loose_ref_cache(struct files_ref_store *refs,
dir = get_ref_dir(refs->loose->root);
if (flags & DO_FOR_EACH_INCLUDE_ROOT_REFS)
if (flags & REFS_FOR_EACH_INCLUDE_ROOT_REFS)
add_root_refs(refs, dir);
/*
@@ -962,17 +962,17 @@ static int files_ref_iterator_advance(struct ref_iterator *ref_iterator)
int ok;
while ((ok = ref_iterator_advance(iter->iter0)) == ITER_OK) {
if (iter->flags & DO_FOR_EACH_PER_WORKTREE_ONLY &&
if (iter->flags & REFS_FOR_EACH_PER_WORKTREE_ONLY &&
parse_worktree_ref(iter->iter0->ref.name, NULL, NULL,
NULL) != REF_WORKTREE_CURRENT)
continue;
if ((iter->flags & DO_FOR_EACH_OMIT_DANGLING_SYMREFS) &&
if ((iter->flags & REFS_FOR_EACH_OMIT_DANGLING_SYMREFS) &&
(iter->iter0->ref.flags & REF_ISSYMREF) &&
(iter->iter0->ref.flags & REF_ISBROKEN))
continue;
if (!(iter->flags & DO_FOR_EACH_INCLUDE_BROKEN) &&
if (!(iter->flags & REFS_FOR_EACH_INCLUDE_BROKEN) &&
!ref_resolves_to_object(iter->iter0->ref.name,
iter->repo,
iter->iter0->ref.oid,
@@ -1019,7 +1019,7 @@ static struct ref_iterator *files_ref_iterator_begin(
struct ref_iterator *ref_iterator;
unsigned int required_flags = REF_STORE_READ;
if (!(flags & DO_FOR_EACH_INCLUDE_BROKEN))
if (!(flags & REFS_FOR_EACH_INCLUDE_BROKEN))
required_flags |= REF_STORE_ODB;
refs = files_downcast(ref_store, required_flags, "ref_iterator_begin");
@@ -1057,7 +1057,7 @@ static struct ref_iterator *files_ref_iterator_begin(
*/
packed_iter = refs_ref_iterator_begin(
refs->packed_ref_store, prefix, exclude_patterns, 0,
DO_FOR_EACH_INCLUDE_BROKEN);
REFS_FOR_EACH_INCLUDE_BROKEN);
overlay_iter = overlay_ref_iterator_begin(loose_iter, packed_iter);
@@ -3156,6 +3156,9 @@ static int files_transaction_finish_initial(struct files_ref_store *refs,
struct ref_transaction *transaction,
struct strbuf *err)
{
struct refs_for_each_ref_options opts = {
.flags = REFS_FOR_EACH_INCLUDE_BROKEN,
};
size_t i;
int ret = 0;
struct string_list affected_refnames = STRING_LIST_INIT_NODUP;
@@ -3180,8 +3183,8 @@ static int files_transaction_finish_initial(struct files_ref_store *refs,
* so here we really only check that none of the references
* that we are creating already exists.
*/
if (refs_for_each_rawref(&refs->base, ref_present,
&transaction->refnames))
if (refs_for_each_ref_ext(&refs->base, ref_present,
&transaction->refnames, &opts))
BUG("initial ref transaction called with existing refs");
packed_transaction = ref_store_transaction_begin(refs->packed_ref_store,

View File

@@ -423,7 +423,7 @@ struct ref_iterator *prefix_ref_iterator_begin(struct ref_iterator *iter0,
}
int do_for_each_ref_iterator(struct ref_iterator *iter,
each_ref_fn fn, void *cb_data)
refs_for_each_cb fn, void *cb_data)
{
int retval = 0, ok;

View File

@@ -987,11 +987,11 @@ static int packed_ref_iterator_advance(struct ref_iterator *ref_iterator)
const char *refname = iter->base.ref.name;
const char *prefix = iter->prefix;
if (iter->flags & DO_FOR_EACH_PER_WORKTREE_ONLY &&
if (iter->flags & REFS_FOR_EACH_PER_WORKTREE_ONLY &&
!is_per_worktree_ref(iter->base.ref.name))
continue;
if (!(iter->flags & DO_FOR_EACH_INCLUDE_BROKEN) &&
if (!(iter->flags & REFS_FOR_EACH_INCLUDE_BROKEN) &&
!ref_resolves_to_object(iter->base.ref.name, iter->repo,
&iter->oid, iter->flags))
continue;
@@ -1164,7 +1164,7 @@ static struct ref_iterator *packed_ref_iterator_begin(
struct ref_iterator *ref_iterator;
unsigned int required_flags = REF_STORE_READ;
if (!(flags & DO_FOR_EACH_INCLUDE_BROKEN))
if (!(flags & REFS_FOR_EACH_INCLUDE_BROKEN))
required_flags |= REF_STORE_ODB;
refs = packed_downcast(ref_store, required_flags, "ref_iterator_begin");
@@ -1406,7 +1406,7 @@ static enum ref_transaction_error write_with_updates(struct packed_ref_store *re
* of updates is exhausted, leave i set to updates->nr.
*/
iter = packed_ref_iterator_begin(&refs->base, "", NULL,
DO_FOR_EACH_INCLUDE_BROKEN);
REFS_FOR_EACH_INCLUDE_BROKEN);
if ((ok = ref_iterator_advance(iter)) != ITER_OK) {
ref_iterator_free(iter);
iter = NULL;

View File

@@ -629,7 +629,7 @@ static int reftable_ref_iterator_advance(struct ref_iterator *ref_iterator)
* the root refs are to be included. We emulate the same behaviour here.
*/
if (!starts_with(iter->ref.refname, "refs/") &&
!(iter->flags & DO_FOR_EACH_INCLUDE_ROOT_REFS &&
!(iter->flags & REFS_FOR_EACH_INCLUDE_ROOT_REFS &&
is_root_ref(iter->ref.refname))) {
continue;
}
@@ -643,7 +643,7 @@ static int reftable_ref_iterator_advance(struct ref_iterator *ref_iterator)
if (iter->exclude_patterns && should_exclude_current_ref(iter))
continue;
if (iter->flags & DO_FOR_EACH_PER_WORKTREE_ONLY &&
if (iter->flags & REFS_FOR_EACH_PER_WORKTREE_ONLY &&
parse_worktree_ref(iter->ref.refname, NULL, NULL, NULL) !=
REF_WORKTREE_CURRENT)
continue;
@@ -681,12 +681,12 @@ static int reftable_ref_iterator_advance(struct ref_iterator *ref_iterator)
flags |= REF_BAD_NAME | REF_ISBROKEN;
}
if (iter->flags & DO_FOR_EACH_OMIT_DANGLING_SYMREFS &&
if (iter->flags & REFS_FOR_EACH_OMIT_DANGLING_SYMREFS &&
flags & REF_ISSYMREF &&
flags & REF_ISBROKEN)
continue;
if (!(iter->flags & DO_FOR_EACH_INCLUDE_BROKEN) &&
if (!(iter->flags & REFS_FOR_EACH_INCLUDE_BROKEN) &&
!ref_resolves_to_object(iter->ref.refname, refs->base.repo,
&iter->oid, flags))
continue;
@@ -838,7 +838,7 @@ static struct ref_iterator *reftable_be_iterator_begin(struct ref_store *ref_sto
struct reftable_ref_store *refs;
unsigned int required_flags = REF_STORE_READ;
if (!(flags & DO_FOR_EACH_INCLUDE_BROKEN))
if (!(flags & REFS_FOR_EACH_INCLUDE_BROKEN))
required_flags |= REF_STORE_ODB;
refs = reftable_be_downcast(ref_store, required_flags, "ref_iterator_begin");

View File

@@ -1647,7 +1647,7 @@ static void init_all_refs_cb(struct all_refs_cb *cb, struct rev_info *revs,
static void handle_refs(struct ref_store *refs,
struct rev_info *revs, unsigned flags,
int (*for_each)(struct ref_store *, each_ref_fn, void *))
int (*for_each)(struct ref_store *, refs_for_each_cb, void *))
{
struct all_refs_cb cb;
@@ -2731,23 +2731,25 @@ void revision_opts_finish(struct rev_info *revs)
}
}
static int for_each_bisect_ref(struct ref_store *refs, each_ref_fn fn,
static int for_each_bisect_ref(struct ref_store *refs, refs_for_each_cb fn,
void *cb_data, const char *term)
{
struct refs_for_each_ref_options opts = { 0 };
struct strbuf bisect_refs = STRBUF_INIT;
int status;
strbuf_addf(&bisect_refs, "refs/bisect/%s", term);
status = refs_for_each_fullref_in(refs, bisect_refs.buf, NULL, fn, cb_data);
opts.prefix = bisect_refs.buf;
status = refs_for_each_ref_ext(refs, fn, cb_data, &opts);
strbuf_release(&bisect_refs);
return status;
}
static int for_each_bad_bisect_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
static int for_each_bad_bisect_ref(struct ref_store *refs, refs_for_each_cb fn, void *cb_data)
{
return for_each_bisect_ref(refs, fn, cb_data, term_bad);
}
static int for_each_good_bisect_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
static int for_each_good_bisect_ref(struct ref_store *refs, refs_for_each_cb fn, void *cb_data)
{
return for_each_bisect_ref(refs, fn, cb_data, term_good);
}
@@ -2817,10 +2819,13 @@ static int handle_revision_pseudo_opt(struct rev_info *revs,
handle_refs(refs, revs, *flags, refs_for_each_remote_ref);
clear_ref_exclusions(&revs->ref_excludes);
} else if ((argcount = parse_long_opt("glob", argv, &optarg))) {
struct refs_for_each_ref_options opts = {
.pattern = optarg,
};
struct all_refs_cb cb;
init_all_refs_cb(&cb, revs, *flags);
refs_for_each_glob_ref(get_main_ref_store(the_repository),
handle_one_ref, optarg, &cb);
refs_for_each_ref_ext(get_main_ref_store(the_repository),
handle_one_ref, &cb, &opts);
clear_ref_exclusions(&revs->ref_excludes);
return argcount;
} else if ((argcount = parse_long_opt("exclude", argv, &optarg))) {
@@ -2830,34 +2835,46 @@ static int handle_revision_pseudo_opt(struct rev_info *revs,
exclude_hidden_refs(&revs->ref_excludes, optarg);
return argcount;
} else if (skip_prefix(arg, "--branches=", &optarg)) {
struct refs_for_each_ref_options opts = {
.prefix = "refs/heads/",
.trim_prefix = strlen("refs/heads/"),
.pattern = optarg,
};
struct all_refs_cb cb;
if (revs->ref_excludes.hidden_refs_configured)
return error(_("options '%s' and '%s' cannot be used together"),
"--exclude-hidden", "--branches");
init_all_refs_cb(&cb, revs, *flags);
refs_for_each_glob_ref_in(get_main_ref_store(the_repository),
handle_one_ref, optarg,
"refs/heads/", &cb);
refs_for_each_ref_ext(get_main_ref_store(the_repository),
handle_one_ref, &cb, &opts);
clear_ref_exclusions(&revs->ref_excludes);
} else if (skip_prefix(arg, "--tags=", &optarg)) {
struct refs_for_each_ref_options opts = {
.prefix = "refs/tags/",
.trim_prefix = strlen("refs/tags/"),
.pattern = optarg,
};
struct all_refs_cb cb;
if (revs->ref_excludes.hidden_refs_configured)
return error(_("options '%s' and '%s' cannot be used together"),
"--exclude-hidden", "--tags");
init_all_refs_cb(&cb, revs, *flags);
refs_for_each_glob_ref_in(get_main_ref_store(the_repository),
handle_one_ref, optarg,
"refs/tags/", &cb);
refs_for_each_ref_ext(get_main_ref_store(the_repository),
handle_one_ref, &cb, &opts);
clear_ref_exclusions(&revs->ref_excludes);
} else if (skip_prefix(arg, "--remotes=", &optarg)) {
struct refs_for_each_ref_options opts = {
.prefix = "refs/remotes/",
.trim_prefix = strlen("refs/remotes/"),
.pattern = optarg,
};
struct all_refs_cb cb;
if (revs->ref_excludes.hidden_refs_configured)
return error(_("options '%s' and '%s' cannot be used together"),
"--exclude-hidden", "--remotes");
init_all_refs_cb(&cb, revs, *flags);
refs_for_each_glob_ref_in(get_main_ref_store(the_repository),
handle_one_ref, optarg,
"refs/remotes/", &cb);
refs_for_each_ref_ext(get_main_ref_store(the_repository),
handle_one_ref, &cb, &opts);
clear_ref_exclusions(&revs->ref_excludes);
} else if (!strcmp(arg, "--reflog")) {
add_reflogs_to_pending(revs, *flags);

View File

@@ -101,7 +101,7 @@ int is_staging_gitmodules_ok(struct index_state *istate)
}
static int for_each_remote_ref_submodule(const char *submodule,
each_ref_fn fn, void *cb_data)
refs_for_each_cb fn, void *cb_data)
{
return refs_for_each_remote_ref(repo_get_submodule_ref_store(the_repository,
submodule),

View File

@@ -163,17 +163,22 @@ static int each_ref(const struct reference *ref, void *cb_data UNUSED)
static int cmd_for_each_ref(struct ref_store *refs, const char **argv)
{
const char *prefix = notnull(*argv++, "prefix");
return refs_for_each_ref_in(refs, prefix, each_ref, NULL);
struct refs_for_each_ref_options opts = {
.prefix = prefix,
.trim_prefix = strlen(prefix),
};
return refs_for_each_ref_ext(refs, each_ref, NULL, &opts);
}
static int cmd_for_each_ref__exclude(struct ref_store *refs, const char **argv)
{
const char *prefix = notnull(*argv++, "prefix");
const char **exclude_patterns = argv;
struct refs_for_each_ref_options opts = {
.prefix = prefix,
.exclude_patterns = argv,
};
return refs_for_each_fullref_in(refs, prefix, exclude_patterns, each_ref,
NULL);
return refs_for_each_ref_ext(refs, each_ref, NULL, &opts);
}
static int cmd_resolve_ref(struct ref_store *refs, const char **argv)

View File

@@ -607,10 +607,13 @@ static int allow_hidden_refs(enum allow_uor allow_uor)
return !(allow_uor & (ALLOW_TIP_SHA1 | ALLOW_REACHABLE_SHA1));
}
static void for_each_namespaced_ref_1(each_ref_fn fn,
static void for_each_namespaced_ref_1(refs_for_each_cb fn,
struct upload_pack_data *data)
{
const char **excludes = NULL;
struct refs_for_each_ref_options opts = {
.namespace = get_git_namespace(),
};
/*
* If `data->allow_uor` allows fetching hidden refs, we need to
* mark all references (including hidden ones), to check in
@@ -621,10 +624,10 @@ static void for_each_namespaced_ref_1(each_ref_fn fn,
* hidden references.
*/
if (allow_hidden_refs(data->allow_uor))
excludes = hidden_refs_to_excludes(&data->hidden_refs);
opts.exclude_patterns = hidden_refs_to_excludes(&data->hidden_refs);
refs_for_each_namespaced_ref(get_main_ref_store(the_repository),
excludes, fn, data);
refs_for_each_ref_ext(get_main_ref_store(the_repository),
fn, data, &opts);
}

View File

@@ -595,7 +595,7 @@ void strbuf_worktree_ref(const struct worktree *wt,
strbuf_addstr(sb, refname);
}
int other_head_refs(each_ref_fn fn, void *cb_data)
int other_head_refs(refs_for_each_cb fn, void *cb_data)
{
struct worktree **worktrees, **p;
struct strbuf refname = STRBUF_INIT;

View File

@@ -197,7 +197,7 @@ int is_shared_symref(const struct worktree *wt,
* Similar to head_ref() for all HEADs _except_ one from the current
* worktree, which is covered by head_ref().
*/
int other_head_refs(each_ref_fn fn, void *cb_data);
int other_head_refs(refs_for_each_cb fn, void *cb_data);
int is_worktree_being_rebased(const struct worktree *wt, const char *target);
int is_worktree_being_bisected(const struct worktree *wt, const char *target);