Re: Git alias syntax help
- From
Jeff King <peff@peff.net>
- Date
- Jan 14, 2020, 22:28 UTC
- Message-ID
- <20200114222802.GC3957260@coredump.intra.peff.net>
- In-Reply-To
- <CAHMHMxWpLAnj3w8DGLMFbfy-A-pBjDxNdMeiM-fyuu-gnZyg+Q@mail.gmail.com>
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}" "$@" ; } ; fOnly 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