Hi,
sorry for top-posting, but I just noticed the "firstlyxy" typo in the
subject ;-)
Ciao,
Dscho
On Sun, 9 Jun 2019, Johannes Schindelin wrote:
> Hi Matthew,
>
> On Thu, 6 Jun 2019, Matthew DeVore wrote:
>
> > 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.
>
> This description is pretty convincing!
>
> > 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) {
>
> I find that it makes sense in general to suppress one's urges regarding
> introducing `{ ... }` around one-liners when the patch does not actually
> require it.
>
> For example, I found this patch harder than necessary to read because of
> it.
>
> > + if ((a->kind & FILTER_REFS_DETACHED_HEAD) !=
> > + (b->kind & FILTER_REFS_DETACHED_HEAD)) {
>
> So in case that both are detached...
>
> > + return (a->kind & FILTER_REFS_DETACHED_HEAD) ? -1 : 1;
> > + }
> > cmp = cmp_fn(va->s, vb->s);
>
> ... we compare their commit hashes, is that right? Might be worth a code
> comment.
>
> > - else {
> > + } else {
>
> FWIW it would have been a much more obvious patch if it had done
>
> if (s->version)
> [...]
> + else if (cmp_type == FIELD_STR &&
> + (a->kind & FILTER_REFS_DETACHED_HEAD ||
> + b->kind & FILTER_REFS_DETACHED_HEAD))
> + return (a->kind & FILTER_REFS_DETACHED_HEAD) ? -1 : 1;
> else if (cmp_type == FIELD_STR)
> [...]
>
> Maybe still worth doing.
>
> FWIW I was *so* tempted to write
>
> ((a->kind ^ b->kind) & FILTER_REFS_DETACHED_HEAD)
>
> to make this code DRYer, but then, readers not intimately familiar with
> Boolean arithmetic might not even know about the `^` operator, making the
> code harder to read than necessary, too.
>
> > 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
>
> I wonder why this hunk, unlike the previous one, does not imitate the
> is_IS handling closely.
>
> > 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 &&
>
> Why?
>
> > + touch r1/foo &&
> > + git -C r1 add foo &&
> > + git -C r1 commit -m foo
> > +'
>
> Why not simply `test_commit 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 &&
>
> I am not sure that `!` is a wise choice, as it might not be a legal file
> name character everywhere. A `.` or `-` might make more sense.
>
> > + LC_ALL=$zh_CN_locale LC_MESSAGES=$zh_CN_locale \
> > + git -C r1 branch >actual &&
> > + git -C r1 checkout - &&
>
> Why call `checkout` after `branch`? That's unnecessary, we do not verify
> anything after that call.
>
> > + 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
>
> This might look beautiful for a fan of `awk`. For the vast majority of us,
> this is not a good idea.
>
> Remember, you do *not* write those tests for your own pleasure, you do
> *not* write those tests in order to help you catch problems while you
> develop your patches, you do *not* develop these tests in order to just
> catch future breakages.
>
> You *do* write those tests for *other* developers who you try to help in
> preventing introducing regressions.
>
> As such, you *want* the tests to be
>
> - easy to understand for as wide a range of developers as you can make,
>
> - quick,
>
> - covering regressions, and *only* regressions,
>
> - helping diagnose *and* fix regressions.
>
> In the ideal case you won't even hear when developers found your test
> helpful, and you will never, ever learn about regressions that have been
> prevented.
>
> You most frequently will hear about your tests when they did not do their
> job well.
>
> In this instance, I would have expected something like
>
> test_expect_lines = 3 actual &&
>
> head -n 1 <actual >first &&
> test_i18ngrep "detached HEAD" first &&
>
> tail -n 1 <actual >last &&
> grep should_be_after last
>
> instead of the "awk-ward" code above.
>
> Ciao,
> Johannes
>
> > +'
> > +
> > +test_done
> > --
> > 2.21.0
> >
> >
>