Skip to content

Commit 6de1630

Browse files
committed
Merge branch 'jk/for-each-ref-multi-key-sort-fix'
"git branch" and other "for-each-ref" variants accepted multiple --sort=<key> options in the increasing order of precedence, but it had a few breakages around "--ignore-case" handling, and tie-breaking with the refname, which have been fixed. * jk/for-each-ref-multi-key-sort-fix: ref-filter: apply fallback refname sort only after all user sorts ref-filter: apply --ignore-case to all sorting keys
2 parents 1260f81 + 7c5045f commit 6de1630

File tree

6 files changed

+104
-11
lines changed

6 files changed

+104
-11
lines changed

builtin/branch.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -737,7 +737,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
737737
*/
738738
if (!sorting)
739739
sorting = ref_default_sorting();
740-
sorting->ignore_case = icase;
740+
ref_sorting_icase_all(sorting, icase);
741741
print_ref_list(&filter, sorting, &format);
742742
print_columns(&output, colopts, NULL);
743743
string_list_clear(&output, 0);

builtin/for-each-ref.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
7070

7171
if (!sorting)
7272
sorting = ref_default_sorting();
73-
sorting->ignore_case = icase;
73+
ref_sorting_icase_all(sorting, icase);
7474
filter.ignore_case = icase;
7575

7676
filter.name_patterns = argv;

builtin/tag.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
485485
}
486486
if (!sorting)
487487
sorting = ref_default_sorting();
488-
sorting->ignore_case = icase;
488+
ref_sorting_icase_all(sorting, icase);
489489
filter.ignore_case = icase;
490490
if (cmdmode == 'l') {
491491
int ret;

ref-filter.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2295,7 +2295,7 @@ static int cmp_ref_sorting(struct ref_sorting *s, struct ref_array_item *a, stru
22952295
if (va->value < vb->value)
22962296
cmp = -1;
22972297
else if (va->value == vb->value)
2298-
cmp = cmp_fn(a->refname, b->refname);
2298+
cmp = 0;
22992299
else
23002300
cmp = 1;
23012301
}
@@ -2314,7 +2314,16 @@ static int compare_refs(const void *a_, const void *b_, void *ref_sorting)
23142314
if (cmp)
23152315
return cmp;
23162316
}
2317-
return 0;
2317+
s = ref_sorting;
2318+
return s && s->ignore_case ?
2319+
strcasecmp(a->refname, b->refname) :
2320+
strcmp(a->refname, b->refname);
2321+
}
2322+
2323+
void ref_sorting_icase_all(struct ref_sorting *sorting, int flag)
2324+
{
2325+
for (; sorting; sorting = sorting->next)
2326+
sorting->ignore_case = !!flag;
23182327
}
23192328

23202329
void ref_array_sort(struct ref_sorting *sorting, struct ref_array *array)

ref-filter.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ void ref_array_clear(struct ref_array *array);
114114
int verify_ref_format(struct ref_format *format);
115115
/* Sort the given ref_array as per the ref_sorting provided */
116116
void ref_array_sort(struct ref_sorting *sort, struct ref_array *array);
117+
/* Set the ignore_case flag for all elements of a sorting list */
118+
void ref_sorting_icase_all(struct ref_sorting *sorting, int flag);
117119
/* Based on the given format and quote_style, fill the strbuf */
118120
int format_ref_array_item(struct ref_array_item *info,
119121
const struct ref_format *format,

t/t6300-for-each-ref.sh

Lines changed: 88 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -650,17 +650,59 @@ test_atom refs/tags/signed-long contents "subject line
650650
body contents
651651
$sig"
652652

653-
sort >expected <<EOF
654-
$(git rev-parse refs/tags/bogo) <[email protected]> refs/tags/bogo
655-
$(git rev-parse refs/tags/master) <[email protected]> refs/tags/master
656-
EOF
653+
test_expect_success 'set up multiple-sort tags' '
654+
for when in 100000 200000
655+
do
656+
for email in user1 user2
657+
do
658+
for ref in ref1 ref2
659+
do
660+
GIT_COMMITTER_DATE="@$when +0000" \
661+
GIT_COMMITTER_EMAIL="[email protected]" \
662+
git tag -m "tag $ref-$when-$email" \
663+
multi-$ref-$when-$email || return 1
664+
done
665+
done
666+
done
667+
'
657668

658669
test_expect_success 'Verify sort with multiple keys' '
659-
git for-each-ref --format="%(objectname) %(taggeremail) %(refname)" --sort=objectname --sort=taggeremail \
660-
refs/tags/bogo refs/tags/master > actual &&
670+
cat >expected <<-\EOF &&
671+
100000 <[email protected]> refs/tags/multi-ref2-100000-user1
672+
100000 <[email protected]> refs/tags/multi-ref1-100000-user1
673+
100000 <[email protected]> refs/tags/multi-ref2-100000-user2
674+
100000 <[email protected]> refs/tags/multi-ref1-100000-user2
675+
200000 <[email protected]> refs/tags/multi-ref2-200000-user1
676+
200000 <[email protected]> refs/tags/multi-ref1-200000-user1
677+
200000 <[email protected]> refs/tags/multi-ref2-200000-user2
678+
200000 <[email protected]> refs/tags/multi-ref1-200000-user2
679+
EOF
680+
git for-each-ref \
681+
--format="%(taggerdate:unix) %(taggeremail) %(refname)" \
682+
--sort=-refname \
683+
--sort=taggeremail \
684+
--sort=taggerdate \
685+
"refs/tags/multi-*" >actual &&
661686
test_cmp expected actual
662687
'
663688

689+
test_expect_success 'equivalent sorts fall back on refname' '
690+
cat >expected <<-\EOF &&
691+
100000 <[email protected]> refs/tags/multi-ref1-100000-user1
692+
100000 <[email protected]> refs/tags/multi-ref1-100000-user2
693+
100000 <[email protected]> refs/tags/multi-ref2-100000-user1
694+
100000 <[email protected]> refs/tags/multi-ref2-100000-user2
695+
200000 <[email protected]> refs/tags/multi-ref1-200000-user1
696+
200000 <[email protected]> refs/tags/multi-ref1-200000-user2
697+
200000 <[email protected]> refs/tags/multi-ref2-200000-user1
698+
200000 <[email protected]> refs/tags/multi-ref2-200000-user2
699+
EOF
700+
git for-each-ref \
701+
--format="%(taggerdate:unix) %(taggeremail) %(refname)" \
702+
--sort=taggerdate \
703+
"refs/tags/multi-*" >actual &&
704+
test_cmp expected actual
705+
'
664706

665707
test_expect_success 'do not dereference NULL upon %(HEAD) on unborn branch' '
666708
test_when_finished "git checkout master" &&
@@ -895,4 +937,44 @@ test_expect_success 'for-each-ref --ignore-case ignores case' '
895937
test_cmp expect actual
896938
'
897939

940+
test_expect_success 'for-each-ref --ignore-case works on multiple sort keys' '
941+
# name refs numerically to avoid case-insensitive filesystem conflicts
942+
nr=0 &&
943+
for email in a A b B
944+
do
945+
for subject in a A b B
946+
do
947+
GIT_COMMITTER_EMAIL="[email protected]" \
948+
git tag -m "tag $subject" icase-$(printf %02d $nr) &&
949+
nr=$((nr+1))||
950+
return 1
951+
done
952+
done &&
953+
git for-each-ref --ignore-case \
954+
--format="%(taggeremail) %(subject) %(refname)" \
955+
--sort=refname \
956+
--sort=subject \
957+
--sort=taggeremail \
958+
refs/tags/icase-* >actual &&
959+
cat >expect <<-\EOF &&
960+
<[email protected]> tag a refs/tags/icase-00
961+
<[email protected]> tag A refs/tags/icase-01
962+
<[email protected]> tag a refs/tags/icase-04
963+
<[email protected]> tag A refs/tags/icase-05
964+
<[email protected]> tag b refs/tags/icase-02
965+
<[email protected]> tag B refs/tags/icase-03
966+
<[email protected]> tag b refs/tags/icase-06
967+
<[email protected]> tag B refs/tags/icase-07
968+
<[email protected]> tag a refs/tags/icase-08
969+
<[email protected]> tag A refs/tags/icase-09
970+
<[email protected]> tag a refs/tags/icase-12
971+
<[email protected]> tag A refs/tags/icase-13
972+
<[email protected]> tag b refs/tags/icase-10
973+
<[email protected]> tag B refs/tags/icase-11
974+
<[email protected]> tag b refs/tags/icase-14
975+
<[email protected]> tag B refs/tags/icase-15
976+
EOF
977+
test_cmp expect actual
978+
'
979+
898980
test_done

0 commit comments

Comments
 (0)