From: Karthik Nayak Date: Mon, 23 Feb 2026 09:02:56 GMT Subject: Re: [PATCH 08/17] refs: generalize `refs_for_each_namespaced_ref()` Message-ID: In-Reply-To: <20260220-pks-refs-for-each-unification-v1-8-17170bd99de1@pks.im> Patrick Steinhardt writes: > 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 > --- > refs.c | 47 +++++++++++++++++++++++++++++------------------ > refs.h | 6 ++++++ > 2 files changed, 35 insertions(+), 18 deletions(-) > > diff --git a/refs.c b/refs.c > index ac34bbe6c1..99994879d9 100644 > --- a/refs.c > +++ b/refs.c > @@ -1845,9 +1845,13 @@ 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; > + const char **exclude_patterns; > + const char *prefix; > int ret; > > if (!refs) > @@ -1876,11 +1880,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/"); > + So if the namespace is 'foo', we'll have the namespace folder as 'refs/namespace/foo', and a prefix of 'refs/heads/' would mean that the 'namespaced_prefix' is now 'refs/namespace/foo/refs/heads'. Looks good. > + 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, > opts->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; > } > @@ -1927,22 +1949,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..2bde60aa0e 100644 > --- a/refs.h > +++ b/refs.h > @@ -468,6 +468,12 @@ 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. > + */ > + const char *namespace; Nit: should we also mention how prefix is appended to namespace? > + > /* > * Exclude any references that match any of these patterns on a > * best-effort basis. The caller needs to be prepared for the exclude > > -- > 2.53.0.414.gf7e9f6c205.dirty