Merge branch 'rs/ref-fitler-used-atoms-value-fix'

"git branch --sort=..." and "git for-each-ref --format=... --sort=..."
did not work as expected with some atoms, which has been corrected.

* rs/ref-fitler-used-atoms-value-fix:
  ref-filter: remove ref_format_clear()
  ref-filter: move is-base tip to used_atom
  ref-filter: move ahead-behind bases into used_atom
This commit is contained in:
Junio C Hamano
2025-01-29 14:05:09 -08:00
8 changed files with 121 additions and 72 deletions

View File

@@ -235,6 +235,10 @@ static struct used_atom {
enum { S_BARE, S_GRADE, S_SIGNER, S_KEY,
S_FINGERPRINT, S_PRI_KEY_FP, S_TRUST_LEVEL } option;
} signature;
struct {
char *name;
struct commit *commit;
} base;
struct strvec describe_args;
struct refname_atom refname;
char *head;
@@ -891,35 +895,30 @@ static int rest_atom_parser(struct ref_format *format UNUSED,
return 0;
}
static int ahead_behind_atom_parser(struct ref_format *format,
struct used_atom *atom UNUSED,
static int ahead_behind_atom_parser(struct ref_format *format UNUSED,
struct used_atom *atom,
const char *arg, struct strbuf *err)
{
struct string_list_item *item;
if (!arg)
return strbuf_addf_ret(err, -1, _("expected format: %%(ahead-behind:<committish>)"));
item = string_list_append(&format->bases, arg);
item->util = lookup_commit_reference_by_name(arg);
if (!item->util)
atom->u.base.commit = lookup_commit_reference_by_name(arg);
if (!atom->u.base.commit)
die("failed to find '%s'", arg);
return 0;
}
static int is_base_atom_parser(struct ref_format *format,
struct used_atom *atom UNUSED,
static int is_base_atom_parser(struct ref_format *format UNUSED,
struct used_atom *atom,
const char *arg, struct strbuf *err)
{
struct string_list_item *item;
if (!arg)
return strbuf_addf_ret(err, -1, _("expected format: %%(is-base:<committish>)"));
item = string_list_append(&format->is_base_tips, arg);
item->util = lookup_commit_reference_by_name(arg);
if (!item->util)
atom->u.base.name = xstrdup(arg);
atom->u.base.commit = lookup_commit_reference_by_name(arg);
if (!atom->u.base.commit)
die("failed to find '%s'", arg);
return 0;
@@ -3009,6 +3008,8 @@ void ref_array_clear(struct ref_array *array)
free(atom->u.head);
else if (atom->atom_type == ATOM_DESCRIBE)
strvec_clear(&atom->u.describe_args);
else if (atom->atom_type == ATOM_ISBASE)
free(atom->u.base.name);
else if (atom->atom_type == ATOM_TRAILERS ||
(atom->atom_type == ATOM_CONTENTS &&
atom->u.contents.option == C_TRAILERS)) {
@@ -3084,22 +3085,30 @@ static void reach_filter(struct ref_array *array,
}
void filter_ahead_behind(struct repository *r,
struct ref_format *format,
struct ref_array *array)
{
struct commit **commits;
size_t commits_nr = format->bases.nr + array->nr;
size_t bases_nr, commits_nr;
if (!format->bases.nr || !array->nr)
if (!array->nr)
return;
ALLOC_ARRAY(commits, commits_nr);
for (size_t i = 0; i < format->bases.nr; i++)
commits[i] = format->bases.items[i].util;
for (size_t i = bases_nr = 0; i < used_atom_cnt; i++) {
if (used_atom[i].atom_type == ATOM_AHEADBEHIND)
bases_nr++;
}
if (!bases_nr)
return;
ALLOC_ARRAY(array->counts, st_mult(format->bases.nr, array->nr));
ALLOC_ARRAY(commits, st_add(bases_nr, array->nr));
for (size_t i = 0, j = 0; i < used_atom_cnt; i++) {
if (used_atom[i].atom_type == ATOM_AHEADBEHIND)
commits[j++] = used_atom[i].u.base.commit;
}
commits_nr = format->bases.nr;
ALLOC_ARRAY(array->counts, st_mult(bases_nr, array->nr));
commits_nr = bases_nr;
array->counts_nr = 0;
for (size_t i = 0; i < array->nr; i++) {
const char *name = array->items[i]->refname;
@@ -3108,8 +3117,8 @@ void filter_ahead_behind(struct repository *r,
if (!commits[commits_nr])
continue;
CALLOC_ARRAY(array->items[i]->counts, format->bases.nr);
for (size_t j = 0; j < format->bases.nr; j++) {
CALLOC_ARRAY(array->items[i]->counts, bases_nr);
for (size_t j = 0; j < bases_nr; j++) {
struct ahead_behind_count *count;
count = &array->counts[array->counts_nr++];
count->tip_index = commits_nr;
@@ -3125,14 +3134,20 @@ void filter_ahead_behind(struct repository *r,
}
void filter_is_base(struct repository *r,
struct ref_format *format,
struct ref_array *array)
{
struct commit **bases;
size_t bases_nr = 0;
size_t bases_nr = 0, is_base_nr;
struct ref_array_item **back_index;
if (!format->is_base_tips.nr || !array->nr)
if (!array->nr)
return;
for (size_t i = is_base_nr = 0; i < used_atom_cnt; i++) {
if (used_atom[i].atom_type == ATOM_ISBASE)
is_base_nr++;
}
if (!is_base_nr)
return;
CALLOC_ARRAY(back_index, array->nr);
@@ -3142,7 +3157,7 @@ void filter_is_base(struct repository *r,
const char *name = array->items[i]->refname;
struct commit *c = lookup_commit_reference_by_name_gently(name, 1);
CALLOC_ARRAY(array->items[i]->is_base, format->is_base_tips.nr);
CALLOC_ARRAY(array->items[i]->is_base, is_base_nr);
if (!c)
continue;
@@ -3152,15 +3167,20 @@ void filter_is_base(struct repository *r,
bases_nr++;
}
for (size_t i = 0; i < format->is_base_tips.nr; i++) {
struct commit *tip = format->is_base_tips.items[i].util;
int base_index = get_branch_base_for_tip(r, tip, bases, bases_nr);
for (size_t i = 0, j = 0; i < used_atom_cnt; i++) {
struct commit *tip;
int base_index;
if (used_atom[i].atom_type != ATOM_ISBASE)
continue;
tip = used_atom[i].u.base.commit;
base_index = get_branch_base_for_tip(r, tip, bases, bases_nr);
if (base_index < 0)
continue;
/* Store the string for use in output later. */
back_index[base_index]->is_base[i] = xstrdup(format->is_base_tips.items[i].string);
back_index[base_index]->is_base[j++] = xstrdup(used_atom[i].u.base.name);
}
free(back_index);
@@ -3252,8 +3272,7 @@ struct ref_sorting {
};
static inline int can_do_iterative_format(struct ref_filter *filter,
struct ref_sorting *sorting,
struct ref_format *format)
struct ref_sorting *sorting)
{
/*
* Reference backends sort patterns lexicographically by refname, so if
@@ -3277,17 +3296,20 @@ static inline int can_do_iterative_format(struct ref_filter *filter,
* - filtering on reachability
* - including ahead-behind information in the formatted output
*/
return !(filter->reachable_from ||
filter->unreachable_from ||
format->bases.nr ||
format->is_base_tips.nr);
for (size_t i = 0; i < used_atom_cnt; i++) {
if (used_atom[i].atom_type == ATOM_AHEADBEHIND)
return 0;
if (used_atom[i].atom_type == ATOM_ISBASE)
return 0;
}
return !(filter->reachable_from || filter->unreachable_from);
}
void filter_and_format_refs(struct ref_filter *filter, unsigned int type,
struct ref_sorting *sorting,
struct ref_format *format)
{
if (can_do_iterative_format(filter, sorting, format)) {
if (can_do_iterative_format(filter, sorting)) {
int save_commit_buffer_orig;
struct ref_filter_and_format_cbdata ref_cbdata = {
.filter = filter,
@@ -3303,8 +3325,8 @@ void filter_and_format_refs(struct ref_filter *filter, unsigned int type,
} else {
struct ref_array array = { 0 };
filter_refs(&array, filter, type);
filter_ahead_behind(the_repository, format, &array);
filter_is_base(the_repository, format, &array);
filter_ahead_behind(the_repository, &array);
filter_is_base(the_repository, &array);
ref_array_sort(sorting, &array);
print_formatted_ref_array(&array, format);
ref_array_clear(&array);
@@ -3638,16 +3660,3 @@ void ref_filter_clear(struct ref_filter *filter)
free_commit_list(filter->unreachable_from);
ref_filter_init(filter);
}
void ref_format_init(struct ref_format *format)
{
struct ref_format blank = REF_FORMAT_INIT;
memcpy(format, &blank, sizeof(blank));
}
void ref_format_clear(struct ref_format *format)
{
string_list_clear(&format->bases, 0);
string_list_clear(&format->is_base_tips, 0);
ref_format_init(format);
}