Skip to content

Commit 53328ca

Browse files
rscharfegitster
authored andcommitted
ref-filter: share bases and is_base_tips between formatting and sorting
verify_ref_format() parses a ref-filter format string and stores recognized items in the static array "used_atom". For "ahead-behind:<committish>" and "is-base:<committish>" it stores the committish part in string_lists that are part of struct ref_format. ref_sorting_options() also parses bare ref-filter format items and also stores recognized ones in "used_atom". The committish parts go to a dummy struct ref_format in parse_sorting_atom(), though, and are leaked and forgotten. If verify_ref_format() is called before ref_sorting_options(), like in git for-each-ref, then all works well if the sort key is included in the format string. If it isn't then sorting cannot work as the committishes are missing. If ref_sorting_options() is called first, like in git branch, then we have the additional issue that if the sort key is included in the format string then filter_ahead_behind() and filter_is_base() can't see their committishes, will not generate any results for them and thus they will for expanded to empty strings. Fix those issues by making the string_lists static, like their sibling "used_atom". This way they can all be shared for handling both ref-filter format strings and sorting options in the same command. And since struct ref_format no longer contains any allocated members, remove the now unnecessary ref_format_init() and ref_format_clear(). Reported-by: Ross Goldberg <ross.goldberg@gmail.com> Signed-off-by: René Scharfe <l.s.r@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent fbe8d30 commit 53328ca

File tree

8 files changed

+89
-57
lines changed

8 files changed

+89
-57
lines changed

builtin/branch.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,7 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin
473473
if (verify_ref_format(format))
474474
die(_("unable to parse format string"));
475475

476-
filter_ahead_behind(the_repository, format, &array);
476+
filter_ahead_behind(the_repository, &array);
477477
ref_array_sort(sorting, &array);
478478

479479
if (column_active(colopts)) {
@@ -884,7 +884,6 @@ int cmd_branch(int argc,
884884
string_list_clear(&output, 0);
885885
ref_sorting_release(sorting);
886886
ref_filter_clear(&filter);
887-
ref_format_clear(&format);
888887

889888
ret = 0;
890889
goto out;

builtin/for-each-ref.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,6 @@ int cmd_for_each_ref(int argc,
108108
filter_and_format_refs(&filter, flags, sorting, &format);
109109

110110
ref_filter_clear(&filter);
111-
ref_format_clear(&format);
112111
ref_sorting_release(sorting);
113112
strvec_clear(&vec);
114113
return 0;

builtin/tag.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -698,7 +698,6 @@ int cmd_tag(int argc,
698698
cleanup:
699699
ref_sorting_release(sorting);
700700
ref_filter_clear(&filter);
701-
ref_format_clear(&format);
702701
strbuf_release(&buf);
703702
strbuf_release(&ref);
704703
strbuf_release(&reflog_msg);

builtin/verify-tag.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,5 @@ int cmd_verify_tag(int argc,
6969
if (format.format)
7070
pretty_print_ref(name, &oid, &format);
7171
}
72-
ref_format_clear(&format);
7372
return had_error;
7473
}

ref-filter.c

Lines changed: 31 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,12 @@ static struct used_atom {
242242
} *used_atom;
243243
static int used_atom_cnt, need_tagged, need_symref;
244244

245+
/* List of bases for ahead-behind counts. */
246+
static struct string_list bases = STRING_LIST_INIT_DUP;
247+
248+
/* List of bases for is-base indicators. */
249+
static struct string_list is_base_tips = STRING_LIST_INIT_DUP;
250+
245251
/*
246252
* Expand string, append it to strbuf *sb, then return error code ret.
247253
* Allow to save few lines of code.
@@ -891,7 +897,7 @@ static int rest_atom_parser(struct ref_format *format UNUSED,
891897
return 0;
892898
}
893899

894-
static int ahead_behind_atom_parser(struct ref_format *format,
900+
static int ahead_behind_atom_parser(struct ref_format *format UNUSED,
895901
struct used_atom *atom UNUSED,
896902
const char *arg, struct strbuf *err)
897903
{
@@ -900,15 +906,15 @@ static int ahead_behind_atom_parser(struct ref_format *format,
900906
if (!arg)
901907
return strbuf_addf_ret(err, -1, _("expected format: %%(ahead-behind:<committish>)"));
902908

903-
item = string_list_append(&format->bases, arg);
909+
item = string_list_append(&bases, arg);
904910
item->util = lookup_commit_reference_by_name(arg);
905911
if (!item->util)
906912
die("failed to find '%s'", arg);
907913

908914
return 0;
909915
}
910916

911-
static int is_base_atom_parser(struct ref_format *format,
917+
static int is_base_atom_parser(struct ref_format *format UNUSED,
912918
struct used_atom *atom UNUSED,
913919
const char *arg, struct strbuf *err)
914920
{
@@ -917,7 +923,7 @@ static int is_base_atom_parser(struct ref_format *format,
917923
if (!arg)
918924
return strbuf_addf_ret(err, -1, _("expected format: %%(is-base:<committish>)"));
919925

920-
item = string_list_append(&format->is_base_tips, arg);
926+
item = string_list_append(&is_base_tips, arg);
921927
item->util = lookup_commit_reference_by_name(arg);
922928
if (!item->util)
923929
die("failed to find '%s'", arg);
@@ -3024,6 +3030,8 @@ void ref_array_clear(struct ref_array *array)
30243030
}
30253031
FREE_AND_NULL(used_atom);
30263032
used_atom_cnt = 0;
3033+
string_list_clear(&bases, 0);
3034+
string_list_clear(&is_base_tips, 0);
30273035

30283036
if (ref_to_worktree_map.worktrees) {
30293037
hashmap_clear_and_free(&(ref_to_worktree_map.map),
@@ -3084,22 +3092,21 @@ static void reach_filter(struct ref_array *array,
30843092
}
30853093

30863094
void filter_ahead_behind(struct repository *r,
3087-
struct ref_format *format,
30883095
struct ref_array *array)
30893096
{
30903097
struct commit **commits;
3091-
size_t commits_nr = format->bases.nr + array->nr;
3098+
size_t commits_nr = bases.nr + array->nr;
30923099

3093-
if (!format->bases.nr || !array->nr)
3100+
if (!bases.nr || !array->nr)
30943101
return;
30953102

30963103
ALLOC_ARRAY(commits, commits_nr);
3097-
for (size_t i = 0; i < format->bases.nr; i++)
3098-
commits[i] = format->bases.items[i].util;
3104+
for (size_t i = 0; i < bases.nr; i++)
3105+
commits[i] = bases.items[i].util;
30993106

3100-
ALLOC_ARRAY(array->counts, st_mult(format->bases.nr, array->nr));
3107+
ALLOC_ARRAY(array->counts, st_mult(bases.nr, array->nr));
31013108

3102-
commits_nr = format->bases.nr;
3109+
commits_nr = bases.nr;
31033110
array->counts_nr = 0;
31043111
for (size_t i = 0; i < array->nr; i++) {
31053112
const char *name = array->items[i]->refname;
@@ -3108,8 +3115,8 @@ void filter_ahead_behind(struct repository *r,
31083115
if (!commits[commits_nr])
31093116
continue;
31103117

3111-
CALLOC_ARRAY(array->items[i]->counts, format->bases.nr);
3112-
for (size_t j = 0; j < format->bases.nr; j++) {
3118+
CALLOC_ARRAY(array->items[i]->counts, bases.nr);
3119+
for (size_t j = 0; j < bases.nr; j++) {
31133120
struct ahead_behind_count *count;
31143121
count = &array->counts[array->counts_nr++];
31153122
count->tip_index = commits_nr;
@@ -3125,14 +3132,13 @@ void filter_ahead_behind(struct repository *r,
31253132
}
31263133

31273134
void filter_is_base(struct repository *r,
3128-
struct ref_format *format,
31293135
struct ref_array *array)
31303136
{
31313137
struct commit **bases;
31323138
size_t bases_nr = 0;
31333139
struct ref_array_item **back_index;
31343140

3135-
if (!format->is_base_tips.nr || !array->nr)
3141+
if (!is_base_tips.nr || !array->nr)
31363142
return;
31373143

31383144
CALLOC_ARRAY(back_index, array->nr);
@@ -3142,7 +3148,7 @@ void filter_is_base(struct repository *r,
31423148
const char *name = array->items[i]->refname;
31433149
struct commit *c = lookup_commit_reference_by_name_gently(name, 1);
31443150

3145-
CALLOC_ARRAY(array->items[i]->is_base, format->is_base_tips.nr);
3151+
CALLOC_ARRAY(array->items[i]->is_base, is_base_tips.nr);
31463152

31473153
if (!c)
31483154
continue;
@@ -3152,15 +3158,15 @@ void filter_is_base(struct repository *r,
31523158
bases_nr++;
31533159
}
31543160

3155-
for (size_t i = 0; i < format->is_base_tips.nr; i++) {
3156-
struct commit *tip = format->is_base_tips.items[i].util;
3161+
for (size_t i = 0; i < is_base_tips.nr; i++) {
3162+
struct commit *tip = is_base_tips.items[i].util;
31573163
int base_index = get_branch_base_for_tip(r, tip, bases, bases_nr);
31583164

31593165
if (base_index < 0)
31603166
continue;
31613167

31623168
/* Store the string for use in output later. */
3163-
back_index[base_index]->is_base[i] = xstrdup(format->is_base_tips.items[i].string);
3169+
back_index[base_index]->is_base[i] = xstrdup(is_base_tips.items[i].string);
31643170
}
31653171

31663172
free(back_index);
@@ -3252,8 +3258,7 @@ struct ref_sorting {
32523258
};
32533259

32543260
static inline int can_do_iterative_format(struct ref_filter *filter,
3255-
struct ref_sorting *sorting,
3256-
struct ref_format *format)
3261+
struct ref_sorting *sorting)
32573262
{
32583263
/*
32593264
* Reference backends sort patterns lexicographically by refname, so if
@@ -3279,15 +3284,15 @@ static inline int can_do_iterative_format(struct ref_filter *filter,
32793284
*/
32803285
return !(filter->reachable_from ||
32813286
filter->unreachable_from ||
3282-
format->bases.nr ||
3283-
format->is_base_tips.nr);
3287+
bases.nr ||
3288+
is_base_tips.nr);
32843289
}
32853290

32863291
void filter_and_format_refs(struct ref_filter *filter, unsigned int type,
32873292
struct ref_sorting *sorting,
32883293
struct ref_format *format)
32893294
{
3290-
if (can_do_iterative_format(filter, sorting, format)) {
3295+
if (can_do_iterative_format(filter, sorting)) {
32913296
int save_commit_buffer_orig;
32923297
struct ref_filter_and_format_cbdata ref_cbdata = {
32933298
.filter = filter,
@@ -3303,8 +3308,8 @@ void filter_and_format_refs(struct ref_filter *filter, unsigned int type,
33033308
} else {
33043309
struct ref_array array = { 0 };
33053310
filter_refs(&array, filter, type);
3306-
filter_ahead_behind(the_repository, format, &array);
3307-
filter_is_base(the_repository, format, &array);
3311+
filter_ahead_behind(the_repository, &array);
3312+
filter_is_base(the_repository, &array);
33083313
ref_array_sort(sorting, &array);
33093314
print_formatted_ref_array(&array, format);
33103315
ref_array_clear(&array);
@@ -3638,16 +3643,3 @@ void ref_filter_clear(struct ref_filter *filter)
36383643
free_commit_list(filter->unreachable_from);
36393644
ref_filter_init(filter);
36403645
}
3641-
3642-
void ref_format_init(struct ref_format *format)
3643-
{
3644-
struct ref_format blank = REF_FORMAT_INIT;
3645-
memcpy(format, &blank, sizeof(blank));
3646-
}
3647-
3648-
void ref_format_clear(struct ref_format *format)
3649-
{
3650-
string_list_clear(&format->bases, 0);
3651-
string_list_clear(&format->is_base_tips, 0);
3652-
ref_format_init(format);
3653-
}

ref-filter.h

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,6 @@ struct ref_format {
9999
/* Internal state to ref-filter */
100100
int need_color_reset_at_eol;
101101

102-
/* List of bases for ahead-behind counts. */
103-
struct string_list bases;
104-
105-
/* List of bases for is-base indicators. */
106-
struct string_list is_base_tips;
107-
108102
struct {
109103
int max_count;
110104
int omit_empty;
@@ -117,8 +111,6 @@ struct ref_format {
117111
}
118112
#define REF_FORMAT_INIT { \
119113
.use_color = -1, \
120-
.bases = STRING_LIST_INIT_DUP, \
121-
.is_base_tips = STRING_LIST_INIT_DUP, \
122114
}
123115

124116
/* Macros for checking --merged and --no-merged options */
@@ -205,7 +197,6 @@ struct ref_array_item *ref_array_push(struct ref_array *array,
205197
* If this is not called, then any ahead-behind atoms will be blank.
206198
*/
207199
void filter_ahead_behind(struct repository *r,
208-
struct ref_format *format,
209200
struct ref_array *array);
210201

211202
/*
@@ -215,13 +206,9 @@ void filter_ahead_behind(struct repository *r,
215206
* If this is not called, then any is-base atoms will be blank.
216207
*/
217208
void filter_is_base(struct repository *r,
218-
struct ref_format *format,
219209
struct ref_array *array);
220210

221211
void ref_filter_init(struct ref_filter *filter);
222212
void ref_filter_clear(struct ref_filter *filter);
223213

224-
void ref_format_init(struct ref_format *format);
225-
void ref_format_clear(struct ref_format *format);
226-
227214
#endif /* REF_FILTER_H */

t/t3203-branch-output.sh

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,34 @@ test_expect_success 'git branch --format with ahead-behind' '
368368
test_cmp expect actual
369369
'
370370

371+
test_expect_success 'git branch `--sort=[-]ahead-behind` option' '
372+
cat >expect <<-\EOF &&
373+
(HEAD detached from fromtag) 0 0
374+
refs/heads/ambiguous 0 0
375+
refs/heads/branch-two 0 0
376+
refs/heads/branch-one 1 0
377+
refs/heads/main 1 0
378+
refs/heads/ref-to-branch 1 0
379+
refs/heads/ref-to-remote 1 0
380+
EOF
381+
git branch --format="%(refname) %(ahead-behind:HEAD)" \
382+
--sort=refname --sort=ahead-behind:HEAD >actual &&
383+
test_cmp expect actual &&
384+
385+
cat >expect <<-\EOF &&
386+
(HEAD detached from fromtag) 0 0
387+
refs/heads/branch-one 1 0
388+
refs/heads/main 1 0
389+
refs/heads/ref-to-branch 1 0
390+
refs/heads/ref-to-remote 1 0
391+
refs/heads/ambiguous 0 0
392+
refs/heads/branch-two 0 0
393+
EOF
394+
git branch --format="%(refname) %(ahead-behind:HEAD)" \
395+
--sort=refname --sort=-ahead-behind:HEAD >actual &&
396+
test_cmp expect actual
397+
'
398+
371399
test_expect_success 'git branch with --format=%(rest) must fail' '
372400
test_must_fail git branch --format="%(rest)" >actual
373401
'

t/t6600-test-reach.sh

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -733,4 +733,33 @@ test_expect_success 'for-each-ref is-base:multiple' '
733733
--format="%(refname)[%(is-base:commit-2-3)-%(is-base:commit-6-5)]" --stdin
734734
'
735735

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+
736765
test_done

0 commit comments

Comments
 (0)