Echos in gitconfig aliases echoing the entire list

2019-07-20 13:32发布

For a long time, I had the following alias in my aliases file:

ignore=!([ ! -e .gitignore ] && touch .gitignore) | echo $1 >>.gitignore

It wasn't original to me, and if you search for it, you'll see it a lot of places. Recently, however, I've started having a weird problem with the alias. Anything I ignore gets placed twice in the .gitignore file and on the same line (with a space only).

I did a bit of debugging and found that what is really happening is that the call to echo $1 is echoing $1 as you'd expect, but also echoing the entire string of arguments to the alias.

To test this, I made a new alias:

eo = !echo $1

> git eo test
test test    

> git eo test0 test1
test0 test0 test1

That last line is the most interesting because it clearly shows that the echo call is getting the entire set of arguments tacked on to it while $1 is getting evaluated correctly. In fact, if I mess with things and change $1 to $9 (and don't fill $9), I get:

> git eo test0 test1
test0 test1

I have confirmed that this happens on Git versions 1.8.5 to 1.9.0 and I have confirmed that it DOES NOT happen in Git version 1.7.1; unfortunately, I am unable to test between 1.7.1 and 1.8.5.

Does anyone have any insight to what is going on here? It breaks a few of my aliases...

1条回答
我命由我不由天
2楼-- · 2019-07-20 13:41

I think the expansion isn't what you expect. Let's start with your alias:

eo = !echo $1

I believe git eo test is being expanded to:

echo $1 test

Which is then expanded to:

echo test test

The typical way git looks at the alias is to say when I say "eo", I want you to run "echo $1" and pass all arguments to that command. That allows you to do things like

[alias]
k = !gitk

And still be able to pass arguments to git k. If you want this to behave differently, you should pass it through a shell invocation like this:

[alias]
eo = !sh -c 'echo $1' -

Then you'll get the expected result.

I think for your ignore alias, you want something like

[alias]
ignore = !sh -c 'echo "$1" >> .gitignore' -

Note: you don't need to touch the file for >> to work, and in your original alias you probably meant to use ; instead of piping the output of touch into echo.

查看更多
登录 后发表回答