git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
From: "Øystein Walle" <oystwa@gmail.com>
To: gitster@pobox.com
Cc: git@vger.kernel.org, oystwa@gmail.com
Subject: Re: [PATCH 2/2] branch, for-each-ref: add option to omit empty lines
Date: Fri, 31 Mar 2023 10:32:13 +0200	[thread overview]
Message-ID: <20230331083213.12013-1-oystwa@gmail.com> (raw)
In-Reply-To: <xmqqilei1bgk.fsf@gitster.g>

Hi Junio,

On Thu, 30 Mar 2023 at 17:54, Junio C Hamano <gitster@pobox.com> wrote:

> While I can see the utility of the new feature, it is unclear if its
> merit is so clear that it deserves a short-and-sweet single letter
> option from the get go.  Especially, don't we want to give this to
> "git branch" and "git tag" in their listing modes for consistency,
> but it means stealing "-n" also from them.

I had this in mind, but I wanted to add a short option because
"--omit-empty-lines" is already longer than "| sed '/^$/d' |" :D Which
is the workaround I've used in the past. I see that later in your reply
you write "--omit-empty". (Perhaps instinctively?) The "line" part is
already implied so I'd be equally happy with "--omit-empty". I realize
that the parser already allows this implicitly, but the full name of the
option should be spelt out in the docs, I assume.

> Move that opening brace at the end of the previous line, i.e.
>
> -       if (list)
> +       if (list) {

Of course, my bad. Old habits and so on. But I may not need to change
this at all in the first place because...

> > +             if (omit_empty_lines && !format.format) {
> > +                     error("--omit-empty-lines without --format does not make sense");
> > +                     usage_with_options(builtin_branch_usage, options);
> > +             }
>
> Does it not make sense?  With the default format, it may happen that
> there will be no empty line so there is nothing to omit, but I do
> not see a strong reason to forbid the request like this.

... it's perfectly fine by me to allow --omit-empty when the user has
not specified their own format. I added this merely as guidance for the
user. For example, Git will bail out with a similar message if the user
tries to unshallow a repository that is already complete, which I assume
is technically not a problem.

> >               setup_auto_pager("branch", 1);
> > +     }
> >
> >       if (delete) {
> >               if (!argc)
> > diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
> > index 6f62f40d12..349c4d4ef8 100644
> > --- a/builtin/for-each-ref.c
> > +++ b/builtin/for-each-ref.c
> > @@ -19,7 +19,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
> >       int i;
> >       struct ref_sorting *sorting;
> >       struct string_list sorting_options = STRING_LIST_INIT_DUP;
> > -     int maxcount = 0, icase = 0;
> > +     int maxcount = 0, icase = 0, omit_empty_lines = 0;
> >       struct ref_array array;
> >       struct ref_filter filter;
> >       struct ref_format format = REF_FORMAT_INIT;
> > @@ -35,6 +35,8 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
> >                       N_("quote placeholders suitably for python"), QUOTE_PYTHON),
> >               OPT_BIT(0 , "tcl",  &format.quote_style,
> >                       N_("quote placeholders suitably for Tcl"), QUOTE_TCL),
> > +             OPT_BOOL('n' , "omit-empty-lines",  &omit_empty_lines,
> > +                     N_("do not output a newline after empty formatted refs")),
> >
> >               OPT_GROUP(""),
> >               OPT_INTEGER( 0 , "count", &maxcount, N_("show only <n> matched refs")),
> > @@ -55,8 +57,6 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
> >       memset(&array, 0, sizeof(array));
> >       memset(&filter, 0, sizeof(filter));
> >
> > -     format.format = "%(objectname) %(objecttype)\t%(refname)";
> > -
> >       git_config(git_default_config, NULL);
> >       parse_options(argc, argv, prefix, opts, for_each_ref_usage, 0);
>
> This smells fishy.  We establish the hardcoded built-in default, let
> the config machinery override, and then finally let command line
> options to further override.  You may be able to reach the same end
> result by leaving the value unset, fill with the configured value,
> override with the command line, and then if the value is still
> unset, fall back to a hardcoded built-in default, but I do not see
> why such a change logically belongs to a patch to add "--omit-empty"
> feature.

This is what I did. I moved the assignment of the default value of
format.format to after parse_options() so that I could use its (lack of)
value to determine whether --format had been specified by the user,
instead of e.g. "int format_was_given = 0;". But then I of course have
to check whether parse_options() already has assigned it before maybe
assigning the default value.

But I only did all of that to be able to die with the error. If we just
allow --omit-empty then all of this can be left alone, making the code,
and the patch, simpler.

> > @@ -68,6 +68,12 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
> >               error("more than one quoting style?");
> >               usage_with_options(for_each_ref_usage, opts);
> >       }
> > +     if (omit_empty_lines && !format.format) {
> > +             error("--omit-empty-lines without --format does not make sense");
> > +             usage_with_options(for_each_ref_usage, opts);
> > +     }
>
> I wouldn't do this, for the same reason as for "git branch".
>
> > +     if (!format.format)
> > +             format.format = "%(objectname) %(objecttype)\t%(refname)";
>
> This is the other half of the earlier change I called "fishy".  It
> may be benign, but it is distracting, especially when done without
> explanation, in a change to add a feature that is not related.

It *was* related, because of the error I wanted to provide. But maybe it
isn't anymore :P

>  * do not compare output.len with 0; it is sufficient to just write
>
>         if (!omit_empty || output.len)
>

Sure, will change. Peff addressed your second point already. But perhaps
move fwrite() (or whatever other printing function) inside the if() too?

> It is hard to see that there is an empty line expected when the
> expectation is prepared like this.  Why not something like
>
>         cat >expect.full <<-\EOF &&
>         one
>         two
>
>         four (three is missing)
>         EOF
>         sed -e "/^$/d" expect.full >expect.stripped &&
>
>         git branch $args >actual &&
>         test_cmp expect.full actual &&
>
>         git branch --omit-empty $args >actual &&
>         test_cmp expect.stripped actual &&
>
> that highlights the fact that there is a missing line for one
> expectation, and that the only difference in two expectations is the
> lack of empty line(s)?

I wholeheartedly agree. I only wrote it this way because actually having
an empty line there lead to a whitespace error in the patch. But that
was because I mistakenly assumed that empty lines in an indented heredoc
also had to be prefixed by a TAB and I didn't investigate. Will fix.

> > diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
> > index c466fd989f..eec9d45513 100755
> > --- a/t/t6300-for-each-ref.sh
> > +++ b/t/t6300-for-each-ref.sh
> > @@ -1374,6 +1374,14 @@ test_expect_success 'for-each-ref --ignore-case ignores case' '
> >       test_cmp expect actual
> >  '
> >
> > +test_expect_success 'for-each-ref --omit-empty-lines works' '
> > +     git for-each-ref --format="%(refname)" > actual &&
> > +     test_line_count -gt 1 actual &&
>
> The next test depends on that a branch 'main' exists, so perhaps
> that should be tested here, at least?  And then if there is no other
> branches and tags, we cannot tell if seeing only the 'main' branch
> is due to --omit-empty correctly working, or due to the repository
> having only that branch, so it is also good to check if there is
> branches or tags other than 'main' in the output.

In general I find it very hard to write meaningful tests because of
stuff like this this. In my (admittedly very limited) experience there
are usually big dependencies on prior tests in a particular test case,
and I just assumed that was okay. I often find it hard to discover what
the state of the repository is at the point in the test script where I
want to add a test, or modify an existing one.

In this particular case I know from the test case right above that main
exists. What is not immediately obvious is that at least one other ref
exists. But if that ever changes then at least 'test_line_count -gt 1
actual' will fail.

> By the way, lose SP between redirection operator '>' and its target,
> i.e. write them like so:
>
>         echo refs/heads/main >expect

Will fix.

> This feature makes %(if)...%(else)...%(end) construct complete and
> is a very good addition.
>
> Thanks for working on it.
>

Thanks for the review!

Øsse

  parent reply	other threads:[~2023-03-31  8:32 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-03-30 11:21 [PATCH 0/2] branch, for-each-ref: add option to omit empty lines Øystein Walle
2023-03-30 11:21 ` [PATCH 1/2] ref-filter: remove unused ref_format member Øystein Walle
2023-03-30 15:21   ` Junio C Hamano
2023-03-30 15:25     ` Junio C Hamano
2023-03-31 10:37       ` Øystein Walle
2023-03-31 10:57         ` ZheNing Hu
2023-03-31 16:19         ` Junio C Hamano
2023-04-06 17:08           ` [PATCH v2 0/2] branch, for-each-ref: add option to omit empty lines Øystein Walle
2023-04-06 17:08             ` [PATCH v2 1/2] ref-filter: remove unused ref_format member Øystein Walle
2023-04-06 17:08             ` [PATCH v2 2/2] branch, for-each-ref: add option to omit empty lines Øystein Walle
2023-04-06 18:24             ` [PATCH v2 0/2] " Junio C Hamano
2023-04-07 17:53               ` [PATCH v3] branch, for-each-ref, tag: " Øystein Walle
2023-04-07 18:48                 ` Junio C Hamano
2023-04-12 23:44                 ` Andrei Rybak
2023-04-13  7:17                   ` Øystein Walle
2023-04-13 15:13                     ` Junio C Hamano
2023-03-30 11:21 ` [PATCH 2/2] branch, for-each-ref: " Øystein Walle
2023-03-30 15:54   ` Junio C Hamano
2023-03-30 18:25     ` Jeff King
2023-03-30 18:54       ` Junio C Hamano
2023-03-31  8:32     ` Øystein Walle [this message]
2023-03-31 15:57       ` Junio C Hamano
2023-03-30 17:21   ` Junio C Hamano
2023-03-31 16:33   ` Phillip Wood
2023-03-31 17:17     ` Junio C Hamano
2023-04-06 16:55       ` Øystein Walle
2023-04-06 17:12         ` Jeff King
2023-04-06 18:20           ` Junio C Hamano
2023-04-10 19:56             ` Jeff King
2023-04-06 18:07         ` Junio C Hamano

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: http://vger.kernel.org/majordomo-info.html

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230331083213.12013-1-oystwa@gmail.com \
    --to=oystwa@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).