ref-filter: move is-base tip to used_atom

The string_list "is_base_tips" in struct ref_format stores the committish part of "is-base:<committish>". It has the same problems that its sibling string_list "bases" had. Fix them the same way as the previous commit did for the latter, by replacing the string_list with fields in "used_atom". Helped-by: Jeff King <peff@peff.net> Signed-off-by: René Scharfe <l.s.r@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>

René Scharfe committed Jan 18, 2025 at 18:11 UTC 7ee4fd18ace71d187ee3ea5ba745a6a3493e0e0a
3 files changed +62 -28
ref-filter.c
+33 -23
@@ -236,6 +236,7 @@ static struct used_atom {
236 S_FINGERPRINT, S_PRI_KEY_FP, S_TRUST_LEVEL } option;
237 } signature;
238 struct {
239 + char *name;
240 struct commit *commit;
241 } base;
242 struct strvec describe_args;
@@ -908,18 +909,16 @@ static int ahead_behind_atom_parser(struct ref_format *format UNUSED,
909 return 0;
910 }
911
911 -static int is_base_atom_parser(struct ref_format *format,
912 - struct used_atom *atom UNUSED,
912 +static int is_base_atom_parser(struct ref_format *format UNUSED,
913 + struct used_atom *atom,
914 const char *arg, struct strbuf *err)
915 {
915 - struct string_list_item *item;
916 -
916 if (!arg)
917 return strbuf_addf_ret(err, -1, _("expected format: %%(is-base:<committish>)"));
918
920 - item = string_list_append(&format->is_base_tips, arg);
921 - item->util = lookup_commit_reference_by_name(arg);
922 - if (!item->util)
919 + atom->u.base.name = xstrdup(arg);
920 + atom->u.base.commit = lookup_commit_reference_by_name(arg);
921 + if (!atom->u.base.commit)
922 die("failed to find '%s'", arg);
923
924 return 0;
@@ -3009,6 +3008,8 @@ void ref_array_clear(struct ref_array *array)
3008 free(atom->u.head);
3009 else if (atom->atom_type == ATOM_DESCRIBE)
3010 strvec_clear(&atom->u.describe_args);
3011 + else if (atom->atom_type == ATOM_ISBASE)
3012 + free(atom->u.base.name);
3013 else if (atom->atom_type == ATOM_TRAILERS ||
3014 (atom->atom_type == ATOM_CONTENTS &&
3015 atom->u.contents.option == C_TRAILERS)) {
@@ -3133,14 +3134,20 @@ void filter_ahead_behind(struct repository *r,
3134 }
3135
3136 void filter_is_base(struct repository *r,
3136 - struct ref_format *format,
3137 struct ref_array *array)
3138 {
3139 struct commit **bases;
3140 - size_t bases_nr = 0;
3140 + size_t bases_nr = 0, is_base_nr;
3141 struct ref_array_item **back_index;
3142
3143 - if (!format->is_base_tips.nr || !array->nr)
3143 + if (!array->nr)
3144 + return;
3145 +
3146 + for (size_t i = is_base_nr = 0; i < used_atom_cnt; i++) {
3147 + if (used_atom[i].atom_type == ATOM_ISBASE)
3148 + is_base_nr++;
3149 + }
3150 + if (!is_base_nr)
3151 return;
3152
3153 CALLOC_ARRAY(back_index, array->nr);
@@ -3150,7 +3157,7 @@ void filter_is_base(struct repository *r,
3157 const char *name = array->items[i]->refname;
3158 struct commit *c = lookup_commit_reference_by_name_gently(name, 1);
3159
3153 - CALLOC_ARRAY(array->items[i]->is_base, format->is_base_tips.nr);
3160 + CALLOC_ARRAY(array->items[i]->is_base, is_base_nr);
3161
3162 if (!c)
3163 continue;
@@ -3160,15 +3167,20 @@ void filter_is_base(struct repository *r,
3167 bases_nr++;
3168 }
3169
3163 - for (size_t i = 0; i < format->is_base_tips.nr; i++) {
3164 - struct commit *tip = format->is_base_tips.items[i].util;
3165 - int base_index = get_branch_base_for_tip(r, tip, bases, bases_nr);
3170 + for (size_t i = 0, j = 0; i < used_atom_cnt; i++) {
3171 + struct commit *tip;
3172 + int base_index;
3173 +
3174 + if (used_atom[i].atom_type != ATOM_ISBASE)
3175 + continue;
3176
3177 + tip = used_atom[i].u.base.commit;
3178 + base_index = get_branch_base_for_tip(r, tip, bases, bases_nr);
3179 if (base_index < 0)
3180 continue;
3181
3182 /* Store the string for use in output later. */
3171 - back_index[base_index]->is_base[i] = xstrdup(format->is_base_tips.items[i].string);
3183 + back_index[base_index]->is_base[j++] = xstrdup(used_atom[i].u.base.name);
3184 }
3185
3186 free(back_index);
@@ -3260,8 +3272,7 @@ struct ref_sorting {
3272 };
3273
3274 static inline int can_do_iterative_format(struct ref_filter *filter,
3263 - struct ref_sorting *sorting,
3264 - struct ref_format *format)
3275 + struct ref_sorting *sorting)
3276 {
3277 /*
3278 * Reference backends sort patterns lexicographically by refname, so if
@@ -3288,17 +3299,17 @@ static inline int can_do_iterative_format(struct ref_filter *filter,
3299 for (size_t i = 0; i < used_atom_cnt; i++) {
3300 if (used_atom[i].atom_type == ATOM_AHEADBEHIND)
3301 return 0;
3302 + if (used_atom[i].atom_type == ATOM_ISBASE)
3303 + return 0;
3304 }
3292 - return !(filter->reachable_from ||
3293 - filter->unreachable_from ||
3294 - format->is_base_tips.nr);
3305 + return !(filter->reachable_from || filter->unreachable_from);
3306 }
3307
3308 void filter_and_format_refs(struct ref_filter *filter, unsigned int type,
3309 struct ref_sorting *sorting,
3310 struct ref_format *format)
3311 {
3301 - if (can_do_iterative_format(filter, sorting, format)) {
3312 + if (can_do_iterative_format(filter, sorting)) {
3313 int save_commit_buffer_orig;
3314 struct ref_filter_and_format_cbdata ref_cbdata = {
3315 .filter = filter,
@@ -3315,7 +3326,7 @@ void filter_and_format_refs(struct ref_filter *filter, unsigned int type,
3326 struct ref_array array = { 0 };
3327 filter_refs(&array, filter, type);
3328 filter_ahead_behind(the_repository, &array);
3318 - filter_is_base(the_repository, format, &array);
3329 + filter_is_base(the_repository, &array);
3330 ref_array_sort(sorting, &array);
3331 print_formatted_ref_array(&array, format);
3332 ref_array_clear(&array);
@@ -3658,6 +3669,5 @@ void ref_format_init(struct ref_format *format)
3669
3670 void ref_format_clear(struct ref_format *format)
3671 {
3661 - string_list_clear(&format->is_base_tips, 0);
3672 ref_format_init(format);
3673 }
ref-filter.h
-5
@@ -99,9 +99,6 @@ struct ref_format {
99 /* Internal state to ref-filter */
100 int need_color_reset_at_eol;
101
102 - /* List of bases for is-base indicators. */
103 - struct string_list is_base_tips;
104 -
102 struct {
103 int max_count;
104 int omit_empty;
@@ -114,7 +111,6 @@ struct ref_format {
111 }
112 #define REF_FORMAT_INIT { \
113 .use_color = -1, \
117 - .is_base_tips = STRING_LIST_INIT_DUP, \
114 }
115
116 /* Macros for checking --merged and --no-merged options */
@@ -210,7 +206,6 @@ void filter_ahead_behind(struct repository *r,
206 * If this is not called, then any is-base atoms will be blank.
207 */
208 void filter_is_base(struct repository *r,
213 - struct ref_format *format,
209 struct ref_array *array);
210
211 void ref_filter_init(struct ref_filter *filter);
t/t6600-test-reach.sh
+29
@@ -733,4 +733,33 @@ test_expect_success 'for-each-ref is-base:multiple' '
733 --format="%(refname)[%(is-base:commit-2-3)-%(is-base:commit-6-5)]" --stdin
734 '
735
736 +test_expect_success 'for-each-ref is-base: --sort' '
737 + cat >input <<-\EOF &&
738 + refs/heads/commit-1-1
739 + refs/heads/commit-4-2
740 + refs/heads/commit-4-4
741 + refs/heads/commit-8-4
742 + EOF
743 +
744 + cat >expect <<-\EOF &&
745 + refs/heads/commit-1-1
746 + refs/heads/commit-4-4
747 + refs/heads/commit-8-4
748 + refs/heads/commit-4-2
749 + EOF
750 + run_all_modes git for-each-ref \
751 + --format="%(refname)" --stdin \
752 + --sort=refname --sort=is-base:commit-2-3 &&
753 +
754 + cat >expect <<-\EOF &&
755 + refs/heads/commit-4-2
756 + refs/heads/commit-1-1
757 + refs/heads/commit-4-4
758 + refs/heads/commit-8-4
759 + EOF
760 + run_all_modes git for-each-ref \
761 + --format="%(refname)" --stdin \
762 + --sort=refname --sort=-is-base:commit-2-3
763 +'
764 +
765 test_done