* 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 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 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
* 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 ` 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 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 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 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: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 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: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: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 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 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
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).