mirror of
https://github.com/git/git.git
synced 2025-02-06 09:26:16 +00:00
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:
commit
8d6240d4c6
@ -473,7 +473,7 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin
|
||||
if (verify_ref_format(format))
|
||||
die(_("unable to parse format string"));
|
||||
|
||||
filter_ahead_behind(the_repository, format, &array);
|
||||
filter_ahead_behind(the_repository, &array);
|
||||
ref_array_sort(sorting, &array);
|
||||
|
||||
if (column_active(colopts)) {
|
||||
@ -884,7 +884,6 @@ int cmd_branch(int argc,
|
||||
string_list_clear(&output, 0);
|
||||
ref_sorting_release(sorting);
|
||||
ref_filter_clear(&filter);
|
||||
ref_format_clear(&format);
|
||||
|
||||
ret = 0;
|
||||
goto out;
|
||||
|
@ -108,7 +108,6 @@ int cmd_for_each_ref(int argc,
|
||||
filter_and_format_refs(&filter, flags, sorting, &format);
|
||||
|
||||
ref_filter_clear(&filter);
|
||||
ref_format_clear(&format);
|
||||
ref_sorting_release(sorting);
|
||||
strvec_clear(&vec);
|
||||
return 0;
|
||||
|
@ -698,7 +698,6 @@ int cmd_tag(int argc,
|
||||
cleanup:
|
||||
ref_sorting_release(sorting);
|
||||
ref_filter_clear(&filter);
|
||||
ref_format_clear(&format);
|
||||
strbuf_release(&buf);
|
||||
strbuf_release(&ref);
|
||||
strbuf_release(&reflog_msg);
|
||||
|
@ -69,6 +69,5 @@ int cmd_verify_tag(int argc,
|
||||
if (format.format)
|
||||
pretty_print_ref(name, &oid, &format);
|
||||
}
|
||||
ref_format_clear(&format);
|
||||
return had_error;
|
||||
}
|
||||
|
117
ref-filter.c
117
ref-filter.c
@ -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);
|
||||
}
|
||||
|
13
ref-filter.h
13
ref-filter.h
@ -99,12 +99,6 @@ struct ref_format {
|
||||
/* Internal state to ref-filter */
|
||||
int need_color_reset_at_eol;
|
||||
|
||||
/* List of bases for ahead-behind counts. */
|
||||
struct string_list bases;
|
||||
|
||||
/* List of bases for is-base indicators. */
|
||||
struct string_list is_base_tips;
|
||||
|
||||
struct {
|
||||
int max_count;
|
||||
int omit_empty;
|
||||
@ -117,8 +111,6 @@ struct ref_format {
|
||||
}
|
||||
#define REF_FORMAT_INIT { \
|
||||
.use_color = -1, \
|
||||
.bases = STRING_LIST_INIT_DUP, \
|
||||
.is_base_tips = STRING_LIST_INIT_DUP, \
|
||||
}
|
||||
|
||||
/* Macros for checking --merged and --no-merged options */
|
||||
@ -205,7 +197,6 @@ struct ref_array_item *ref_array_push(struct ref_array *array,
|
||||
* If this is not called, then any ahead-behind atoms will be blank.
|
||||
*/
|
||||
void filter_ahead_behind(struct repository *r,
|
||||
struct ref_format *format,
|
||||
struct ref_array *array);
|
||||
|
||||
/*
|
||||
@ -215,13 +206,9 @@ void filter_ahead_behind(struct repository *r,
|
||||
* If this is not called, then any is-base atoms will be blank.
|
||||
*/
|
||||
void filter_is_base(struct repository *r,
|
||||
struct ref_format *format,
|
||||
struct ref_array *array);
|
||||
|
||||
void ref_filter_init(struct ref_filter *filter);
|
||||
void ref_filter_clear(struct ref_filter *filter);
|
||||
|
||||
void ref_format_init(struct ref_format *format);
|
||||
void ref_format_clear(struct ref_format *format);
|
||||
|
||||
#endif /* REF_FILTER_H */
|
||||
|
@ -368,6 +368,34 @@ test_expect_success 'git branch --format with ahead-behind' '
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'git branch `--sort=[-]ahead-behind` option' '
|
||||
cat >expect <<-\EOF &&
|
||||
(HEAD detached from fromtag) 0 0
|
||||
refs/heads/ambiguous 0 0
|
||||
refs/heads/branch-two 0 0
|
||||
refs/heads/branch-one 1 0
|
||||
refs/heads/main 1 0
|
||||
refs/heads/ref-to-branch 1 0
|
||||
refs/heads/ref-to-remote 1 0
|
||||
EOF
|
||||
git branch --format="%(refname) %(ahead-behind:HEAD)" \
|
||||
--sort=refname --sort=ahead-behind:HEAD >actual &&
|
||||
test_cmp expect actual &&
|
||||
|
||||
cat >expect <<-\EOF &&
|
||||
(HEAD detached from fromtag) 0 0
|
||||
refs/heads/branch-one 1 0
|
||||
refs/heads/main 1 0
|
||||
refs/heads/ref-to-branch 1 0
|
||||
refs/heads/ref-to-remote 1 0
|
||||
refs/heads/ambiguous 0 0
|
||||
refs/heads/branch-two 0 0
|
||||
EOF
|
||||
git branch --format="%(refname) %(ahead-behind:HEAD)" \
|
||||
--sort=refname --sort=-ahead-behind:HEAD >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'git branch with --format=%(rest) must fail' '
|
||||
test_must_fail git branch --format="%(rest)" >actual
|
||||
'
|
||||
|
@ -733,4 +733,33 @@ test_expect_success 'for-each-ref is-base:multiple' '
|
||||
--format="%(refname)[%(is-base:commit-2-3)-%(is-base:commit-6-5)]" --stdin
|
||||
'
|
||||
|
||||
test_expect_success 'for-each-ref is-base: --sort' '
|
||||
cat >input <<-\EOF &&
|
||||
refs/heads/commit-1-1
|
||||
refs/heads/commit-4-2
|
||||
refs/heads/commit-4-4
|
||||
refs/heads/commit-8-4
|
||||
EOF
|
||||
|
||||
cat >expect <<-\EOF &&
|
||||
refs/heads/commit-1-1
|
||||
refs/heads/commit-4-4
|
||||
refs/heads/commit-8-4
|
||||
refs/heads/commit-4-2
|
||||
EOF
|
||||
run_all_modes git for-each-ref \
|
||||
--format="%(refname)" --stdin \
|
||||
--sort=refname --sort=is-base:commit-2-3 &&
|
||||
|
||||
cat >expect <<-\EOF &&
|
||||
refs/heads/commit-4-2
|
||||
refs/heads/commit-1-1
|
||||
refs/heads/commit-4-4
|
||||
refs/heads/commit-8-4
|
||||
EOF
|
||||
run_all_modes git for-each-ref \
|
||||
--format="%(refname)" --stdin \
|
||||
--sort=refname --sort=-is-base:commit-2-3
|
||||
'
|
||||
|
||||
test_done
|
||||
|
Loading…
x
Reference in New Issue
Block a user