refs: generalize refs_for_each_namespaced_ref()

The function `refs_for_each_namespaced_ref()` iterates through all
references that are part of the current ref namespace. This namespace
can be configured by setting the `GIT_NAMESPACE` environment variable
and is then retrieved by calling `get_git_namespace()`.

If a namespace is configured, then we:

  - Obviously only yield refs that exist in this namespace.

  - Rewrite exclude patterns so that they work for the given namespace,
    if any namespace is currently configured.

Port this logic to `refs_for_each_ref_ext()` by adding a new `namespace`
field to the options structure. This gives callers more flexibility as
they can decide by themselves whether they want to use the globally
configured or an arbitrary other namespace.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Patrick Steinhardt
2026-02-23 12:59:42 +01:00
committed by Junio C Hamano
parent daf01b1366
commit 5387919327
2 changed files with 36 additions and 18 deletions

47
refs.c
View File

@@ -1848,10 +1848,14 @@ 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 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;
if (!refs)
@@ -1886,11 +1890,29 @@ int refs_for_each_ref_ext(struct ref_store *refs,
cb_data = &filter;
}
iter = refs_ref_iterator_begin(refs, opts->prefix ? opts->prefix : "",
opts->exclude_patterns,
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(&namespaced_prefix);
strbuf_release(&real_pattern);
return ret;
}
@@ -1937,22 +1959,11 @@ int refs_for_each_namespaced_ref(struct ref_store *refs,
const char **exclude_patterns,
refs_for_each_cb cb, void *cb_data)
{
struct refs_for_each_ref_options opts = { 0 };
struct strvec namespaced_exclude_patterns = STRVEC_INIT;
struct strbuf prefix = STRBUF_INIT;
int ret;
opts.exclude_patterns = get_namespaced_exclude_patterns(exclude_patterns,
get_git_namespace(),
&namespaced_exclude_patterns);
strbuf_addf(&prefix, "%srefs/", get_git_namespace());
opts.prefix = prefix.buf;
ret = refs_for_each_ref_ext(refs, cb, cb_data, &opts);
strvec_clear(&namespaced_exclude_patterns);
strbuf_release(&prefix);
return ret;
struct refs_for_each_ref_options opts = {
.exclude_patterns = exclude_patterns,
.namespace = get_git_namespace(),
};
return refs_for_each_ref_ext(refs, cb, cb_data, &opts);
}
int refs_for_each_rawref(struct ref_store *refs, refs_for_each_cb fn, void *cb_data)

7
refs.h
View File

@@ -468,6 +468,13 @@ struct refs_for_each_ref_options {
*/
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