Just bumped into something similar; hope it's oK to post my notes. One thing that confuses me about git
aliases with arguments, probably comes from the git help config
(I have git version 1.7.9.5):
If the alias expansion is prefixed with an exclamation point, it will be treated as a shell command. For example, defining "alias.new = !gitk --all --not ORIG_HEAD", the invocation "git new" is equivalent to running the shell command
"gitk --all --not ORIG_HEAD". Note that shell commands will be executed from the top-level directory of a repository,
which may not necessarily be the current directory. [...]
The way I see it - if an alias "will be treated as a shell command" when prefixed with an exclamation point - why would I need to use a function, or sh -c
with arguments; why not just write my command as-is?
I still don't know the answer - but I think actually there is a slight difference in the outcome. Here's a little test - throw this in your .git/config
or your ~/.gitconfig
:
[alias]
# ...
ech = "! echo rem: "
shech = "! sh -c 'echo rem:' "
fech = "! f() { echo rem: ; }; f " # must have ; after echo!
echargs = "! echo 0[[\"$0\"]] 1-\"$1\"/ A-"$@"/ "
fechargs = "! f() { echo 0[[\"$0\"]] 1-\"$1\"/ A-"$@"/ ; }; f "
Here is what I get running these aliases:
$ git ech word1 word2
rem: word1 word2
$ git shech word1 word2
rem:
$ git fech word1 word2
rem:
$ git echargs word1 word2
0[[ echo 0[["$0"]] 1-"$1"/ A-$@/ ]] 1-word1/ A-word1 word2/ word1 word2
$ git fechargs word1 word2
0[[ f() { echo 0[["$0"]] 1-"$1"/ A-$@/ ; }; f ]] 1-word1/ A-word1 word2/
... or: when you're using a "plain" command after the !
"as-is" in a git
alias - then git
automatically appends the arguments list to that command! A way to avoid it, is indeed, to call your script as either a function - or as the argument to sh -c
.
Another interesting thing here (for me), is that in a shell script, one typically expects the automatic variable $0
to be the filename of the script. But for a git
alias function, the $0
argument is, basically, the content of the entire string specifying that command (as entered in the config file).
Which is why, I guess, if you happen to misquote - in the below case, that would be escaping the outer double quotes:
[alias]
# ...
fail = ! \"echo 'A' 'B'\"
... - then git
would fail with (for me, at least) somewhat cryptic message:
$ git fail
"echo 'A' 'B'": 1: echo 'A' 'B': not found
fatal: While expanding alias 'fail': ' "echo 'A' 'B'"': No such file or directory
I think, since git
"saw" a whole string as only one argument to !
- it tried to run it as an executable file; and correspondingly it failed finding "echo 'A' 'B'"
as a file.
In any case, in the context of the git help config
quote above, I'd speculate that it's more accurate to state something like: " ... the invocation "git new" is equivalent to running the shell command "gitk --all --not ORIG_HEAD $@", where $@ are the arguments passed to the git command alias from the command line at runtime. ... ". I think that would also explain, why the "direct" approach in OP doesn't work with positional parameters.
$1
should work). – Causation