threads / discuss / 63846

-h prints alias information even for grep

Subject: -h prints alias information even for grep

## tl;dr

9 messages between Jul 25, 2025 and Jul 29, 2025.

replies: 8people: 5as markdown or json

Kevin Brodsky· Jul 25, 2025, 08:17 UTC · lore
Hi,
I've noticed a strange interaction that probably wasn't intended.

The -h flag typically means "help", and if passed to an aliased command an extra line is printed to describe the alias. This also holds for the grep command, if no other argument is passed.

Things get weirder if grep is passed valid arguments, because in that case -h means something else (suppressing filename output). Of course no help message is printed in that case, but the alias information is still printed!

Example:
$ git g -h -A20 alias .gitconfig
'g' is aliased to 'grep'
[alias]
[...]
    g    = grep
----

It seems like that alias information line should be tied to the printing of the help message, rather than the -h flag?

I noticed this behaviour years ago and I still do with the latest version of Git (2.50.1).

Cheers, Kevin

René Scharfe· Jul 25, 2025, 18:41 UTC · re: Kevin Brodsky · lore

[PATCH] git: show alias info only with lone -h

Builtin commands show usage information on stdout if called with -h as their only option, usage.c::show_usage_if_asked() makes sure of that.

Aliases show alias information on stderr if called with -h as the first option since a9a60b94cc (git.c: handle_alias: prepend alias info when first argument is -h, 2018-10-09). This is surprising when using aliases for commands that take -h as a normal argument among others, like git grep.

Tighten the condition and show the alias information only if -h is the only option given, to be consistent with builtins.

It's probably still is a good idea to write to stderr, as an alias command doesn't have to be a builtin and could instead produce output with just -h that might be spoiled by an extra alias info line.

Reported-by: Kevin Brodsky <kevin.brodsky@arm.com>
Signed-off-by: René Scharfe <l.s.r@web.de>
---
 git.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/git.c b/git.c
index 07a5fe39fb..83eac0aeab 100644
--- a/git.c
+++ b/git.c
@@ -371,7 +371,7 @@ static int handle_alias(struct strvec *args)
 	alias_command = args->v[0];
 	alias_string = alias_lookup(alias_command);
 	if (alias_string) {
-		if (args->nr > 1 && !strcmp(args->v[1], "-h"))
+		if (args->nr == 2 && !strcmp(args->v[1], "-h"))
 			fprintf_ln(stderr, _("'%s' is aliased to '%s'"),
 				   alias_command, alias_string);
 		if (alias_string[0] == '!') {
-- 
2.50.1
Junio C Hamano· Jul 25, 2025, 23:52 UTC · re: René Scharfe · lore

Re: [PATCH] git: show alias info only with lone -h

René Scharfe <l.s.r@web.de> writes:
Show 11 quoted lines
> Builtin commands show usage information on stdout if called with -h as
> their only option, usage.c::show_usage_if_asked() makes sure of that.
>
> Aliases show alias information on stderr if called with -h as the first
> option since a9a60b94cc (git.c: handle_alias: prepend alias info when
> first argument is -h, 2018-10-09).  This is surprising when using
> aliases for commands that take -h as a normal argument among others,
> like git grep.
>
> Tighten the condition and show the alias information only if -h is the
> only option given, to be consistent with builtins.

Hmph. This certainly is an obvious improvement, especially when the alias does not redirect to our commands, e.g. "git g" is an alias to the system supplied (likely to be GNU) grep:

   $ git -c alias.g='!grep' g -h frotz *.c

which gives us hits in our sources as expected. But without arguments, we get the obvious plus something we may not want to see:

   $ git -c alias.g='!grep' g -h
   'g' is aliased to '!grep'
   Usage: grep [OPTION]... PATTERNS [FILE]...
   Try 'grep --help' for more information.

I wonder if we should not run the underlying/aliased command after showing the alias expansion? With "grep" we got lucky that a sole "-h" means the same thing as it means to us (i.e. short help), but if it is not one of our commands that would not generally hold. It is risky to blindly run the external command with a single "-h" as an argument.

When it redirects to our commands, it is less risky as we aim to make all our commands honor a single "-h" via t0450.

   $ git -c alias.c=checkout c -h
   'c' is aliased to 'checkout'
   usage: git checkout [<options>] <branch>
      or: git checkout [<options>] [<branch>] -- <file>...
       -b <branch>           create and checkout a new branch
       -B <branch>           create/reset and checkout a branch
   ...
       --pathspec-from-file <file>
                             read pathspec from file
       --pathspec-file-nul   with --pathspec-from-file, pathspec elements are separated with NUL character

But then, it may not be such a good idea to pay attention to "do we have extra '-h'?" when alias expands to our commands, e.g.

   $ git -c alias.c=checkout c -h main
   usage: git checkout [<options>] <branch>
      or: git checkout [<options>] [<branch>] -- <file>...
       -b <branch>           create and checkout a new branch
       -B <branch>           create/reset and checkout a branch
   ...
       --pathspec-from-file <file>
                             read pathspec from file
       --pathspec-file-nul   with --pathspec-from-file, pathspec elements are separated with NUL character

We get the same short-help, without what alias expansion caused this mess, and without any indication that we lost 'main' on the command line.

So, I dunno.
Jeff King· Jul 26, 2025, 08:12 UTC · re: Junio C Hamano · lore

Re: [PATCH] git: show alias info only with lone -h

On Fri, Jul 25, 2025 at 04:52:40PM -0700, Junio C Hamano wrote:
Show 17 quoted lines
> When it redirects to our commands, it is less risky as we aim to
> make all our commands honor a single "-h" via t0450.
> 
>    $ git -c alias.c=checkout c -h
>    'c' is aliased to 'checkout'
>    usage: git checkout [<options>] <branch>
>       or: git checkout [<options>] [<branch>] -- <file>...
> 
>        -b <branch>           create and checkout a new branch
>        -B <branch>           create/reset and checkout a branch
>    ...
>        --pathspec-from-file <file>
>                              read pathspec from file
>        --pathspec-file-nul   with --pathspec-from-file, pathspec elements are separated with NUL character
> 
> But then, it may not be such a good idea to pay attention to "do we
> have extra '-h'?" when alias expands to our commands, e.g.

Another interesting case: even for our own commands, the alias itself may add extra arguments, which confuses things further. So:

  $ git -c alias.gi='grep --cached' gi -h
  'gi' is aliased to 'grep --cached'
  fatal: no pattern given

runs git-grep, but even though the user said only "-h" the alias added another option which prevents the help-mode from activating.

In this case it is not too harmful, but you can come up with pathological cases where it actually runs a real command:

  git -c alias.grep-for-foo='grep -e foo' grep-for-foo -h
which runs a real grep.

I guess one way to deal with it would be if the user runs "foo -h", and alias.foo is "bar --other arguments", then we run just "bar -h", dropping the extra arguments provided by the alias.

(Another fun corner case: not all git-foo are our commands. But maybe it is enough to say "if you make a third-party git-foo it should probably respect bare -h as an option").

Show 14 quoted lines
>    $ git -c alias.c=checkout c -h main
>    usage: git checkout [<options>] <branch>
>       or: git checkout [<options>] [<branch>] -- <file>...
> 
>        -b <branch>           create and checkout a new branch
>        -B <branch>           create/reset and checkout a branch
>    ...
>        --pathspec-from-file <file>
>                              read pathspec from file
>        --pathspec-file-nul   with --pathspec-from-file, pathspec elements are separated with NUL character
> 
> We get the same short-help, without what alias expansion caused this
> mess, and without any indication that we lost 'main' on the command
> line.

Yeah, that is the flip side of René's patch. Right now we overly guess that "-h" means help. And after the patch, we'd sometimes under-guess that it meant help, even for commands which treat it as such. I think that may be the lesser of two evils, though; if you are asking for help then "git c -h" is the most-strict way to do it.

So IMHO the patch under discussion is a strict improvement, even though it leaves many other questionable cases unsolved. I'd also be happy if on top we did:

  1. When alias.foo="bar --options", turn "git foo -h" into "git bar
     -h", dropping "--options".
  2. When alias.foo="!bar", report only the alias and do not run "bar"
     at all. The collateral damage here would be:
        !git bar $(some_shell_magic_we_need)
     but IMHO that is not all that bad. If we report the alias content,
     the user can probably figure out which "git help" to run next.
-Peff
D. Ben Knoble· Jul 26, 2025, 13:12 UTC · re: Jeff King · lore

Re: [PATCH] git: show alias info only with lone -h

I have a few (unsent) patches I've been working on that touch the help mechanism, so I have some thoughts below.

On Sat, Jul 26, 2025 at 4:13 AM Jeff King <peff@peff.net> wrote:
Show 41 quoted lines
>
> On Fri, Jul 25, 2025 at 04:52:40PM -0700, Junio C Hamano wrote:
>
> > When it redirects to our commands, it is less risky as we aim to
> > make all our commands honor a single "-h" via t0450.
> >
> >    $ git -c alias.c=checkout c -h
> >    'c' is aliased to 'checkout'
> >    usage: git checkout [<options>] <branch>
> >       or: git checkout [<options>] [<branch>] -- <file>...
> >
> >        -b <branch>           create and checkout a new branch
> >        -B <branch>           create/reset and checkout a branch
> >    ...
> >        --pathspec-from-file <file>
> >                              read pathspec from file
> >        --pathspec-file-nul   with --pathspec-from-file, pathspec elements are separated with NUL character
> >
> > But then, it may not be such a good idea to pay attention to "do we
> > have extra '-h'?" when alias expands to our commands, e.g.
>
> Another interesting case: even for our own commands, the alias itself
> may add extra arguments, which confuses things further. So:
>
>   $ git -c alias.gi='grep --cached' gi -h
>   'gi' is aliased to 'grep --cached'
>   fatal: no pattern given
>
> runs git-grep, but even though the user said only "-h" the alias added
> another option which prevents the help-mode from activating.
>
> In this case it is not too harmful, but you can come up with
> pathological cases where it actually runs a real command:
>
>   git -c alias.grep-for-foo='grep -e foo' grep-for-foo -h
>
> which runs a real grep.
>
> I guess one way to deal with it would be if the user runs "foo -h", and
> alias.foo is "bar --other arguments", then we run just "bar -h",
> dropping the extra arguments provided by the alias.

This is intriguing: it would mean that an alias is not purely a textual replacement? That's true for ! aliases today, but other than shelling out it's pretty close.

Show 40 quoted lines
>
> (Another fun corner case: not all git-foo are our commands. But maybe it
> is enough to say "if you make a third-party git-foo it should probably
> respect bare -h as an option").
>
> >    $ git -c alias.c=checkout c -h main
> >    usage: git checkout [<options>] <branch>
> >       or: git checkout [<options>] [<branch>] -- <file>...
> >
> >        -b <branch>           create and checkout a new branch
> >        -B <branch>           create/reset and checkout a branch
> >    ...
> >        --pathspec-from-file <file>
> >                              read pathspec from file
> >        --pathspec-file-nul   with --pathspec-from-file, pathspec elements are separated with NUL character
> >
> > We get the same short-help, without what alias expansion caused this
> > mess, and without any indication that we lost 'main' on the command
> > line.
>
> Yeah, that is the flip side of René's patch. Right now we overly guess
> that "-h" means help. And after the patch, we'd sometimes under-guess
> that it meant help, even for commands which treat it as such. I think
> that may be the lesser of two evils, though; if you are asking for help
> then "git c -h" is the most-strict way to do it.
>
> So IMHO the patch under discussion is a strict improvement, even though
> it leaves many other questionable cases unsolved. I'd also be happy if
> on top we did:
>
>   1. When alias.foo="bar --options", turn "git foo -h" into "git bar
>      -h", dropping "--options".
>
>   2. When alias.foo="!bar", report only the alias and do not run "bar"
>      at all. The collateral damage here would be:
>
>         !git bar $(some_shell_magic_we_need)
>
>      but IMHO that is not all that bad. If we report the alias content,
>      the user can probably figure out which "git help" to run next.

And if the user actually wanted to run `bar -h`, say, because `-h` didn't mean help for that command? I can't come up with a compelling example, but this goes back to "textual substitution" vs. "trying to decide what the user actually wants."

At any rate, a (3) to consider is "--help-all": the patches I've been working on are to make that flag work more often outside of Git repositories. I just need to clean things up a bit and get to tests. But if we do treat "git alias -h" specially, perhaps "--help-all" then also warrants treatment.

>
> -Peff
>
-- 
D. Ben Knoble
D. Ben Knoble· Jul 26, 2025, 14:22 UTC · re: D. Ben Knoble · lore

Re: [PATCH] git: show alias info only with lone -h

On Sat, Jul 26, 2025 at 9:12 AM D. Ben Knoble <ben.knoble@gmail.com> wrote:
Show 50 quoted lines
>
> I have a few (unsent) patches I've been working on that touch the help
> mechanism, so I have some thoughts below.
>
> On Sat, Jul 26, 2025 at 4:13 AM Jeff King <peff@peff.net> wrote:
> >
> > On Fri, Jul 25, 2025 at 04:52:40PM -0700, Junio C Hamano wrote:
> >
> > > When it redirects to our commands, it is less risky as we aim to
> > > make all our commands honor a single "-h" via t0450.
> > >
> > >    $ git -c alias.c=checkout c -h
> > >    'c' is aliased to 'checkout'
> > >    usage: git checkout [<options>] <branch>
> > >       or: git checkout [<options>] [<branch>] -- <file>...
> > >
> > >        -b <branch>           create and checkout a new branch
> > >        -B <branch>           create/reset and checkout a branch
> > >    ...
> > >        --pathspec-from-file <file>
> > >                              read pathspec from file
> > >        --pathspec-file-nul   with --pathspec-from-file, pathspec elements are separated with NUL character
> > >
> > > But then, it may not be such a good idea to pay attention to "do we
> > > have extra '-h'?" when alias expands to our commands, e.g.
> >
> > Another interesting case: even for our own commands, the alias itself
> > may add extra arguments, which confuses things further. So:
> >
> >   $ git -c alias.gi='grep --cached' gi -h
> >   'gi' is aliased to 'grep --cached'
> >   fatal: no pattern given
> >
> > runs git-grep, but even though the user said only "-h" the alias added
> > another option which prevents the help-mode from activating.
> >
> > In this case it is not too harmful, but you can come up with
> > pathological cases where it actually runs a real command:
> >
> >   git -c alias.grep-for-foo='grep -e foo' grep-for-foo -h
> >
> > which runs a real grep.
> >
> > I guess one way to deal with it would be if the user runs "foo -h", and
> > alias.foo is "bar --other arguments", then we run just "bar -h",
> > dropping the extra arguments provided by the alias.
>
> This is intriguing: it would mean that an alias is not purely a
> textual replacement? That's true for ! aliases today, but other than
> shelling out it's pretty close.

One other thing I've just remembered: "git help alias" shows the alias information without running it. So I don't know if special-casing "-h" adds much?

-- 
D. Ben Knoble
Jeff King· Jul 29, 2025, 07:23 UTC · re: D. Ben Knoble · lore

Re: [PATCH] git: show alias info only with lone -h

On Sat, Jul 26, 2025 at 09:12:55AM -0400, D. Ben Knoble wrote:
Show 14 quoted lines
> > In this case it is not too harmful, but you can come up with
> > pathological cases where it actually runs a real command:
> >
> >   git -c alias.grep-for-foo='grep -e foo' grep-for-foo -h
> >
> > which runs a real grep.
> >
> > I guess one way to deal with it would be if the user runs "foo -h", and
> > alias.foo is "bar --other arguments", then we run just "bar -h",
> > dropping the extra arguments provided by the alias.
> 
> This is intriguing: it would mean that an alias is not purely a
> textual replacement? That's true for ! aliases today, but other than
> shelling out it's pretty close.

Sort of. It's still a textual replacement for running the command. It's just that "git foo -h" is magic that puts us into help mode, and we try to communicate that help mode to the underlying command.

So I guess it depends on your point of view. :)
Show 19 quoted lines
> > So IMHO the patch under discussion is a strict improvement, even though
> > it leaves many other questionable cases unsolved. I'd also be happy if
> > on top we did:
> >
> >   1. When alias.foo="bar --options", turn "git foo -h" into "git bar
> >      -h", dropping "--options".
> >
> >   2. When alias.foo="!bar", report only the alias and do not run "bar"
> >      at all. The collateral damage here would be:
> >
> >         !git bar $(some_shell_magic_we_need)
> >
> >      but IMHO that is not all that bad. If we report the alias content,
> >      the user can probably figure out which "git help" to run next.
> 
> And if the user actually wanted to run `bar -h`, say, because `-h`
> didn't mean help for that command? I can't come up with a compelling
> example, but this goes back to "textual substitution" vs. "trying to
> decide what the user actually wants."

This is leaning into the idea that "git bar -h" without other arguments should _always_ mean help. We enforce it for our own commands (via a test script). It's not enforced for third-party commands. If somebody found a third-party command that violated this, I'd be tempted to say "you're doing it wrong". But that might not be feasible if it's a command with an established history.

But I think this is already somewhat true, isn't it? If you have alias.foo=bar, then "git foo -h" is already treated as help. René's patch restricts that to the case of "git foo -h" and not "git foo -h other-arg", which is good. But I don't know if we are ready to get rid of "git foo -h" being alias-help at all.

Show 5 quoted lines
> At any rate, a (3) to consider is "--help-all": the patches I've been
> working on are to make that flag work more often outside of Git
> repositories. I just need to clean things up a bit and get to tests.
> But if we do treat "git alias -h" specially, perhaps "--help-all" then
> also warrants treatment.

Most of the special-casing of "-h" now is just recognizing it when its alone to mean "help", even if the sub-command might recognize it as a non-help option in other contexts. I don't think --help-all really needs the same, since there's not much ambiguity to its meaning.

But yeah, if individual commands checked "--help-all" before insisting on being in a repo (just like we do for "-h"), that seems like a good improvement to me.

-Peff
Junio C Hamano· Jul 28, 2025, 13:43 UTC · re: Jeff King · lore

Re: [PATCH] git: show alias info only with lone -h

Jeff King <peff@peff.net> writes:
Show 16 quoted lines
> Another interesting case: even for our own commands, the alias itself
> may add extra arguments, which confuses things further. So:
>
>   $ git -c alias.gi='grep --cached' gi -h
>   'gi' is aliased to 'grep --cached'
>   fatal: no pattern given
>
> runs git-grep, but even though the user said only "-h" the alias added
> another option which prevents the help-mode from activating.
>
> In this case it is not too harmful, but you can come up with
> pathological cases where it actually runs a real command:
>
>   git -c alias.grep-for-foo='grep -e foo' grep-for-foo -h
>
> which runs a real grep.

Yes, that is an excellent point to further argue that we should fix the help-alias case to stop there after describing the alias. The user can choose to do "git grep -h" and look for "--cached" after learning that their 'git gi' is a shorthand for 'git grep --cached", but we shouldn't be doing so.

> I guess one way to deal with it would be if the user runs "foo -h", and
> alias.foo is "bar --other arguments", then we run just "bar -h",
> dropping the extra arguments provided by the alias.

It is much simpler and saner to just stop after giving the alias expansion, isn't it? Nobody can get hurt if we did so; doing anything else would be driving us into further corner cases that would either confuse or harm the users.

> So IMHO the patch under discussion is a strict improvement, even though
> it leaves many other questionable cases unsolved.

That part I 100% agree with. Let's accept the change, and then give further fixes in related areas.

> I'd also be happy if on top we did:
>
>   1. When alias.foo="bar --options", turn "git foo -h" into "git bar
>      -h", dropping "--options".

This smells like piling more voodoo magic on top, which I am not enthused.

Show 7 quoted lines
>   2. When alias.foo="!bar", report only the alias and do not run "bar"
>      at all. The collateral damage here would be:
>
>         !git bar $(some_shell_magic_we_need)
>
>      but IMHO that is not all that bad. If we report the alias content,
>      the user can probably figure out which "git help" to run next.

This I very much like, and further, I would prefer to do this for all aliases.

Thanks.
Jeff King· Jul 29, 2025, 07:26 UTC · re: Junio C Hamano · lore

Re: [PATCH] git: show alias info only with lone -h

On Mon, Jul 28, 2025 at 06:43:16AM -0700, Junio C Hamano wrote:
Show 8 quoted lines
> > I guess one way to deal with it would be if the user runs "foo -h", and
> > alias.foo is "bar --other arguments", then we run just "bar -h",
> > dropping the extra arguments provided by the alias.
> 
> It is much simpler and saner to just stop after giving the alias
> expansion, isn't it?  Nobody can get hurt if we did so; doing
> anything else would be driving us into further corner cases that
> would either confuse or harm the users.

Yeah, my suggestion was assuming that it is very valuable for "git foo -h" to not only print out the alias but to automatically print git-bar's help output. I don't know if people would miss it or not.

But...
Show 18 quoted lines
> > I'd also be happy if on top we did:
> >
> >   1. When alias.foo="bar --options", turn "git foo -h" into "git bar
> >      -h", dropping "--options".
> 
> This smells like piling more voodoo magic on top, which I am not
> enthused.
> 
> >   2. When alias.foo="!bar", report only the alias and do not run "bar"
> >      at all. The collateral damage here would be:
> >
> >         !git bar $(some_shell_magic_we_need)
> >
> >      but IMHO that is not all that bad. If we report the alias content,
> >      the user can probably figure out which "git help" to run next.
> 
> This I very much like, and further, I would prefer to do this for
> all aliases.

...yeah, after having slept on it, I am tempted to say that it is not that valuable. And the best thing is to just stop running the sub-command automatically entirely, whether shell-based or not.

-Peff

← back to recent threads