git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: Weird behavior of shell variables in git aliases

From
Jeff King <peff@peff.net>
Date
Mar 22, 2011, 11:18 UTC
Message-ID
<20110322111844.GA32446@sigill.intra.peff.net>
In-Reply-To
<7v4o6wnlxm.fsf@alter.siamese.dyndns.org>
On Mon, Mar 21, 2011 at 03:33:25PM -0700, Junio C Hamano wrote:
Show 10 quoted lines
> >> But interestingly, that's _not_ the behavior as of Erik's 7f51f8b
> >> (alias: use run_command api to execute aliases, 2011-01-07), which is in
> >> master but not yet released. With that, we end up executing:
> >>
> >>   sh -c 'echo $1 && echo $1 "$@"' 'echo $1 && echo $1' 'foo'
> [...]
> >
> > Oh, I should have been paying a bit more attention.  I've been assuming
> > that we were turning "!anything" into { "sh", "-c", "anything", "-" }
> > followed by the user supplied arguments.
Yeah, I think that would be more useful in general, but...
Show 16 quoted lines
> The attached quick hack gives
> 
>   $ git config alias.silly
>   !echo hello $1; echo $# args, bye!
>   $ GIT_TRACE=1 ./git silly world funny
>   trace: exec: 'git-silly' 'world' 'funny'
>   trace: run_command: 'git-silly' 'world' 'funny'
>   trace: run_command: 'sh' '-c' 'echo hello $1; echo $# args, bye'\!'' '-' 'world' 'funny'
>   trace: exec: 'sh' '-c' 'echo hello $1; echo $# args, bye'\!''
>   '-' 'world' 'funny'
>   hello world
>   2 args, bye!
> 
> but it would penalize a properly written alias that uses "sh -c <it> -"
> trick itself by double forking, which is not very nice and I am unhappy
> about.

Doesn't it also break a lot of other more garden-variety aliases that rely on the automagic "$@", like:

  $ git config alias.log-nopager
  !git --no-pager log
  $ GIT_TRACE=1 git.v1.7.4 log-nopager --oneline
  trace: exec: 'git-log-nopager' '--oneline'
  trace: run_command: 'git-log-nopager' '--oneline'
  trace: alias to shell cmd: log-nopager => git --no-pager log '--oneline'
  trace: built-in: git 'log' '--oneline'
  93c7d44 foo
  $ GIT_TRACE=1 git.master log-nopager --oneline
  trace: exec: 'git-log-nopager' '--oneline'
  trace: run_command: 'git-log-nopager' '--oneline'
  trace: run_command: 'git --no-pager log' '--oneline'
  trace: exec: 'sh' '-c' 'git --no-pager log "$@"' 'git --no-pager log' '--oneline'
  trace: built-in: git 'log' '--oneline'
  93c7d44 foo
  $ GIT_TRACE=1 git.jch.shell-alias log-nopager --oneline
  trace: exec: 'git-log-nopager' '--oneline'
  trace: run_command: 'git-log-nopager' '--oneline'
  trace: run_command: 'sh' '-c' 'git --no-pager log' '-' '--oneline'
  trace: exec: 'sh' '-c' 'git --no-pager log' '-' '--oneline'
  trace: built-in: git 'log'
  commit 93c7d44635e8bb56a4fd864d024ce75a2ad4ffcf
  Author: Jeff King <peff@peff.net>
  Date:   Tue Mar 22 06:57:02 2011 -0400
      foo
I think the evolution of the alias code was something like:
 1. Let's have alias.foo, so that "git foo XXX" can be aliased to "git
    log --whatever XXX", just like shell aliases.
 2. Oops, git doesn't allow some things in (1) that we might want to do,
    like turning off the pager or choosing a new repo. For that we need
    to respawn git, so now we have "!git --whatever1 log --whatever2".
    It appends the arguments, just like the form in (1), so it is
    consistent.
 3. Oops, (2) doesn't allow complex mini-scripts that access the
    parameters in a non-sequential way. You have to do "!sh -c 'git
    --whatever $1 log --whatever2 $2'".

Knowing that step (3) exists, I think your solution is a better one. The question is whether it is better enough to be worth breaking the people who were helped by step (2).

Another way of looking at it is that types (1) and (2) are like shell aliases. And they suck for complex things, just the way that shell aliases do. The solution in the shell is to put your complex alias into a shell function, or to push it into its own script. In git, you can push things into their own script, but we have no equivalent to a shell function. So one solution is:

  git config function.silly '!echo hello $1; echo $# args, bye!'

The name is of course terrible. But I think the idea is sound that there are two different types of interface people may want. On the other hand, this is getting kind of grossly complex. The separate script option is always available.

-Peff
Previous: Ævar Arnfjörð BjarmasonNext: Jeff King
Message 9 of 20 in “Weird behavior of shell variables in git aliases”
  1. Dun PealMar 21, 2011
  2. Jeff KingMar 21, 2011
  3. Junio C HamanoMar 21, 2011
  4. Junio C HamanoMar 21, 2011
  5. Lasse MakholmMar 22, 2011
  6. Jeff KingMar 22, 2011
  7. Lasse MakholmMar 22, 2011
  8. Ævar Arnfjörð BjarmasonMar 22, 2011
  9. Jeff KingMar 22, 2011
  10. Jeff KingMar 22, 2011
  11. Lasse MakholmMar 22, 2011
  12. Jeff KingMar 22, 2011
  13. Lasse MakholmMar 22, 2011
  14. Dun PealMar 22, 2011
  15. Junio C HamanoMar 22, 2011
  16. Jeff KingMar 22, 2011
  17. Lasse MakholmMar 22, 2011
  18. Junio C HamanoMar 23, 2011
  19. Junio C HamanoMar 22, 2011
  20. Junio C HamanoMar 22, 2011

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.