diff --git a/refs.c b/refs.c index e4402d787f..0d0f0edbfb 100644 --- a/refs.c +++ b/refs.c @@ -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) diff --git a/refs.h b/refs.h index a66dbf3865..5a5fb4e1e4 100644 --- a/refs.h +++ b/refs.h @@ -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