>From 5aa6f037642df3b358ab659d17b5fb5bc7936f0f Mon Sep 17 00:00:00 2001 From: Kenneth Cochran <kenneth.cochran101@xxxxxxxxx> Date: Sun, 3 Mar 2019 15:05:11 -0600 Subject: [RFC PATCH 2/4] refs: add function to iteratively dereference symref chain Cc: Sahil Dua <sahildua2305@xxxxxxxxx>, Duy Nguyen <pclouds@xxxxxxxxx>, Jeff King <peff@xxxxxxxx> As far as I can tell, currently, there's not really any way to run something once per symref in a symref chain. This adds that ability. This will be useful for instance to improve how `git branch -d` handles a checked out symref. Signed-off-by: Kenneth Cochran <kenneth.cochran101@xxxxxxxxx> --- refs.c | 28 ++++++++++++++++++++++++++++ refs.h | 13 +++++++++++++ 2 files changed, 41 insertions(+) diff --git a/refs.c b/refs.c index 142888a40a..18a222d76a 100644 --- a/refs.c +++ b/refs.c @@ -1466,6 +1466,34 @@ static int do_for_each_ref(struct ref_store *refs, const char *prefix, do_for_each_ref_helper, &hp); } +int refs_for_each_ref_in_chain(struct ref_store *refs, each_ref_fn fn, + void *cb_data, const char *starting_ref) +{ + int symref_count; + struct object_id oid; + int flags; + const char *ref_name = xstrdup(starting_ref); + int res; + + for (symref_count = 0; symref_count < SYMREF_MAXDEPTH; symref_count++) { + res = fn(ref_name, &oid, flags, cb_data); + ref_name = refs_resolve_ref_unsafe(refs, ref_name, RESOLVE_REF_NO_RECURSE, + &oid, &flags); + + if (res) + return res; + if (!(flags & REF_ISSYMREF)) + break; + } + return 0; +} + +int for_each_ref_in_chain(each_ref_fn fn, void *cb_data, const char *starting_ref) +{ + return refs_for_each_ref_in_chain(get_main_ref_store(the_repository), fn, + cb_data, starting_ref); +} + int refs_for_each_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data) { return do_for_each_ref(refs, "", fn, 0, 0, cb_data); diff --git a/refs.h b/refs.h index 308fa1f03b..66ccb85e8d 100644 --- a/refs.h +++ b/refs.h @@ -327,6 +327,19 @@ int for_each_glob_ref_in(each_ref_fn fn, const char *pattern, int head_ref_namespaced(each_ref_fn fn, void *cb_data); int for_each_namespaced_ref(each_ref_fn fn, void *cb_data); +/* + * Iteratively calls fn with each reference in a symref chain. + * Iteration will continue until one of the following occurs: + * - SYMREF_MAXDEPTH is reached + * - A non-symbolic ref is reached (fn will be called with this before returning) + * - fn returns a non 0 value + * + * Will always return 0 unless fn returns a non-zero value. + */ +int refs_for_each_ref_in_chain(struct ref_store *refs, each_ref_fn fn, + void *cb_data, const char *starting_ref); +int for_each_ref_in_chain(each_ref_fn fn, void *cb_data, const char *starting_ref); + /* 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 for_each_rawref(each_ref_fn fn, void *cb_data); -- 2.17.1