threads / discuss / 52635

Git alias syntax help

Subject: Git alias syntax help

## tl;dr

5 messages between Jan 14, 2020 and Mar 28, 2020.

replies: 4people: 3as markdown or json

Σταύρος Ντέντος· Jan 14, 2020, 15:21 UTC · lore
Hello there,

I am having an issue with git-aliases - specifically, the intricacies involved in their syntax.

In general, the syntax is confusing to me, especially when it is _wise_ to use quotes inside a `!sh` alias. e.g. which one would be the correct one new = "!f() { : git log ; git log \"${1}@{1}..${1}@{0}\" \"$@\" ; } ; f" new = !f() { : git log ; git log "${1}@{1}..${1}@{0}" "$@" ; } ; f

(from converting this:
https://git.wiki.kernel.org/index.php/Aliases#What.27s_new.3F)
        new = !sh -c 'git log $1@{1}..$1@{0} "$@"'

The alias confusing me is more specifically this: https://git.wiki.kernel.org/index.php/Aliases#simple_diff_ignoring_line_number_changes

diffsort = !sh -c 'git diff "$@" | grep "^[+-]" | sort --key=1.2 | uniq -u -s1'

The output of: $ colordiff -su <(git diffsort HEAD^..HEAD) <(git diffsort HEAD^^..HEAD^) Files /dev/fd/63 and /dev/fd/62 are identical is a little unexpected, since I know for a fact that one of the referced commits is not a code block moved.

(and indeed, if I do it myself:
$ colordiff -su <(git diff HEAD^..HEAD | grep "^[+-]" | sort --key=1.2
| uniq -u -s1) <(git diff HEAD^^..HEAD^ | grep "^[+-]" | sort
--key=1.2 | uniq -u -s1)
--- /dev/fd/63 2020-01-14 17:17:45.103771745 +0200
+++ /dev/fd/62 2020-01-14 17:17:45.103771745 +0200
@@ -1,2 +1,13 @@
[....]

it works.

The issue I have found is: $@ is not expanded

Tested with:

diffsort = !sh -c 'echo "+git diff $@" | grep "^[+-]" | sort --key=1.2
| uniq -u -s1'
$ git diffsort HEAD^..HEAD
+git diff

I would appreciate if someone would clear out the air for me.
I think I have done my homework enough, and it is not trivially
obvious what is the correct thing to do.

I'll gladly take pointers though

Ντέντος Σταύρος
Jeff King· Jan 14, 2020, 22:28 UTC · re: Σταύρος Ντέντος · lore

Re: Git alias syntax help

On Tue, Jan 14, 2020 at 05:21:20PM +0200, Σταύρος Ντέντος wrote:
Show 8 quoted lines
> I am having an issue with git-aliases - specifically, the intricacies
> involved in their syntax.
> 
> In general, the syntax is confusing to me, especially when it is
> _wise_ to use quotes inside a `!sh` alias.
> e.g. which one would be the correct one
> new = "!f() { : git log ; git log \"${1}@{1}..${1}@{0}\" \"$@\" ; } ; f"
> new = !f() { : git log ; git log "${1}@{1}..${1}@{0}" "$@" ; } ; f

Only the first one is correct. In addition to the quotes in the second one being eaten by the config parser, the unquoted semicolon starts a comment.

Show 10 quoted lines
> The alias confusing me is more specifically this:
> https://git.wiki.kernel.org/index.php/Aliases#simple_diff_ignoring_line_number_changes
> 
> diffsort = !sh -c 'git diff "$@" | grep "^[+-]" | sort --key=1.2 | uniq -u -s1'
> 
> The output of:
> $  colordiff -su <(git diffsort HEAD^..HEAD) <(git diffsort HEAD^^..HEAD^)
> Files /dev/fd/63 and /dev/fd/62 are identical
> is a little unexpected, since I know for a fact that one of the
> referced commits is not a code block moved.

The issue here isn't with Git's alias mechanism, but a quirk of how "sh -c" works. You can run with GIT_TRACE to see what we're passing to the shell (though note that your double-quotes don't make it through):

  $ GIT_TRACE=1 git diffsort HEAD^..HEAD
  17:22:47.644542 [pid=3959333] git.c:708           trace: exec: git-diffsort HEAD^..HEAD
  17:22:47.644648 [pid=3959333] run-command.c:663   trace: run_command: git-diffsort HEAD^..HEAD
  17:22:47.645038 [pid=3959333] run-command.c:663   trace: run_command: 'sh -c '\''git diff $@ | grep ^[+-] | sort --key=1.2 | uniq -u -s1'\''' HEAD^..HEAD
  17:22:47.650319 [pid=3959336] git.c:439           trace: built-in: git diff

The problem is that "sh -c" takes the first non-option argument as $0, not $1. For example:

  $ sh -c 'echo 0=$0, @=$@' foo bar baz
  0=foo, @=bar baz
You can add any extra string there to become $0, like:
  diffsort = "!sh -c 'git diff \"$@\" | grep \"^[+-]\" | sort --key=1.2 | uniq -u -s1' --"

which will do what you want. You can use whatever string you like, since you know that your "-c" snippet does not ever look at $0.

-Peff
Σταύρος Ντέντος· Jan 14, 2020, 23:13 UTC · re: Jeff King · lore

Re: Git alias syntax help

On Wed, 15 Jan 2020 at 00:28, Jeff King <peff@peff.net> wrote:
Show 15 quoted lines
>
> On Tue, Jan 14, 2020 at 05:21:20PM +0200, Σταύρος Ντέντος wrote:
>
> > I am having an issue with git-aliases - specifically, the intricacies
> > involved in their syntax.
> >
> > In general, the syntax is confusing to me, especially when it is
> > _wise_ to use quotes inside a `!sh` alias.
> > e.g. which one would be the correct one
> > new = "!f() { : git log ; git log \"${1}@{1}..${1}@{0}\" \"$@\" ; } ; f"
> > new = !f() { : git log ; git log "${1}@{1}..${1}@{0}" "$@" ; } ; f
>
> Only the first one is correct. In addition to the quotes in the second
> one being eaten by the config parser, the unquoted semicolon starts a
> comment.
Could somehow the latter "become" the correct option?
Especially in the case of `!sh`:
1) You need to quote everything after `=` sign ("forced" double quotes), then
2) `sh -c` needs another set (singles are most safe here, I think), and
3) If, for some reason, you need to quote further ("$@" would be a
common suspect usually)

Apart from the [1] feeling unneeded (the equivalent of Python's `alias_cmd = cfg_line.split()[1]` could be enough), this brings a quoting mess on [3]

Show 35 quoted lines
> > The alias confusing me is more specifically this:
> > https://git.wiki.kernel.org/index.php/Aliases#simple_diff_ignoring_line_number_changes
> >
> > diffsort = !sh -c 'git diff "$@" | grep "^[+-]" | sort --key=1.2 | uniq -u -s1'
> >
> > The output of:
> > $  colordiff -su <(git diffsort HEAD^..HEAD) <(git diffsort HEAD^^..HEAD^)
> > Files /dev/fd/63 and /dev/fd/62 are identical
> > is a little unexpected, since I know for a fact that one of the
> > referced commits is not a code block moved.
>
> The issue here isn't with Git's alias mechanism, but a quirk of how "sh
> -c" works.  You can run with GIT_TRACE to see what we're passing to the
> shell (though note that your double-quotes don't make it through):
>
>   $ GIT_TRACE=1 git diffsort HEAD^..HEAD
>   17:22:47.644542 [pid=3959333] git.c:708           trace: exec: git-diffsort HEAD^..HEAD
>   17:22:47.644648 [pid=3959333] run-command.c:663   trace: run_command: git-diffsort HEAD^..HEAD
>   17:22:47.645038 [pid=3959333] run-command.c:663   trace: run_command: 'sh -c '\''git diff $@ | grep ^[+-] | sort --key=1.2 | uniq -u -s1'\''' HEAD^..HEAD
>   17:22:47.650319 [pid=3959336] git.c:439           trace: built-in: git diff
>
> The problem is that "sh -c" takes the first non-option argument as $0,
> not $1. For example:
>
>   $ sh -c 'echo 0=$0, @=$@' foo bar baz
>   0=foo, @=bar baz
>
> You can add any extra string there to become $0, like:
>
>   diffsort = "!sh -c 'git diff \"$@\" | grep \"^[+-]\" | sort --key=1.2 | uniq -u -s1' --"
>
> which will do what you want. You can use whatever string you like, since
> you know that your "-c" snippet does not ever look at $0.
>
> -Peff
Thank you very much for a complete explaination of all of this .

Can some of this be documented somewhere? Are they somewhere and I missed them?

If nothing more, a link to this e-mail chain either on the wiki (if https://git.wiki.kernel.org/index.php/Aliases is an official page) or on git-alias help (here https://git-scm.com/book/en/v2/Git-Basics-Git-Aliases or in some "advanced" section, which I cannot find)

If https://git.wiki.kernel.org/index.php/Aliases is an official page, then: was this written for an earlier version? Could it also be updated?

-- Ntentos Stavros

Jeff King· Jan 15, 2020, 18:13 UTC · re: Σταύρος Ντέντος · lore

Re: Git alias syntax help

On Wed, Jan 15, 2020 at 01:13:17AM +0200, Σταύρος Ντέντος wrote:
Show 8 quoted lines
> > > new = "!f() { : git log ; git log \"${1}@{1}..${1}@{0}\" \"$@\" ; } ; f"
> > > new = !f() { : git log ; git log "${1}@{1}..${1}@{0}" "$@" ; } ; f
> >
> > Only the first one is correct. In addition to the quotes in the second
> > one being eaten by the config parser, the unquoted semicolon starts a
> > comment.
> 
> Could somehow the latter "become" the correct option?

Unfortunately not without breaking compatibility of existing config files.

Show 5 quoted lines
> Especially in the case of `!sh`:
> 1) You need to quote everything after `=` sign ("forced" double quotes), then
> 2) `sh -c` needs another set (singles are most safe here, I think), and
> 3) If, for some reason, you need to quote further ("$@" would be a
> common suspect usually)

Yes, the quoting can get pretty hairy. If your command is complicated, I suggest writing it as a separate script and dropping it into your $PATH as git-new. Then "git new" will run it automatically (and it's not even any less efficient; it still ends up with a single shell invocation).

> Thank you very much for a complete explaination of all of this .
> 
> Can some of this be documented somewhere?
> Are they somewhere and I missed them?

I think the config syntax around quoting is described in "git help config" (see the section Syntax). The shell parts seem out of scope for Git's manpages themselves, though it sounds like maybe some examples you found could stand to be fixed (and/or to call out the subtlety).

Show 9 quoted lines
> If nothing more, a link to this e-mail chain either on the wiki (if
> https://git.wiki.kernel.org/index.php/Aliases is an official page) or
> on git-alias help (here
> https://git-scm.com/book/en/v2/Git-Basics-Git-Aliases or in some
> "advanced" section, which I cannot find)
> 
> If https://git.wiki.kernel.org/index.php/Aliases is an official page,
> then: was this written for an earlier version?
> Could it also be updated?

I think both of the issues you mentioned have always been true. That wiki is open to editing by the world, so it's possible that somebody just added bad examples (and fixes would be welcome).

I don't know the book content very well. Looking at the page you linked, I don't think it says anything _wrong_, but it definitely doesn't discuss more advanced alias usage. I suspect that would be a welcome addition; they take contributions at https://github.com/progit/progit2.

-Peff
Philip Oakley· Mar 28, 2020, 17:05 UTC · re: Jeff King · lore

Re: Git alias syntax help

Hi,
On 15/01/2020 18:13, Jeff King wrote:
Show 41 quoted lines
> On Wed, Jan 15, 2020 at 01:13:17AM +0200, Σταύρος Ντέντος wrote:
>
>>>> new = "!f() { : git log ; git log \"${1}@{1}..${1}@{0}\" \"$@\" ; } ; f"
>>>> new = !f() { : git log ; git log "${1}@{1}..${1}@{0}" "$@" ; } ; f
>>> Only the first one is correct. In addition to the quotes in the second
>>> one being eaten by the config parser, the unquoted semicolon starts a
>>> comment.
>> Could somehow the latter "become" the correct option?
> Unfortunately not without breaking compatibility of existing config
> files.
>
>> Especially in the case of `!sh`:
>> 1) You need to quote everything after `=` sign ("forced" double quotes), then
>> 2) `sh -c` needs another set (singles are most safe here, I think), and
>> 3) If, for some reason, you need to quote further ("$@" would be a
>> common suspect usually)
> Yes, the quoting can get pretty hairy. If your command is complicated, I
> suggest writing it as a separate script and dropping it into your $PATH
> as git-new. Then "git new" will run it automatically (and it's not even
> any less efficient; it still ends up with a single shell invocation).
>
>> Thank you very much for a complete explaination of all of this .
>>
>> Can some of this be documented somewhere?
>> Are they somewhere and I missed them?
> I think the config syntax around quoting is described in "git help
> config" (see the section Syntax). The shell parts seem out of scope for
> Git's manpages themselves, though it sounds like maybe some examples you
> found could stand to be fixed (and/or to call out the subtlety).
>
>> If nothing more, a link to this e-mail chain either on the wiki (if
>> https://git.wiki.kernel.org/index.php/Aliases is an official page) or
>> on git-alias help (here
>> https://git-scm.com/book/en/v2/Git-Basics-Git-Aliases or in some
>> "advanced" section, which I cannot find)
>>
>> If https://git.wiki.kernel.org/index.php/Aliases is an official page,
>> then: was this written for an earlier version?
>> Could it also be updated?
> I think both of the issues you mentioned have always been true. That
> wiki is open to editing by the world,

I took the liberty of adding a small subsection on quoting based on this discussion, and adding a link to it. Feedback on my ignorance welcomed ;-)

Show 10 quoted lines
>  so it's possible that somebody
> just added bad examples (and fixes would be welcome).
>
> I don't know the book content very well. Looking at the page you
> linked, I don't think it says anything _wrong_, but it definitely
> doesn't discuss more advanced alias usage. I suspect that would be a
> welcome addition; they take contributions at
> https://github.com/progit/progit2.
>
> -Peff
Philip

← back to recent threads