Before this patch, "git branch" would put "(HEAD detached...)" and "(no branch, rebasing...)" lines before all the other branches *in most cases* and only because of the fact that "(" is a low codepoint. This would not hold in the Chinese locale, which uses a full-width "(" symbol (codepoint FF08). This meant that the detached HEAD line would appear after all local refs and even after the remote refs if there were any. Deliberately sort the detached HEAD refs before other refs when sorting by refname rather than rely on codepoint subtleties. Signed-off-by: Matthew DeVore <matvore@xxxxxxxxxx> --- ref-filter.c | 10 +++++++--- t/lib-gettext.sh | 16 +++++++++++++--- t/t3207-branch-intl.sh | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 6 deletions(-) create mode 100755 t/t3207-branch-intl.sh diff --git a/ref-filter.c b/ref-filter.c index 8500671bc6..cbfae790f9 100644 --- a/ref-filter.c +++ b/ref-filter.c @@ -2157,25 +2157,29 @@ static int cmp_ref_sorting(struct ref_sorting *s, struct ref_array_item *a, stru cmp_type cmp_type = used_atom[s->atom].type; int (*cmp_fn)(const char *, const char *); struct strbuf err = STRBUF_INIT; if (get_ref_atom_value(a, s->atom, &va, &err)) die("%s", err.buf); if (get_ref_atom_value(b, s->atom, &vb, &err)) die("%s", err.buf); strbuf_release(&err); cmp_fn = s->ignore_case ? strcasecmp : strcmp; - if (s->version) + if (s->version) { cmp = versioncmp(va->s, vb->s); - else if (cmp_type == FIELD_STR) + } else if (cmp_type == FIELD_STR) { + if ((a->kind & FILTER_REFS_DETACHED_HEAD) != + (b->kind & FILTER_REFS_DETACHED_HEAD)) { + return (a->kind & FILTER_REFS_DETACHED_HEAD) ? -1 : 1; + } cmp = cmp_fn(va->s, vb->s); - else { + } else { if (va->value < vb->value) cmp = -1; else if (va->value == vb->value) cmp = cmp_fn(a->refname, b->refname); else cmp = 1; } return (s->reverse) ? -cmp : cmp; } diff --git a/t/lib-gettext.sh b/t/lib-gettext.sh index 2139b427ca..de08d109dc 100644 --- a/t/lib-gettext.sh +++ b/t/lib-gettext.sh @@ -25,23 +25,29 @@ then p q }') # is_IS.ISO8859-1 on Solaris and FreeBSD, is_IS.iso88591 on Debian is_IS_iso_locale=$(locale -a 2>/dev/null | sed -n '/^is_IS\.[iI][sS][oO]8859-*1$/{ p q }') - # Export them as an environment variable so the t0202/test.pl Perl - # test can use it too - export is_IS_locale is_IS_iso_locale + zh_CN_locale=$(locale -a 2>/dev/null | + sed -n '/^zh_CN\.[uU][tT][fF]-*8$/{ + p + q + }') + + # Export them as environment variables so other tests can use them + # too + export is_IS_locale is_IS_iso_locale zh_CN_locale if test -n "$is_IS_locale" && test $GIT_INTERNAL_GETTEXT_SH_SCHEME != "fallthrough" then # Some of the tests need the reference Icelandic locale test_set_prereq GETTEXT_LOCALE # Exporting for t0202/test.pl GETTEXT_LOCALE=1 export GETTEXT_LOCALE @@ -53,11 +59,15 @@ then if test -n "$is_IS_iso_locale" && test $GIT_INTERNAL_GETTEXT_SH_SCHEME != "fallthrough" then # Some of the tests need the reference Icelandic locale test_set_prereq GETTEXT_ISO_LOCALE say "# lib-gettext: Found '$is_IS_iso_locale' as an is_IS ISO-8859-1 locale" else say "# lib-gettext: No is_IS ISO-8859-1 locale available" fi + + if test -z "$zh_CN_locale"; then + say "# lib-gettext: No zh_CN UTF-8 locale available" + fi fi diff --git a/t/t3207-branch-intl.sh b/t/t3207-branch-intl.sh new file mode 100755 index 0000000000..9f6fcc7481 --- /dev/null +++ b/t/t3207-branch-intl.sh @@ -0,0 +1,38 @@ +#!/bin/sh + +test_description='git branch internationalization tests' + +. ./lib-gettext.sh + +test_expect_success 'init repo' ' + git init r1 && + touch r1/foo && + git -C r1 add foo && + git -C r1 commit -m foo +' + +test_expect_success 'detached head sorts before other branches' ' + # Ref sorting logic should put detached heads before the other + # branches, but this is not automatic when a branch name sorts + # lexically before "(" or the full-width "(" (Unicode codepoint FF08). + # The latter case is nearly guaranteed for the Chinese locale. + + git -C r1 checkout HEAD^{} -- && + git -C r1 branch !should_be_after_detached HEAD && + LC_ALL=$zh_CN_locale LC_MESSAGES=$zh_CN_locale \ + git -C r1 branch >actual && + git -C r1 checkout - && + + awk " + # We need full-width or half-width parens on the first line. + NR == 1 && (/[(].*[)]/ || /\xef\xbc\x88.*\xef\xbc\x89/) { + found_head = 1; + } + /!should_be_after_detached/ { + found_control_branch = 1; + } + END { exit !found_head || !found_control_branch } + " actual +' + +test_done -- 2.21.0