* Git branch outputs usage message on stderr @ 2025-01-15 11:21 Jonas Konrad 2025-01-15 11:36 ` Matěj Cepl 0 siblings, 1 reply; 27+ messages in thread From: Jonas Konrad @ 2025-01-15 11:21 UTC (permalink / raw) To: git [-- Attachment #1: Type: text/plain, Size: 2137 bytes --] Hey, please find the report below. What did you do before the bug happened? (Steps to reproduce your issue) I opened a terminal on Arch Linux with a bash shell and called `git branch -h` to get a usage overview of git's `branch` command. I then tried processing the output with `grep` by `git branch -h | grep list` which gave the whole (unfiltered) output, i.e., the displayed message was not processed by `grep`. What did you expect to happen? (Expected behavior) Pipe redirects stdout to grep (here: usage info of git branch) and grep can filter it. What happened instead? (Actual behavior) `git branch -h` output was not redirected to `grep`. Instead, it went to stderr, bypassing the pipe. Using `|&` as pipe gives the expected result and confirms that the usage output is indeed redirected to stderr. What's different between what you expected and what actually happened? To me, `git branch -h` (invoked without any non-valid option) shall output its help/usage message to stdout, and exit without error status (exit status 0). Anything else you want to add: In fact, `git branch -h` exits with a non-zero status. This is coherent with outputting the usage message on stderr and made me think the behavior could be intended. I can hardly imagine, as outputting usage info to stderr to me only made sense if `git branch` is invoked with, e.g., a non-valid option (if at all). I would prefer the usage output on stderr even in this case, but allow for a non-zero exit status of git branch. Also, `git -h` gives its output on stdout. [System Info] git version: git version 2.48.1 cpu: x86_64 no commit associated with this build sizeof-long: 8 sizeof-size_t: 8 shell-path: /bin/sh libcurl: 8.11.1 OpenSSL: OpenSSL 3.4.0 22 Oct 2024 zlib: 1.3.1 uname: Linux 6.12.8-arch1-1 #1 SMP PREEMPT_DYNAMIC Thu, 02 Jan 2025 22:52:26 +0000 x86_64 compiler info: gnuc: 14.2 libc info: glibc: 2.40 $SHELL (typically, interactive shell): /bin/bash Best, -- Jonas Konrad, PhD Student Institute for Geoinformatics, University Münster Heisenbergstr. 2, 48149 Münster [-- Attachment #2: S/MIME Cryptographic Signature --] [-- Type: application/pkcs7-signature, Size: 6990 bytes --] ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Git branch outputs usage message on stderr 2025-01-15 11:21 Git branch outputs usage message on stderr Jonas Konrad @ 2025-01-15 11:36 ` Matěj Cepl 2025-01-15 14:47 ` Jonas Konrad 2025-01-15 15:28 ` Junio C Hamano 0 siblings, 2 replies; 27+ messages in thread From: Matěj Cepl @ 2025-01-15 11:36 UTC (permalink / raw) To: Jonas Konrad, git [-- Attachment #1.1.1: Type: text/plain, Size: 990 bytes --] On Wed Jan 15, 2025 at 12:22 PM CET, Jonas Konrad wrote: > What did you do before the bug happened? (Steps to reproduce your issue) > I opened a terminal on Arch Linux with a bash shell and called `git > branch -h` to get a usage overview of git's `branch` command. I then > tried processing the output with `grep` by `git branch -h | grep list` > which gave the whole (unfiltered) output, i.e., the displayed message > was not processed by `grep`. And that is exactly the correct behaviour. In the world of UNIX, where pipes are normal, utilities should send to the stdout only substantial material, which could be processed down the pipeline. Error messages, help, and similar diagnostics, should go to stderr. Also, you know about `|&`, right? Best, Matěj -- http://matej.ceplovi.cz/blog/, @mcepl@en.osm.town GPG Finger: 3C76 A027 CA45 AD70 98B5 BC1D 7920 5802 880B C9D8 Thou shalt not lie. Thou shalt not deceive one another. -- Leviticus 19:11 [-- Attachment #1.2: E09FEF25D96484AC.asc --] [-- Type: application/pgp-keys, Size: 3102 bytes --] -----BEGIN PGP PUBLIC KEY BLOCK----- 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 wwCdEnRlCGlvnO78R0FgKXlt3RyzGuE= =sxoW -----END PGP PUBLIC KEY BLOCK----- [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 216 bytes --] ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Git branch outputs usage message on stderr 2025-01-15 11:36 ` Matěj Cepl @ 2025-01-15 14:47 ` Jonas Konrad 2025-01-15 15:28 ` Junio C Hamano 1 sibling, 0 replies; 27+ messages in thread From: Jonas Konrad @ 2025-01-15 14:47 UTC (permalink / raw) To: Matěj Cepl, git [-- Attachment #1: Type: text/plain, Size: 1844 bytes --] Well, let me add that one detail: I could not find any other git sub command which behaves the same (admittedly haven't tried all). Instead, the ones I have tried give their help output usually on stdout. Try yourself with `git -h`. It perfectly acts according to what I'd expect (exit status 0). Where as `git reflog -h`outputs to stdout but still exit with non-zero status (which seems okay). `git branch -h` adds a third way, as described. I argue: That diverging behavior is confusing to the user. If your claim was right, this bug report got even bigger as a lot of behavior from other subcommands would have to be changed. In fact, what "substantial material" is, has to be defined for every piece of software regarding each output. However, I cannot see how one subcommand's usage message is considered "substantial" whereas another subcommand's usage message is not (besides, I guess, `git branch` is more frequently used than `git reflog`). Best, Jonas On 15.01.25 12:36, Matěj Cepl wrote: > On Wed Jan 15, 2025 at 12:22 PM CET, Jonas Konrad wrote: >> What did you do before the bug happened? (Steps to reproduce your issue) >> I opened a terminal on Arch Linux with a bash shell and called `git >> branch -h` to get a usage overview of git's `branch` command. I then >> tried processing the output with `grep` by `git branch -h | grep list` >> which gave the whole (unfiltered) output, i.e., the displayed message >> was not processed by `grep`. > And that is exactly the correct behaviour. In the world of UNIX, > where pipes are normal, utilities should send to the stdout > only substantial material, which could be processed down the > pipeline. Error messages, help, and similar diagnostics, should > go to stderr. Also, you know about `|&`, right? > > Best, > > Matěj > [-- Attachment #2: S/MIME Cryptographic Signature --] [-- Type: application/pkcs7-signature, Size: 6990 bytes --] ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Git branch outputs usage message on stderr 2025-01-15 11:36 ` Matěj Cepl 2025-01-15 14:47 ` Jonas Konrad @ 2025-01-15 15:28 ` Junio C Hamano 2025-01-15 16:55 ` Kristoffer Haugsbakk 1 sibling, 1 reply; 27+ messages in thread From: Junio C Hamano @ 2025-01-15 15:28 UTC (permalink / raw) To: Matěj Cepl; +Cc: Jonas Konrad, git Matěj Cepl <mcepl@cepl.eu> writes: > On Wed Jan 15, 2025 at 12:22 PM CET, Jonas Konrad wrote: >> What did you do before the bug happened? (Steps to reproduce your issue) >> I opened a terminal on Arch Linux with a bash shell and called `git >> branch -h` to get a usage overview of git's `branch` command. I then >> tried processing the output with `grep` by `git branch -h | grep list` >> which gave the whole (unfiltered) output, i.e., the displayed message >> was not processed by `grep`. > > And that is exactly the correct behaviour. In the world of UNIX, > where pipes are normal, utilities should send to the stdout > only substantial material, ... If I understand the case Jonas reports correctly, he is talking about "git branch -h<RETURN>", and the "substantial material" (I'd rather phrase it as the primary output in response to the end user request) in that case is the help text. Somebody may want to go over "git help --all" and for each of them try "git $cmd -h >/dev/null" to find those that give the help output to their standard error stream. Thanks, both. ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Git branch outputs usage message on stderr 2025-01-15 15:28 ` Junio C Hamano @ 2025-01-15 16:55 ` Kristoffer Haugsbakk 2025-01-15 17:14 ` Jeff King ` (2 more replies) 0 siblings, 3 replies; 27+ messages in thread From: Kristoffer Haugsbakk @ 2025-01-15 16:55 UTC (permalink / raw) To: Junio C Hamano, Matěj Cepl; +Cc: Jonas Konrad, git On Wed, Jan 15, 2025, at 16:28, Junio C Hamano wrote: > Somebody may want to go over "git help --all" and for each of them > try "git $cmd -h >/dev/null" to find those that give the help output > to their standard error stream. #!/bin/sh for cmd in $(git --list-cmds=builtins); do git $cmd -h >/dev/null done 2>&1 | grep '^usage: ' \ | perl -pe 's/^usage:\s*(\(EXPERIMENTAL!\)\s*)?//; s/^(git\s+[a-zA-Z0-9-]+).*/\1/' Gives git am git branch git check-ref-format git checkout--worker git checkout-index git commit git commit-tree git credential git diff git diff-files git diff-index git diff-tree git fast-import git fetch-pack git fsmonitor--daemon git gc git get-tar-commit-id git index-pack git ls-files git mailsplit git merge git merge-index git merge-ours git merge-recursive git merge-recursive-ours git merge-recursive-theirs git merge-subtree git pack-redundant git rebase git remote-ext git remote-fd git rev-list git rev-parse git status git unpack-file git unpack-objects git update-index git upload-archive git upload-archive git var For $ git version git version 2.48.0 ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Git branch outputs usage message on stderr 2025-01-15 16:55 ` Kristoffer Haugsbakk @ 2025-01-15 17:14 ` Jeff King 2025-01-15 17:49 ` Junio C Hamano 2025-01-15 17:56 ` Junio C Hamano 2025-01-15 17:14 ` Jonas Konrad 2025-01-15 17:19 ` Junio C Hamano 2 siblings, 2 replies; 27+ messages in thread From: Jeff King @ 2025-01-15 17:14 UTC (permalink / raw) To: Kristoffer Haugsbakk; +Cc: Junio C Hamano, Matěj Cepl, Jonas Konrad, git On Wed, Jan 15, 2025 at 05:55:19PM +0100, Kristoffer Haugsbakk wrote: > On Wed, Jan 15, 2025, at 16:28, Junio C Hamano wrote: > > Somebody may want to go over "git help --all" and for each of them > > try "git $cmd -h >/dev/null" to find those that give the help output > > to their standard error stream. > > #!/bin/sh > > for cmd in $(git --list-cmds=builtins); do > git $cmd -h >/dev/null > done 2>&1 | grep '^usage: ' \ > | perl -pe 's/^usage:\s*(\(EXPERIMENTAL!\)\s*)?//; s/^(git\s+[a-zA-Z0-9-]+).*/\1/' > [...] We may want: diff --git a/t/t0012-help.sh b/t/t0012-help.sh index 1d273d91c2..469cb12eb2 100755 --- a/t/t0012-help.sh +++ b/t/t0012-help.sh @@ -255,7 +255,8 @@ do ( GIT_CEILING_DIRECTORIES=$(pwd) && export GIT_CEILING_DIRECTORIES && - test_expect_code 129 git -C sub $builtin -h >output 2>&1 + test_expect_code 129 git -C sub $builtin -h >output 2>err && + test_must_be_empty err ) && test_grep usage output ' which produces a similar list. In the case of git-branch, it is due to 1dacfbcf13 (branch -h: show usage even in an invalid repository, 2010-10-22). Instead of letting parse-options handle it (which then goes to stdout), we call usage_with_options(), which is usually for complaining about a broken option, not showing "-h". The reason there is that some of the pre-parse_options() setup accesses the ref store (causing a BUG() if you run "branch -h" outside of a repository). In this case, I think it can simply be reordered like: diff --git a/builtin/branch.c b/builtin/branch.c index 6e7b0cfddb..4617e32fff 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -784,31 +784,28 @@ int cmd_branch(int argc, filter.kind = FILTER_REFS_BRANCHES; filter.abbrev = -1; - if (argc == 2 && !strcmp(argv[1], "-h")) - usage_with_options(builtin_branch_usage, options); - /* * Try to set sort keys from config. If config does not set any, * fall back on default (refname) sorting. */ git_config(git_branch_config, &sorting_options); if (!sorting_options.nr) string_list_append(&sorting_options, "refname"); track = git_branch_track; + argc = parse_options(argc, argv, prefix, options, builtin_branch_usage, + 0); + head = refs_resolve_refdup(get_main_ref_store(the_repository), "HEAD", 0, &head_oid, NULL); if (!head) die(_("failed to resolve HEAD as a valid ref")); if (!strcmp(head, "HEAD")) filter.detached = 1; else if (!skip_prefix(head, "refs/heads/", &head)) die(_("HEAD not found below refs/heads!")); - argc = parse_options(argc, argv, prefix, options, builtin_branch_usage, - 0); - if (!delete && !rename && !copy && !edit_description && !new_upstream && !show_current && !unset_upstream && argc == 0) list = 1; Knowing that is safe means confirming manually that setup code is not needed by parse_options(). E.g., if it were setting defaults the user could overwrite with an option. In this case neither "head" nor "filter.detached" is touched by any of the options. But there are a ton of commands, as you saw, and handling each one would be a pain. So it would probably be easier to just introduce a variant of usage_with_options() that writes to stdout (the underlying _internal function already does so, we'd just need a one-liner wrapper). And then use that everywhere. Possibly it could even do the argc/argv check, too, since every call site is going to be doing that itself. -Peff ^ permalink raw reply related [flat|nested] 27+ messages in thread
* Re: Git branch outputs usage message on stderr 2025-01-15 17:14 ` Jeff King @ 2025-01-15 17:49 ` Junio C Hamano 2025-01-15 17:56 ` Junio C Hamano 1 sibling, 0 replies; 27+ messages in thread From: Junio C Hamano @ 2025-01-15 17:49 UTC (permalink / raw) To: Jeff King; +Cc: Kristoffer Haugsbakk, Matěj Cepl, Jonas Konrad, git Jeff King <peff@peff.net> writes: > But there are a ton of commands, as you saw, and handling each one would > be a pain. So it would probably be easier to just introduce a variant of > usage_with_options() that writes to stdout (the underlying _internal > function already does so, we'd just need a one-liner wrapper). Yup, I was looking at the code involved and came to the same conclusion. ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Git branch outputs usage message on stderr 2025-01-15 17:14 ` Jeff King 2025-01-15 17:49 ` Junio C Hamano @ 2025-01-15 17:56 ` Junio C Hamano 2025-01-15 18:24 ` Jeff King 2025-01-15 18:29 ` Junio C Hamano 1 sibling, 2 replies; 27+ messages in thread From: Junio C Hamano @ 2025-01-15 17:56 UTC (permalink / raw) To: Jeff King; +Cc: Kristoffer Haugsbakk, Matěj Cepl, Jonas Konrad, git Jeff King <peff@peff.net> writes: > use that everywhere. Possibly it could even do the argc/argv check, too, > since every call site is going to be doing that itself. It would look something like this; I am not sure if I like the "this may show help and exit if the user requested, but otherwise it is a no-op" semantics, though. builtin/am.c | 3 +-- parse-options.c | 10 ++++++++++ parse-options.h | 4 ++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git c/builtin/am.c w/builtin/am.c index 370f5593f2..c9571f605a 100644 --- c/builtin/am.c +++ w/builtin/am.c @@ -2417,8 +2417,7 @@ int cmd_am(int argc, const char **argv, const char *prefix) OPT_END() }; - if (argc == 2 && !strcmp(argv[1], "-h")) - usage_with_options(usage, options); + show_usage_help(argc, argv, usage, options); git_config(git_default_config, NULL); diff --git c/parse-options.c w/parse-options.c index 30b9e68f8a..9419b174de 100644 --- c/parse-options.c +++ w/parse-options.c @@ -1276,6 +1276,16 @@ void NORETURN usage_with_options(const char * const *usagestr, exit(129); } +void show_usage_help(int ac, const char **av, + const char * const *usagestr, + const struct option *opts) +{ + if (ac == 2 && !strcmp(av[1], "-h")) { + usage_with_options_internal(NULL, usagestr, opts, 0, 0); + exit(0); + } +} + void NORETURN usage_msg_opt(const char *msg, const char * const *usagestr, const struct option *options) diff --git c/parse-options.h w/parse-options.h index ae15342390..75a7493350 100644 --- c/parse-options.h +++ w/parse-options.h @@ -388,6 +388,10 @@ int parse_options(int argc, const char **argv, const char *prefix, NORETURN void usage_with_options(const char * const *usagestr, const struct option *options); +void show_usage_help(int, const char **, + const char * const *usagestr, + const struct option *options); + NORETURN void usage_msg_opt(const char *msg, const char * const *usagestr, const struct option *options); ^ permalink raw reply related [flat|nested] 27+ messages in thread
* Re: Git branch outputs usage message on stderr 2025-01-15 17:56 ` Junio C Hamano @ 2025-01-15 18:24 ` Jeff King 2025-01-15 21:16 ` Junio C Hamano 2025-01-15 18:29 ` Junio C Hamano 1 sibling, 1 reply; 27+ messages in thread From: Jeff King @ 2025-01-15 18:24 UTC (permalink / raw) To: Junio C Hamano; +Cc: Kristoffer Haugsbakk, Matěj Cepl, Jonas Konrad, git On Wed, Jan 15, 2025 at 09:56:23AM -0800, Junio C Hamano wrote: > Jeff King <peff@peff.net> writes: > > > use that everywhere. Possibly it could even do the argc/argv check, too, > > since every call site is going to be doing that itself. > > It would look something like this; I am not sure if I like the "this > may show help and exit if the user requested, but otherwise it is a > no-op" semantics, though. Yeah, I agree it is funny to have a "maybe noop, maybe exit" function. Perhaps a different name would help? I'd expect show_usage_help() to always do what the name says. Maybe check_help_option() or something? > +void show_usage_help(int ac, const char **av, > + const char * const *usagestr, > + const struct option *opts) > +{ > + if (ac == 2 && !strcmp(av[1], "-h")) { > + usage_with_options_internal(NULL, usagestr, opts, 0, 0); > + exit(0); > + } > +} I think parse-options will exit(129) in this case, and that's what t0012 insists upon. -Peff ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Git branch outputs usage message on stderr 2025-01-15 18:24 ` Jeff King @ 2025-01-15 21:16 ` Junio C Hamano 2025-01-15 21:29 ` Jeff King 0 siblings, 1 reply; 27+ messages in thread From: Junio C Hamano @ 2025-01-15 21:16 UTC (permalink / raw) To: Jeff King; +Cc: Kristoffer Haugsbakk, Matěj Cepl, Jonas Konrad, git Jeff King <peff@peff.net> writes: > Yeah, I agree it is funny to have a "maybe noop, maybe exit" function. > Perhaps a different name would help? I'd expect show_usage_help() to > always do what the name says. Maybe check_help_option() or something? maybe_show_usage_help()? >> +void show_usage_help(int ac, const char **av, >> + const char * const *usagestr, >> + const struct option *opts) >> +{ >> + if (ac == 2 && !strcmp(av[1], "-h")) { >> + usage_with_options_internal(NULL, usagestr, opts, 0, 0); >> + exit(0); >> + } >> +} > > I think parse-options will exit(129) in this case, and that's what t0012 > insists upon. Yeah, but the test can be adjusted to updated reality if needed. In this case, the command is doing what the end-user asked it to do, and if we were writing the system from scratch, 0 would certainly be the right exit status in this case. If hit usage_with_options() because the command line option supplied by the user was nonsense, we should exit with non-zero, but I am not sure if exit(129) is a good idea here. ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Git branch outputs usage message on stderr 2025-01-15 21:16 ` Junio C Hamano @ 2025-01-15 21:29 ` Jeff King 2025-01-15 21:56 ` Junio C Hamano 2025-01-15 22:11 ` Junio C Hamano 0 siblings, 2 replies; 27+ messages in thread From: Jeff King @ 2025-01-15 21:29 UTC (permalink / raw) To: Junio C Hamano; +Cc: Kristoffer Haugsbakk, Matěj Cepl, Jonas Konrad, git On Wed, Jan 15, 2025 at 01:16:50PM -0800, Junio C Hamano wrote: > Jeff King <peff@peff.net> writes: > > > Yeah, I agree it is funny to have a "maybe noop, maybe exit" function. > > Perhaps a different name would help? I'd expect show_usage_help() to > > always do what the name says. Maybe check_help_option() or something? > > maybe_show_usage_help()? Heh, I almost suggested that one, too, but worried it was too clunky. But maybe since we both thought of it... > > I think parse-options will exit(129) in this case, and that's what t0012 > > insists upon. > > Yeah, but the test can be adjusted to updated reality if needed. > > In this case, the command is doing what the end-user asked it to do, > and if we were writing the system from scratch, 0 would certainly be > the right exit status in this case. If hit usage_with_options() > because the command line option supplied by the user was nonsense, > we should exit with non-zero, but I am not sure if exit(129) is a > good idea here. I certainly see an argument for exit(0), but whatever we do should be consistent with how parse-options handles it (since whether we use this or leave it to parse-options is purely an implementation detail that the user should not need to be aware of). And it uses code 129, even for "-h". I don't see any explicit rationale for that in the history; I think it goes back to the beginning of parse-options. It happens via the PARSE_OPT_HELP flag, but curiously we also trigger that for ambiguous options (which should exit with error). That might be a bug-in-waiting if we start handling PARSE_OPT_HELP differently. -Peff ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Git branch outputs usage message on stderr 2025-01-15 21:29 ` Jeff King @ 2025-01-15 21:56 ` Junio C Hamano 2025-01-15 22:27 ` Jeff King 2025-01-15 22:11 ` Junio C Hamano 1 sibling, 1 reply; 27+ messages in thread From: Junio C Hamano @ 2025-01-15 21:56 UTC (permalink / raw) To: Jeff King; +Cc: Kristoffer Haugsbakk, Matěj Cepl, Jonas Konrad, git Jeff King <peff@peff.net> writes: > I certainly see an argument for exit(0), but whatever we do should be > consistent with how parse-options handles it (since whether we use this > or leave it to parse-options is purely an implementation detail that the > user should not need to be aware of). > > And it uses code 129, even for "-h". I don't see any explicit rationale > for that in the history; I think it goes back to the beginning of > parse-options. It happens via the PARSE_OPT_HELP flag, but curiously we > also trigger that for ambiguous options (which should exit with error). > That might be a bug-in-waiting if we start handling PARSE_OPT_HELP > differently. Here is what I have as v2; there will be patches that touch builtin/*.c in between and I expect that the last patch to conclude the series will end with an update to parse-options.c (to exit with 0 when asked to give a help) and t0012 (to stop expecting 129). --- >8 --- Subject: [PATCH v2] parse-options: add show_usage_help_and_exit_if_asked() Many commands call usage_with_options() when they are asked to give the help message, but it incorrectly sends the help text to the standard error stream. When the user asked for it with "git cmd -h", the help message is the primary output from the command, hence we should send it to the standard output stream. Introduce a helper function that captures the common pattern if (argc == 2 && !strcmp(argv[1], "-h")) usage_with_options(usage, options); and replaces it with show_usage_help_and_exit_if_asked(argc, argv, usage, options); to help correct code paths (there are 40 or so of them). Note that this helper function still exits with status 129, and t0012 insists on it. After converting all the mistaken callers of usage_with_options() to call this new helper, we may want to address it---the end user is asking us to give the help text, and we are doing exactly as asked, so there is no reason to exit with non-zero status. Suggested-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- parse-options.c | 10 ++++++++++ parse-options.h | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/parse-options.c b/parse-options.c index 33bfba0ed4..8a8b934e67 100644 --- a/parse-options.c +++ b/parse-options.c @@ -1282,6 +1282,16 @@ void NORETURN usage_with_options(const char * const *usagestr, exit(129); } +void show_usage_help_and_exit_if_asked(int ac, const char **av, + const char * const *usagestr, + const struct option *opts) +{ + if (ac == 2 && !strcmp(av[1], "-h")) { + usage_with_options_internal(NULL, usagestr, opts, 0, 0); + exit(129); + } +} + void NORETURN usage_msg_opt(const char *msg, const char * const *usagestr, const struct option *options) diff --git a/parse-options.h b/parse-options.h index d01361ca97..6af4ee148a 100644 --- a/parse-options.h +++ b/parse-options.h @@ -402,6 +402,10 @@ int parse_options(int argc, const char **argv, const char *prefix, NORETURN void usage_with_options(const char * const *usagestr, const struct option *options); +void show_usage_help_and_exit_if_asked(int ac, const char **av, + const char * const *usage, + const struct option *options); + NORETURN void usage_msg_opt(const char *msg, const char * const *usagestr, const struct option *options); -- 2.48.1-187-gd93ffc6ef3 ^ permalink raw reply related [flat|nested] 27+ messages in thread
* Re: Git branch outputs usage message on stderr 2025-01-15 21:56 ` Junio C Hamano @ 2025-01-15 22:27 ` Jeff King 2025-01-15 23:32 ` Junio C Hamano 0 siblings, 1 reply; 27+ messages in thread From: Jeff King @ 2025-01-15 22:27 UTC (permalink / raw) To: Junio C Hamano; +Cc: Kristoffer Haugsbakk, Matěj Cepl, Jonas Konrad, git On Wed, Jan 15, 2025 at 01:56:31PM -0800, Junio C Hamano wrote: > Here is what I have as v2; there will be patches that touch > builtin/*.c in between and I expect that the last patch to conclude > the series will end with an update to parse-options.c (to exit with > 0 when asked to give a help) and t0012 (to stop expecting 129). > > --- >8 --- > Subject: [PATCH v2] parse-options: add show_usage_help_and_exit_if_asked() Thanks, this looks fine. The name is clunky but probably OK. ;) I don't know if we'd want something like this on top. If somebody is interested in just doing all the conversions in the near-term, we could do without the optional flag. -- >8 -- Subject: [PATCH] t0012: optionally check that "-h" output goes to stdout For most commands, "git foo -h" will send the help output to stdout, as this is what parse-options.c does. But some commands send it to stderr instead. This is usually because they call usage_with_options(), and should be switched to show_usage_help_and_exit_if_asked(). Currently t0012 is permissive and allows either behavior. We'd like it to eventually enforce that help goes to stdout, and teaching it to do so identifies the commands that need to be changed. But during the transition period, we don't want to enforce that for most test runs. So let's introduce a flag that will let most test runs use the permissive behavior, and people interested in converting commands can run: GIT_TEST_HELP_MUST_BE_STDOUT=1 ./t0012-help.sh to see the failures. Eventually (when all builtins have been converted) we'll remove this flag entirely and always check the strict behavior. Signed-off-by: Jeff King <peff@peff.net> --- t/t0012-help.sh | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/t/t0012-help.sh b/t/t0012-help.sh index 1d273d91c2..9c7ae9fd36 100755 --- a/t/t0012-help.sh +++ b/t/t0012-help.sh @@ -255,9 +255,16 @@ do ( GIT_CEILING_DIRECTORIES=$(pwd) && export GIT_CEILING_DIRECTORIES && - test_expect_code 129 git -C sub $builtin -h >output 2>&1 + test_expect_code 129 git -C sub $builtin -h >output 2>err ) && - test_grep usage output + if test -n "$GIT_TEST_HELP_MUST_BE_STDOUT" + then + test_must_be_empty err && + test_grep usage output + else + test_grep usage output || + test_grep usage err + fi ' done <builtins -- 2.48.1.434.g4084d8f956 ^ permalink raw reply related [flat|nested] 27+ messages in thread
* Re: Git branch outputs usage message on stderr 2025-01-15 22:27 ` Jeff King @ 2025-01-15 23:32 ` Junio C Hamano 2025-01-16 1:21 ` Junio C Hamano 2025-01-16 10:24 ` Jeff King 0 siblings, 2 replies; 27+ messages in thread From: Junio C Hamano @ 2025-01-15 23:32 UTC (permalink / raw) To: Jeff King; +Cc: Kristoffer Haugsbakk, Matěj Cepl, Jonas Konrad, git Jeff King <peff@peff.net> writes: > I don't know if we'd want something like this on top. If somebody is > interested in just doing all the conversions in the near-term, we could > do without the optional flag. Ah, you are much more practical than I am ;-) I was wondering if we want a list of "these commands have already been updated" and behave differently. > Currently t0012 is permissive and allows either behavior. We'd like it > to eventually enforce that help goes to stdout, and teaching it to do so > identifies the commands that need to be changed. But during the > transition period, we don't want to enforce that for most test runs. Yeah, that is why the "git branch -h" thing has been left broken for such a long time. > So let's introduce a flag that will let most test runs use the > permissive behavior, and people interested in converting commands can > run: > > GIT_TEST_HELP_MUST_BE_STDOUT=1 ./t0012-help.sh > > to see the failures. Eventually (when all builtins have been converted) > we'll remove this flag entirely and always check the strict behavior. > > Signed-off-by: Jeff King <peff@peff.net> > --- > t/t0012-help.sh | 11 +++++++++-- > 1 file changed, 9 insertions(+), 2 deletions(-) Nice. It is a tangent, but I wonder how many among the 40 really needed to use usage_with_options() to react to "-h" in the first place. In other words, these manual checks for "-h" are done only because the code _wants_ to react to "-h" before it calls parse_options(), but does everybody who _wants_ to do so really _needs_ to do so? You already have shown that "gir branch" did not have to, and to me, 40 among 100+ felt way too many. > diff --git a/t/t0012-help.sh b/t/t0012-help.sh > index 1d273d91c2..9c7ae9fd36 100755 > --- a/t/t0012-help.sh > +++ b/t/t0012-help.sh > @@ -255,9 +255,16 @@ do > ( > GIT_CEILING_DIRECTORIES=$(pwd) && > export GIT_CEILING_DIRECTORIES && > - test_expect_code 129 git -C sub $builtin -h >output 2>&1 > + test_expect_code 129 git -C sub $builtin -h >output 2>err > ) && > - test_grep usage output > + if test -n "$GIT_TEST_HELP_MUST_BE_STDOUT" > + then > + test_must_be_empty err && This may be a bit stricter than needed (things other than usage may need to be spitted out), but it is sufficent to declare that we will deal with any potential fallout only after it becomes necessary ;-). > + test_grep usage output > + else > + test_grep usage output || > + test_grep usage err > + fi > ' > done <builtins Will queue. Thanks. ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Git branch outputs usage message on stderr 2025-01-15 23:32 ` Junio C Hamano @ 2025-01-16 1:21 ` Junio C Hamano 2025-01-16 10:24 ` Jeff King 1 sibling, 0 replies; 27+ messages in thread From: Junio C Hamano @ 2025-01-16 1:21 UTC (permalink / raw) To: Jeff King; +Cc: Kristoffer Haugsbakk, Matěj Cepl, Jonas Konrad, git Junio C Hamano <gitster@pobox.com> writes: > It is a tangent, but I wonder how many among the 40 really needed to > use usage_with_options() to react to "-h" in the first place. In > other words, these manual checks for "-h" are done only because the > code _wants_ to react to "-h" before it calls parse_options(), but > does everybody who _wants_ to do so really _needs_ to do so? You > already have shown that "gir branch" did not have to, and to me, 40 > among 100+ felt way too many. It turns out that some of the actually cannot be helped, as they do not even use parse-options and calling usage() themselves is the only way to show the usage text for them. I'll send a 6-patch series out shortly. ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Git branch outputs usage message on stderr 2025-01-15 23:32 ` Junio C Hamano 2025-01-16 1:21 ` Junio C Hamano @ 2025-01-16 10:24 ` Jeff King 1 sibling, 0 replies; 27+ messages in thread From: Jeff King @ 2025-01-16 10:24 UTC (permalink / raw) To: Junio C Hamano; +Cc: Kristoffer Haugsbakk, Matěj Cepl, Jonas Konrad, git On Wed, Jan 15, 2025 at 03:32:29PM -0800, Junio C Hamano wrote: > Jeff King <peff@peff.net> writes: > > > I don't know if we'd want something like this on top. If somebody is > > interested in just doing all the conversions in the near-term, we could > > do without the optional flag. > > Ah, you are much more practical than I am ;-) I was wondering if we > want a list of "these commands have already been updated" and behave > differently. Heh, I started writing it that way but then got turned off by how annoying it is to look up in a list of strings in bash. ;) > It is a tangent, but I wonder how many among the 40 really needed to > use usage_with_options() to react to "-h" in the first place. In > other words, these manual checks for "-h" are done only because the > code _wants_ to react to "-h" before it calls parse_options(), but > does everybody who _wants_ to do so really _needs_ to do so? You > already have shown that "gir branch" did not have to, and to me, 40 > among 100+ felt way too many. Yes, I had the same thought. Unfortunately it is a lot of brain-power to examine each one, with relatively little gain. > > - test_grep usage output > > + if test -n "$GIT_TEST_HELP_MUST_BE_STDOUT" > > + then > > + test_must_be_empty err && > > This may be a bit stricter than needed (things other than usage may > need to be spitted out), but it is sufficent to declare that we will > deal with any potential fallout only after it becomes necessary ;-). Yep. I'd hope for the most part that "-h" would spew help and nothing else, but I guess we could get hit with a deprecation notice or something. I agree on crossing that bridge when we come to it. -Peff ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Git branch outputs usage message on stderr 2025-01-15 21:29 ` Jeff King 2025-01-15 21:56 ` Junio C Hamano @ 2025-01-15 22:11 ` Junio C Hamano 2025-01-15 22:28 ` Jeff King 1 sibling, 1 reply; 27+ messages in thread From: Junio C Hamano @ 2025-01-15 22:11 UTC (permalink / raw) To: Jeff King; +Cc: Kristoffer Haugsbakk, Matěj Cepl, Jonas Konrad, git Jeff King <peff@peff.net> writes: > And it uses code 129, even for "-h". I don't see any explicit rationale > for that in the history; I think it goes back to the beginning of > parse-options. It happens via the PARSE_OPT_HELP flag, but curiously we > also trigger that for ambiguous options (which should exit with error). > That might be a bug-in-waiting if we start handling PARSE_OPT_HELP > differently. There is another class of callers that are protected by the same "argc == 2 && !strcmp(argv[1], "-h")" condition, and they call usage.c:usage(), instead of calling usage_with_options(). These calls (but not all calls to usage()) need to be updated to use a similar helper, say, show_usage_and_exit_if_asked(). Sigh... ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Git branch outputs usage message on stderr 2025-01-15 22:11 ` Junio C Hamano @ 2025-01-15 22:28 ` Jeff King 2025-01-15 23:35 ` Junio C Hamano 0 siblings, 1 reply; 27+ messages in thread From: Jeff King @ 2025-01-15 22:28 UTC (permalink / raw) To: Junio C Hamano; +Cc: Kristoffer Haugsbakk, Matěj Cepl, Jonas Konrad, git On Wed, Jan 15, 2025 at 02:11:56PM -0800, Junio C Hamano wrote: > Jeff King <peff@peff.net> writes: > > > And it uses code 129, even for "-h". I don't see any explicit rationale > > for that in the history; I think it goes back to the beginning of > > parse-options. It happens via the PARSE_OPT_HELP flag, but curiously we > > also trigger that for ambiguous options (which should exit with error). > > That might be a bug-in-waiting if we start handling PARSE_OPT_HELP > > differently. > > There is another class of callers that are protected by the same > "argc == 2 && !strcmp(argv[1], "-h")" condition, and they call > usage.c:usage(), instead of calling usage_with_options(). These > calls (but not all calls to usage()) need to be updated to use a > similar helper, say, show_usage_and_exit_if_asked(). Sigh... Oof. And that uses vreportf(), which always writes to stderr. So more refactoring. -Peff ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Git branch outputs usage message on stderr 2025-01-15 22:28 ` Jeff King @ 2025-01-15 23:35 ` Junio C Hamano 0 siblings, 0 replies; 27+ messages in thread From: Junio C Hamano @ 2025-01-15 23:35 UTC (permalink / raw) To: Jeff King; +Cc: Kristoffer Haugsbakk, Matěj Cepl, Jonas Konrad, git Jeff King <peff@peff.net> writes: > On Wed, Jan 15, 2025 at 02:11:56PM -0800, Junio C Hamano wrote: > >> Jeff King <peff@peff.net> writes: >> >> > And it uses code 129, even for "-h". I don't see any explicit rationale >> > for that in the history; I think it goes back to the beginning of >> > parse-options. It happens via the PARSE_OPT_HELP flag, but curiously we >> > also trigger that for ambiguous options (which should exit with error). >> > That might be a bug-in-waiting if we start handling PARSE_OPT_HELP >> > differently. >> >> There is another class of callers that are protected by the same >> "argc == 2 && !strcmp(argv[1], "-h")" condition, and they call >> usage.c:usage(), instead of calling usage_with_options(). These >> calls (but not all calls to usage()) need to be updated to use a >> similar helper, say, show_usage_and_exit_if_asked(). Sigh... > > Oof. And that uses vreportf(), which always writes to stderr. So more > refactoring. Yes, it's ugly ;-) In any case, this is a result of my sweek in builtin/ for usage_with_options(). The remaining if (argc == 2 && !strcmp(argv[1], "-h")) are all protecting usage() call. ---- >8 ---- Subject: [PATCH] builtins: send help text to standard output Using the show_usage_help_and_exit_if_asked() helper we introduced earlier, fix callers of usage_with_options() that want to show the help text when explicitly asked by the end-user. The help text now goes to the standard output stream for them. Signed-off-by: Junio C Hamano <gitster@pobox.com> --- builtin/am.c | 3 +-- builtin/branch.c | 4 ++-- builtin/checkout--worker.c | 6 +++--- builtin/checkout-index.c | 6 +++--- builtin/commit-tree.c | 4 ++-- builtin/commit.c | 8 ++++---- builtin/fsmonitor--daemon.c | 4 ++-- builtin/gc.c | 4 ++-- builtin/ls-files.c | 4 ++-- builtin/merge.c | 4 ++-- builtin/rebase.c | 6 +++--- builtin/update-index.c | 4 ++-- t/t7600-merge.sh | 2 +- 13 files changed, 29 insertions(+), 30 deletions(-) diff --git a/builtin/am.c b/builtin/am.c index 1338b606fe..0801b556c2 100644 --- a/builtin/am.c +++ b/builtin/am.c @@ -2427,8 +2427,7 @@ int cmd_am(int argc, OPT_END() }; - if (argc == 2 && !strcmp(argv[1], "-h")) - usage_with_options(usage, options); + show_usage_help_and_exit_if_asked(argc, argv, usage, options); git_config(git_default_config, NULL); diff --git a/builtin/branch.c b/builtin/branch.c index 6e7b0cfddb..366729a78b 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -784,8 +784,8 @@ int cmd_branch(int argc, filter.kind = FILTER_REFS_BRANCHES; filter.abbrev = -1; - if (argc == 2 && !strcmp(argv[1], "-h")) - usage_with_options(builtin_branch_usage, options); + show_usage_help_and_exit_if_asked(argc, argv, + builtin_branch_usage, options); /* * Try to set sort keys from config. If config does not set any, diff --git a/builtin/checkout--worker.c b/builtin/checkout--worker.c index b81002a1df..7093d1efd5 100644 --- a/builtin/checkout--worker.c +++ b/builtin/checkout--worker.c @@ -128,9 +128,9 @@ int cmd_checkout__worker(int argc, OPT_END() }; - if (argc == 2 && !strcmp(argv[1], "-h")) - usage_with_options(checkout_worker_usage, - checkout_worker_options); + show_usage_help_and_exit_if_asked(argc, argv, + checkout_worker_usage, + checkout_worker_options); git_config(git_default_config, NULL); argc = parse_options(argc, argv, prefix, checkout_worker_options, diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c index a81501098d..d928d6b5e3 100644 --- a/builtin/checkout-index.c +++ b/builtin/checkout-index.c @@ -250,9 +250,9 @@ int cmd_checkout_index(int argc, OPT_END() }; - if (argc == 2 && !strcmp(argv[1], "-h")) - usage_with_options(builtin_checkout_index_usage, - builtin_checkout_index_options); + show_usage_help_and_exit_if_asked(argc, argv, + builtin_checkout_index_usage, + builtin_checkout_index_options); git_config(git_default_config, NULL); prefix_length = prefix ? strlen(prefix) : 0; diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c index 2ca1a57ebb..2efc224d32 100644 --- a/builtin/commit-tree.c +++ b/builtin/commit-tree.c @@ -119,8 +119,8 @@ int cmd_commit_tree(int argc, git_config(git_default_config, NULL); - if (argc < 2 || !strcmp(argv[1], "-h")) - usage_with_options(commit_tree_usage, options); + show_usage_help_and_exit_if_asked(argc, argv, + commit_tree_usage, options); argc = parse_options(argc, argv, prefix, options, commit_tree_usage, 0); diff --git a/builtin/commit.c b/builtin/commit.c index ef5e622c07..4268915120 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -1559,8 +1559,8 @@ struct repository *repo UNUSED) OPT_END(), }; - if (argc == 2 && !strcmp(argv[1], "-h")) - usage_with_options(builtin_status_usage, builtin_status_options); + show_usage_help_and_exit_if_asked(argc, argv, + builtin_status_usage, builtin_status_options); prepare_repo_settings(the_repository); the_repository->settings.command_requires_full_index = 0; @@ -1736,8 +1736,8 @@ int cmd_commit(int argc, struct strbuf err = STRBUF_INIT; int ret = 0; - if (argc == 2 && !strcmp(argv[1], "-h")) - usage_with_options(builtin_commit_usage, builtin_commit_options); + show_usage_help_and_exit_if_asked(argc, argv, + builtin_commit_usage, builtin_commit_options); prepare_repo_settings(the_repository); the_repository->settings.command_requires_full_index = 0; diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c index 029dc64d6c..dabf190bbe 100644 --- a/builtin/fsmonitor--daemon.c +++ b/builtin/fsmonitor--daemon.c @@ -1598,8 +1598,8 @@ int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix UNUSED OPT_END() }; - if (argc == 2 && !strcmp(argv[1], "-h")) - usage_with_options(builtin_fsmonitor__daemon_usage, options); + show_usage_help_and_exit_if_asked(argc, argv, + builtin_fsmonitor__daemon_usage, options); die(_("fsmonitor--daemon not supported on this platform")); } diff --git a/builtin/gc.c b/builtin/gc.c index a9b1c36de2..5f831e1f94 100644 --- a/builtin/gc.c +++ b/builtin/gc.c @@ -710,8 +710,8 @@ struct repository *repo UNUSED) OPT_END() }; - if (argc == 2 && !strcmp(argv[1], "-h")) - usage_with_options(builtin_gc_usage, builtin_gc_options); + show_usage_help_and_exit_if_asked(argc, argv, + builtin_gc_usage, builtin_gc_options); strvec_pushl(&reflog, "reflog", "expire", "--all", NULL); strvec_pushl(&repack, "repack", "-d", "-l", NULL); diff --git a/builtin/ls-files.c b/builtin/ls-files.c index 15499cd12b..9efe92b7c0 100644 --- a/builtin/ls-files.c +++ b/builtin/ls-files.c @@ -644,8 +644,8 @@ int cmd_ls_files(int argc, }; int ret = 0; - if (argc == 2 && !strcmp(argv[1], "-h")) - usage_with_options(ls_files_usage, builtin_ls_files_options); + show_usage_help_and_exit_if_asked(argc, argv, + ls_files_usage, builtin_ls_files_options); prepare_repo_settings(the_repository); the_repository->settings.command_requires_full_index = 0; diff --git a/builtin/merge.c b/builtin/merge.c index 5f67007bba..95d798fc89 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -1300,8 +1300,8 @@ int cmd_merge(int argc, void *branch_to_free; int orig_argc = argc; - if (argc == 2 && !strcmp(argv[1], "-h")) - usage_with_options(builtin_merge_usage, builtin_merge_options); + show_usage_help_and_exit_if_asked(argc, argv, + builtin_merge_usage, builtin_merge_options); prepare_repo_settings(the_repository); the_repository->settings.command_requires_full_index = 0; diff --git a/builtin/rebase.c b/builtin/rebase.c index 0498fff3c9..cb49323c44 100644 --- a/builtin/rebase.c +++ b/builtin/rebase.c @@ -1223,9 +1223,9 @@ int cmd_rebase(int argc, }; int i; - if (argc == 2 && !strcmp(argv[1], "-h")) - usage_with_options(builtin_rebase_usage, - builtin_rebase_options); + show_usage_help_and_exit_if_asked(argc, argv, + builtin_rebase_usage, + builtin_rebase_options); prepare_repo_settings(the_repository); the_repository->settings.command_requires_full_index = 0; diff --git a/builtin/update-index.c b/builtin/update-index.c index 74bbad9f87..b0e2ad4970 100644 --- a/builtin/update-index.c +++ b/builtin/update-index.c @@ -1045,8 +1045,8 @@ int cmd_update_index(int argc, OPT_END() }; - if (argc == 2 && !strcmp(argv[1], "-h")) - usage_with_options(update_index_usage, options); + show_usage_help_and_exit_if_asked(argc, argv, + update_index_usage, options); git_config(git_default_config, NULL); diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh index ef54cff4fa..2a8df29219 100755 --- a/t/t7600-merge.sh +++ b/t/t7600-merge.sh @@ -173,7 +173,7 @@ test_expect_success 'merge -h with invalid index' ' cd broken && git init && >.git/index && - test_expect_code 129 git merge -h 2>usage + test_expect_code 129 git merge -h >usage ) && test_grep "[Uu]sage: git merge" broken/usage ' -- 2.48.1-187-gd93ffc6ef3 ^ permalink raw reply related [flat|nested] 27+ messages in thread
* Re: Git branch outputs usage message on stderr 2025-01-15 17:56 ` Junio C Hamano 2025-01-15 18:24 ` Jeff King @ 2025-01-15 18:29 ` Junio C Hamano 2025-01-15 18:33 ` Kristoffer Haugsbakk 1 sibling, 1 reply; 27+ messages in thread From: Junio C Hamano @ 2025-01-15 18:29 UTC (permalink / raw) To: Jeff King; +Cc: Kristoffer Haugsbakk, Matěj Cepl, Jonas Konrad, git Junio C Hamano <gitster@pobox.com> writes: > Jeff King <peff@peff.net> writes: > >> use that everywhere. Possibly it could even do the argc/argv check, too, >> since every call site is going to be doing that itself. > > It would look something like this; I am not sure if I like the "this > may show help and exit if the user requested, but otherwise it is a > no-op" semantics, though. After thinking about it a bit more, I am starting to like it, not because it reduces a few more lines from the calling site, but because it makes it almost impossible to use for a careless and incorrect conversion from usage_with_options(). Any existing callsite of usage_with_options() MUST be inspected to make sure it is responding to an end-user request to give "-h"(elp) text before being replaced with the call to a new helper, and if I made show_usage_help() without argc/argv, a careless developer can easily and blindly do string replacement to send a ton of patch that reviewers need to waste time to do the inspection for them. But with your "argc and argv checking included" approach, it is harder to do the blind replacement. --- >8 --- From: Junio C Hamano <gitster@pobox.com> Date: Wed, 15 Jan 2025 09:56:23 -0800 Subject: [PATCH] parse-options: add show_usage_help() Many commands call usage_with_options() when they are asked to give the help message, but it incorrectly sends the help text to the standard error stream. When the user asked for it with "git cmd -h", the help message is the primary output from the command, hence we should send it to the standard output stream. Introduce a helper function that captures the common pattern if (argc == 2 && !strcmp(argv[1], "-h")) usage_with_options(usage, options); and replaces it with show_usage_help(argc, argv, usage, options); to help correct code paths (there are 40 or so of them). Suggested-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- parse-options.c | 10 ++++++++++ parse-options.h | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/parse-options.c b/parse-options.c index 33bfba0ed4..4b00065692 100644 --- a/parse-options.c +++ b/parse-options.c @@ -1282,6 +1282,16 @@ void NORETURN usage_with_options(const char * const *usagestr, exit(129); } +void show_usage_help(int ac, const char **av, + const char * const *usagestr, + const struct option *opts) +{ + if (ac == 2 && !strcmp(av[1], "-h")) { + usage_with_options_internal(NULL, usagestr, opts, 0, 0); + exit(0); + } +} + void NORETURN usage_msg_opt(const char *msg, const char * const *usagestr, const struct option *options) diff --git a/parse-options.h b/parse-options.h index d01361ca97..f93f13434c 100644 --- a/parse-options.h +++ b/parse-options.h @@ -402,6 +402,10 @@ int parse_options(int argc, const char **argv, const char *prefix, NORETURN void usage_with_options(const char * const *usagestr, const struct option *options); +void show_usage_help(int, const char **, + const char * const *usagestr, + const struct option *options); + NORETURN void usage_msg_opt(const char *msg, const char * const *usagestr, const struct option *options); -- 2.48.1-187-gd93ffc6ef3 ^ permalink raw reply related [flat|nested] 27+ messages in thread
* Re: Git branch outputs usage message on stderr 2025-01-15 18:29 ` Junio C Hamano @ 2025-01-15 18:33 ` Kristoffer Haugsbakk 2025-01-15 21:13 ` Junio C Hamano 0 siblings, 1 reply; 27+ messages in thread From: Kristoffer Haugsbakk @ 2025-01-15 18:33 UTC (permalink / raw) To: Junio C Hamano, Jeff King; +Cc: Matěj Cepl, Jonas Konrad, git On Wed, Jan 15, 2025, at 19:29, Junio C Hamano wrote: > From: Junio C Hamano <gitster@pobox.com> > Date: Wed, 15 Jan 2025 09:56:23 -0800 > Subject: [PATCH] parse-options: add show_usage_help() > > Many commands call usage_with_options() when they are asked to give > the help message, but it incorrectly sends the help text to the > standard error stream. When the user asked for it with "git cmd -h", > the help message is the primary output from the command, hence we > should send it to the standard output stream. > > Introduce a helper function that captures the common pattern > > if (argc == 2 && !strcmp(argv[1], "-h")) > usage_with_options(usage, options); > > and replaces it with > > show_usage_help(argc, argv, usage, options); > > to help correct code paths (there are 40 or so of them). > > Suggested-by: Jeff King <peff@peff.net> +Reported-by: Jonas Konrad <jonas.konrad@uni-muenster.de> > Signed-off-by: Junio C Hamano <gitster@pobox.com> -- Kristoffer Haugsbakk ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Git branch outputs usage message on stderr 2025-01-15 18:33 ` Kristoffer Haugsbakk @ 2025-01-15 21:13 ` Junio C Hamano 0 siblings, 0 replies; 27+ messages in thread From: Junio C Hamano @ 2025-01-15 21:13 UTC (permalink / raw) To: Kristoffer Haugsbakk; +Cc: Jeff King, Matěj Cepl, Jonas Konrad, git "Kristoffer Haugsbakk" <kristofferhaugsbakk@fastmail.com> writes: >> and replaces it with >> >> show_usage_help(argc, argv, usage, options); >> >> to help correct code paths (there are 40 or so of them). >> >> Suggested-by: Jeff King <peff@peff.net> > > +Reported-by: Jonas Konrad <jonas.konrad@uni-muenster.de> Not on this patch, but it would be a good addition to a follow-up patch that uses this new API function to update builtin/branch.c (which I do not plan to do myself). Thanks. ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Git branch outputs usage message on stderr 2025-01-15 16:55 ` Kristoffer Haugsbakk 2025-01-15 17:14 ` Jeff King @ 2025-01-15 17:14 ` Jonas Konrad 2025-01-15 17:53 ` Kristoffer Haugsbakk 2025-01-15 17:19 ` Junio C Hamano 2 siblings, 1 reply; 27+ messages in thread From: Jonas Konrad @ 2025-01-15 17:14 UTC (permalink / raw) To: Kristoffer Haugsbakk, Junio C Hamano, Matěj Cepl; +Cc: git [-- Attachment #1: Type: text/plain, Size: 1193 bytes --] On 15.01.25 17:55, Kristoffer Haugsbakk wrote: > On Wed, Jan 15, 2025, at 16:28, Junio C Hamano wrote: >> Somebody may want to go over "git help --all" and for each of them >> try "git $cmd -h >/dev/null" to find those that give the help output >> to their standard error stream. > #!/bin/sh > > for cmd in $(git --list-cmds=builtins); do > git $cmd -h >/dev/null > done 2>&1 | grep '^usage: ' \ > | perl -pe 's/^usage:\s*(\(EXPERIMENTAL!\)\s*)?//; s/^(git\s+[a-zA-Z0-9-]+).*/\1/' > > Gives > > git am > [...] > For > > $ git version > git version 2.48.0 Was just about to share the very same results, leading to 40 commands out of 142 built-ins outputting their usage info to stderr. Some additions on non-builtins: git-scalar also outputs its usage info to stderr. git-lfs does not have "usage text for -h". I have not tested git-svn and git-cvsserver properly (do not have installed the respective modules). On another note, git-p4 does not know "-h", but then gives usage info - to stdout(!)). Lastly, if you still read, test git-http-backend and git-filter-branch, as they show special behavior. [-- Attachment #2: S/MIME Cryptographic Signature --] [-- Type: application/pkcs7-signature, Size: 6990 bytes --] ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Git branch outputs usage message on stderr 2025-01-15 17:14 ` Jonas Konrad @ 2025-01-15 17:53 ` Kristoffer Haugsbakk 0 siblings, 0 replies; 27+ messages in thread From: Kristoffer Haugsbakk @ 2025-01-15 17:53 UTC (permalink / raw) To: Jonas Konrad, Junio C Hamano, Matěj Cepl; +Cc: git On Wed, Jan 15, 2025, at 18:14, Jonas Konrad wrote: > On 15.01.25 17:55, Kristoffer Haugsbakk wrote: >> [snip] > > Was just about to share the very same results, leading to 40 commands > out of 142 built-ins outputting their usage info to stderr. Some > additions on non-builtins: git-scalar also outputs its usage info to > stderr. git-lfs does not have "usage text for -h". I have not tested > git-svn and git-cvsserver properly (do not have installed the respective > modules). On another note, git-p4 does not know "-h", but then gives > usage info - to stdout(!)). Lastly, if you still read, test > git-http-backend and git-filter-branch, as they show special behavior. Okay, `git-http-backend` is listed in `git --list-cmds=main`. That one doesn’t support `-h`. $ git http-backend -h >/dev/null fatal: No REQUEST_METHOD from server and $ git http-backend -h 2>/dev/null Status: 500 Internal Server Error Expires: Fri, 01 Jan 1980 00:00:00 GMT Pragma: no-cache Cache-Control: no-cache, max-age=0, must-revalidate git-filter-branch(1) prints a warning about “glut of gotchas”, waits 10 seconds, then prints usage to stdout. $ time git filter-branch -h >/dev/null real 0m10,058s user 0m0,023s sys 0m0,041s -- Kristoffer Haugsbakk ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Git branch outputs usage message on stderr 2025-01-15 16:55 ` Kristoffer Haugsbakk 2025-01-15 17:14 ` Jeff King 2025-01-15 17:14 ` Jonas Konrad @ 2025-01-15 17:19 ` Junio C Hamano 2025-01-15 17:39 ` Kristoffer Haugsbakk 2 siblings, 1 reply; 27+ messages in thread From: Junio C Hamano @ 2025-01-15 17:19 UTC (permalink / raw) To: Kristoffer Haugsbakk; +Cc: Matěj Cepl, Jonas Konrad, git "Kristoffer Haugsbakk" <kristofferhaugsbakk@fastmail.com> writes: > On Wed, Jan 15, 2025, at 16:28, Junio C Hamano wrote: >> Somebody may want to go over "git help --all" and for each of them >> try "git $cmd -h >/dev/null" to find those that give the help output >> to their standard error stream. > > #!/bin/sh > > for cmd in $(git --list-cmds=builtins); do > git $cmd -h >/dev/null > done 2>&1 | grep '^usage: ' \ > | perl -pe 's/^usage:\s*(\(EXPERIMENTAL!\)\s*)?//; s/^(git\s+[a-zA-Z0-9-]+).*/\1/' > > Gives ... Being consistent is a good idea, and I wanted to first gauge which way we should unify. It seems that those who spit their help text into their standard error stream are indeed in minority? Thanks. ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Git branch outputs usage message on stderr 2025-01-15 17:19 ` Junio C Hamano @ 2025-01-15 17:39 ` Kristoffer Haugsbakk 2025-01-15 17:47 ` Junio C Hamano 0 siblings, 1 reply; 27+ messages in thread From: Kristoffer Haugsbakk @ 2025-01-15 17:39 UTC (permalink / raw) To: Junio C Hamano; +Cc: Matěj Cepl, Jonas Konrad, git, Jeff King On Wed, Jan 15, 2025, at 18:19, Junio C Hamano wrote: > "Kristoffer Haugsbakk" <kristofferhaugsbakk@fastmail.com> writes: >> [snip] > > Being consistent is a good idea, and I wanted to first gauge which > way we should unify. It seems that those who spit their help text > into their standard error stream are indeed in minority? Yes: 40 of those stderr `-h` outputs. Versus 102 that use stdout.[1] Trying a random command with usage-on-error: $ git-upload-pack >/dev/null usage: [snip] Does give usage on stderr. † 1: git add git annotate git apply git archive git bisect git blame git bugreport git bundle git cat-file git check-attr git check-ignore git check-mailmap git checkout git cherry git cherry-pick git clean git clone git column git commit-graph git config git count-objects git credential-cache git credential-cache--daemon git credential-store git describe git diagnose git difftool git fast-export git fetch git fmt-merge-msg git for-each-ref git for-each-repo git format-patch git fsck git fsck git grep git hash-object git help git hook git init git init git interpret-trailers git log git ls-remote git ls-tree git mailinfo git maintenance git merge-base git merge-file git merge-tree git mktag git mktree git multi-pack-index git mv git name-rev git notes git pack-objects git pack-refs git patch-id git blame git prune git prune-packed git pull git push git range-diff git read-tree git receive-pack git reflog git refs git remote git repack git replace git replay git rerere git reset git restore git revert git rm git send-pack git shortlog git log git show-branch git show-index git show-ref git sparse-checkout git add git stash git stripspace git submodule--helper git switch git symbolic-ref git tag git update-ref git update-server-info git-upload-pack git verify-commit git verify-pack git verify-tag git version git log git worktree git write-tree ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Git branch outputs usage message on stderr 2025-01-15 17:39 ` Kristoffer Haugsbakk @ 2025-01-15 17:47 ` Junio C Hamano 0 siblings, 0 replies; 27+ messages in thread From: Junio C Hamano @ 2025-01-15 17:47 UTC (permalink / raw) To: Kristoffer Haugsbakk; +Cc: Matěj Cepl, Jonas Konrad, git, Jeff King "Kristoffer Haugsbakk" <kristofferhaugsbakk@fastmail.com> writes: > Trying a random command with usage-on-error: > > $ git-upload-pack >/dev/null > usage: [snip] > > Does give usage on stderr. Good; that is what we want to see. Thanks. ^ permalink raw reply [flat|nested] 27+ messages in thread
end of thread, other threads:[~2025-01-16 10:24 UTC | newest] Thread overview: 27+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2025-01-15 11:21 Git branch outputs usage message on stderr Jonas Konrad 2025-01-15 11:36 ` Matěj Cepl 2025-01-15 14:47 ` Jonas Konrad 2025-01-15 15:28 ` Junio C Hamano 2025-01-15 16:55 ` Kristoffer Haugsbakk 2025-01-15 17:14 ` Jeff King 2025-01-15 17:49 ` Junio C Hamano 2025-01-15 17:56 ` Junio C Hamano 2025-01-15 18:24 ` Jeff King 2025-01-15 21:16 ` Junio C Hamano 2025-01-15 21:29 ` Jeff King 2025-01-15 21:56 ` Junio C Hamano 2025-01-15 22:27 ` Jeff King 2025-01-15 23:32 ` Junio C Hamano 2025-01-16 1:21 ` Junio C Hamano 2025-01-16 10:24 ` Jeff King 2025-01-15 22:11 ` Junio C Hamano 2025-01-15 22:28 ` Jeff King 2025-01-15 23:35 ` Junio C Hamano 2025-01-15 18:29 ` Junio C Hamano 2025-01-15 18:33 ` Kristoffer Haugsbakk 2025-01-15 21:13 ` Junio C Hamano 2025-01-15 17:14 ` Jonas Konrad 2025-01-15 17:53 ` Kristoffer Haugsbakk 2025-01-15 17:19 ` Junio C Hamano 2025-01-15 17:39 ` Kristoffer Haugsbakk 2025-01-15 17:47 ` Junio C Hamano
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 NNTP newsgroup(s).