为什么引用参数在git别名中不起作用?

Meh*_*dad 0 git shell parsing

我有以下内容~/.gitconfig

[alias]
    print = !printf %s\\\\n a b c
Run Code Online (Sandbox Code Playgroud)

它的行为如下:

$ git print
a
b
c
Run Code Online (Sandbox Code Playgroud)

但是现在我将其更改为以下内容~/.gitconfig

[alias]
    print = !printf %s\\\\n "a b" c
Run Code Online (Sandbox Code Playgroud)

ab仍然会进行分词:

$ git print
a
b
c
Run Code Online (Sandbox Code Playgroud)

如果""引号不能阻止单词拆分,那么它们在做什么?
命令如何解析?

tor*_*rek 5

Git的配置语言解析器出于自身目的使用双引号

... "可以通过将逸出转义为\"和来包括双引号和反斜杠\\。阅读时,其他字符前面的反斜杠将被删除;例如,\t读取为t\0读取为0...

当此特定段落讨论小节名称时,双引号和双反斜杠规则也适用于小节名称之外。这些引号的其余部分适用于所有地方,但小节名称中的\t= 除外t

在双引号内,必须对双引号"和反斜杠\字符进行转义:使用\"for "\\for \

可以识别以下转义序列(在\"和旁边\\):\n换行符(NL),\t水平制表符(HT,TAB)和\b退格键(BS)。其他字符转义序列(包括八进制转义序列)无效。

请注意,这与别名没有任何关系:这些规则适用于或文件中的所有行。(这在子模块路径中很重要,尽管通常不会在其中将双引号编码。).gitconfig.git/config

现在,完成配置解析器的.git/config文件读取之后,如果该行在某alias节中,则它将定义一个别名。在该别名中,双引号确实可以防止单词拆分:

[alias]
    foo = log \"a b\"

$ git foo
fatal: ambiguous argument 'a b': unknown revision or path not in the working tree.
Run Code Online (Sandbox Code Playgroud)

请注意,首先要通过配置解析器,必须使用反斜杠。为了避免这种特殊的烦恼,我们可以改用单引号:

[alias]
    foo = log 'a b'
Run Code Online (Sandbox Code Playgroud)

产生相同的结果。

如果别名是shell别名(以前缀!),则将整个字符串(当然减去感叹号)输入到shell。要观察这一点,请使用GIT_TRACE

[alias]
    foo = !printf %s\\\\n 'a b'

$ GIT_TRACE=1 git foo
23:15:46.947801 git.c:670               trace: exec: git-foo
23:15:46.948153 run-command.c:643       trace: run_command: git-foo
23:15:46.948883 run-command.c:643       trace: run_command: 'printf %s\\n '\''a b'\'''
a b
Run Code Online (Sandbox Code Playgroud)

如果我们在配置解析器后得到双引号,则它们具有相同的效果:

$ GIT_TRACE=1 git foo
23:16:24.919042 git.c:670               trace: exec: git-foo
23:16:24.919402 run-command.c:643       trace: run_command: git-foo
23:16:24.920114 run-command.c:643       trace: run_command: 'printf %s\\n "a b"'
a b
Run Code Online (Sandbox Code Playgroud)

当然,我们需要四个反斜杠的原因是,Git配置解析器将它们变成了两个反斜杠(如GIT_TRACE=1输出所示),然后外壳程序本身将它们变成了一个反斜杠,然后printf与组合n成一个换行符。

尝试别名:

    foo = !printf %s\\\\n "a b
Run Code Online (Sandbox Code Playgroud)

失败:

fatal: bad config line 30 in file [path]/.gitconfig
Run Code Online (Sandbox Code Playgroud)

因为Git本身正在运行其逐行解析器,并且对未封闭的报价不满意。