Git 在 PowerShell 中配置双引号

Git Config Double Quotes in PowerShell

有人问过这个问题 here,但没有为 PowerShell 提供解决方案。给出的解决方案在 PowerShell 中不起作用(具体来说,VSCode 中的 PowerShell 5.1)。

我试过了

git config --global mergetool.vscode.cmd '"code --wait $MERGED"'

但我丢失了双引号(即相应的 .gitconfig 文件中没有双引号)。仅供参考,单引号是将 $MERGED 作为字符串文字传递并且不让 PowerShell 尝试扩展它所必需的。

我也试过了

echo '"code --wait $MERGED"' | git config --global mergetool.vscode.cmd
git config --global mergetool.vscode.cmd '`"code --wait $MERGED`"'
git config --global mergetool.vscode.cmd @'
code --wait $MERGED
'@

但没有任何效果。没有办法从 PowerShell 中执行此操作吗?

此外,我研究了this question

的解决方案
git config --global mergetool.vscode.cmd '\"code --wait $MERGED\"'

也不

git config --global mergetool.vscode.cmd "\"code --wait $MERGED\""

也不行。

我得到的最接近的是使用

git config --global mergetool.vscode.cmd '" code --wait $MERGED "'

但这会输出字符串中的空格:

[mergetool "vscode"]
    cmd = " code --wait $MERGED "

不幸的是,需要一个模糊的解决方法(通过可安装模块查看通用解决方案的底部):

git config --global mergetool.vscode.cmd --% "\"code --wait $MERGED\""

注意:这假定您希望在 ~/.gitconfig 中得到以下内容,这可能 不是 你的意图:

[mergetool "vscode"]
    cmd = \"code --wait $MERGED\"

相反,正如 one of the answers you link to 所建议的那样,只有 $MERGED 部分应该用双引号 嵌入 双引号,在这种情况下您应该使用(请参阅底部的替代方法):

git config --global mergetool.vscode.cmd --% "code --wait \"$MERGED\""

那会给你:

[mergetool "vscode"]
    cmd = code --wait \"$MERGED\"

也就是说,只有shell命令中的那些个别参数,你的值构成需要双引号 为了 shell 的缘故 必须包含在 "...".

请注意,git 逐字重新转义 " 个字符。在给定的配置值中作为配置文件中的 \"未转义 " 在配置文件中 - 具有 语法 函数 for git 本身 - 仅在传递带有前导 and/or 尾随空格的值时使用,以便将值作为一个整体进行分隔; 带有(内部)空格的值本身需要手动双引号:git将它们按原样存储在配置文件中,除了转义嵌入式\ 作为 \" 作为 \".

从 PowerShell 传递 --% "code --wait \"$MERGED\"" 表示将 逐字 code --wait "$MERGED" 传递给 git config --global mergetool.vscode.cmd 的意图,这是 git config --global mergetool.vscode.cmd 的正确表述=113=]sh 命令行[1]sh 是 POSIX 兼容的 shell git 通过随附的 bash 实现甚至在 Windows 上使用)其中 "..." 周围(环境)变量引用 $MERGED 确保扩展例如,值按原样传递给目标二进制文件 code,即使它包含空格。

您可以通过查询之后的值来验证这一点:

# After running the command above:
PS> git config --global mergetool.vscode.cmd
code --wait "$MERGED"

git config 和配置文件格式记录 here,也可通过 运行 git help config 在本地获得,或者,仅在类 Unix 平台上,man git-config


解决方法说明:

--%stop-parsing symbol 的使用允许您控制传递给外部程序的后续参数的精确引用(同时还抑制 PowerShell 变量的扩展,因此 $MERGED 保持原样),而 PowerShell 默认情况下会在执行自己的解析后在幕后执行 重新引用

抛开对整个命令行的双引号最终不是正确的方法,纯粹从您尝试的 PowerShell 语法角度来看,'"code --wait $MERGED"', 应该 工作 - PowerShell 应该在幕后自动将其转换为 "\"code --wait $MERGED\"" - 但从 PowerShell 7.1 开始不会,由于一个长期存在的错误 ,在 this answer.

中有详细描述

虽然显式 \-转义嵌入的 " 字符。(!) 通常 是一个更好的解决方法并且在 中可靠地工作PowerShell (Core) 7+,在 Windows PowerShell 中存在一些边缘情况,但您遇到了其中之一:

# Alternative workaround for *PowerShell (Core) v7+ only*
git config --global mergetool.vscode.cmd '\"code --wait $MERGED\"'

这在 Windows PowerShell 中不起作用的原因是它错误地认为 \"...\" 构成 syntactic 双引号,因此不会' t 将参数括在 "..." 中;也就是说,它不传递 "\"...\"",而是仅传递 \"...\" 作为目标进程命令行的一部分。

请注意 单独 引用参数避免了讨论的边缘情况,因此显式 \-转义甚至在 Windows PowerShell 中也有效:

# Also works in Windows PowerShell, because the edge case is avoided.
git config --global mergetool.vscode.cmd 'code --wait \"$MERGED\"'

通过模块的通用解决方案Native:

如果你想解决 most[2] (on Windows) / all(在 Unix 上)调用外部程序,考虑我的 Native moduleie 函数,它封装了所有必需的解决方法:

# Install the module in the current user's scope.
Install-Module Native

# Simply prepend `ie` to your external-program calls, which correctly
# handles all behind-the-scenes re-quoting, allowing you to focus on 
# PowerShell syntax only.
ie git config --global mergetool.vscode.cmd 'code --wait "$MERGED"'

[1] git 似乎正在调用 sh 如下(使用带占位符的 sh 语法进行说明):
sh -c '<config-value> "$@"' '<config-value>' <git-supplied args>
也就是说,调用存储在配置值中的命令行时附加 git 提供的传递参数。请注意,第一个 post -c 参数再次是配置值,它绑定到 [=64=],即设置调用名称,因此 不是 传递参数数组的一部分,"$@"git 提供的传递参数的一个示例是要编辑的文件的路径,它被传递到存储在 core.editor 配置值中的命令行。

[2] 与 所有 外部程序一起工作的解决方案在 Windows 上基本上是不可能的,因为每个程序都可以自行决定它如何解析对传递的参数进行编码的字符串。但是,ie 了解并适当应用了一些广泛使用的模式,这使得它可以与批处理文件和类似 msiexec 的可执行文件一起稳健地工作。