如何在git子模块foreach中运行多个命令?

au9on6nz  于 2023-09-29  发布在  Git
关注(0)|答案(2)|浏览(120)

我所尝试的

git submodule foreach git checkout main
git submodule foreach git add --all
git submodule foreach git diff-index --quiet HEAD || git commit -m "%CommitMessage%"
git submodule foreach git push

这将对所有子模块运行命令1,然后对所有子模块运行命令2,依此类推。
我想要什么
我希望只有一个foreach,并一次执行子模块的所有命令,然后继续执行下一个子模块。

提问

有没有办法让git submodule foreach调用一个方法,或者以某种方式一次调用多个命令?
我想在Windows上的批处理脚本中执行此操作。

w9apscun

w9apscun1#

假设一个类Unix环境,你可以用git submodule foreach运行一个shell脚本:

git submodule foreach sh -e -c '
  git checkout main
  git add --all
  git diff-index --quiet HEAD || git commit -m "message"
  git push
  '
gojuced7

gojuced72#

要使用 Windows 的**解决方案补充larsks' helpful Unix solution,请从 * 批处理文件 *(请参阅 PowerShell 的下一节):

  • git支持传递 *shell命令 * 的其他情况一样,这些命令由Git Bash评估,即Windows上与git捆绑在一起的Bash实现。因此,即使在Windows上也必须使用 Bash(POSIX兼容)shell语法。
  • 注意:git submodule foreach定义了以下(环境)变量来提供关于子模块的信息,您可以在shell命令中引用这些变量:
  • $name$sm_path$displaypath$sha1$toplevel ;如上所述,由于必须在shell命令中使用 Bash 语法,您需要引用这些变量,如图所示(例如:作为$name而不是批处理文件样式%name%
  • 详情请参见git help submodule
git submodule foreach "git checkout main && git add --all && git diff-index --quiet HEAD || git commit -m \"%CommitMessage%\" && git push"
  • 在 * 单行 * 上使用"..."引号(cmd.exe/批处理文件不支持多行引号字符串,并且程序只期望",而不是'在其进程命令行上具有语法功能)。
  • %CommitMessage%批处理样式的变量引用被 * 预先 * 扩展为cmd.exe\"...\"用于正确地转义扩展结果周围的嵌入式"..."
    *警告:如果%CommitMessage%的值包含cmd.exe元字符,如|&,则命令将 break,因为cmd.exe将这些视为 unquoted,这是由于不理解周围的\"是 * 转义 * 双引号;正如您所报告的,set "CommitMessage=%info1% | %info2% | %info3%"在您的案例中导致了一个问题,有两个解决方案选项:
  • 或者:如果可行,手动^-转义元字符;例如:
set "CommitMessage=%info1% ^| %info2% ^| %info3%"
  • 或者,就像你已经做的那样,使用 delayed variable expansion,这会绕过这个问题(但可能会导致文字!字符被消除):
  • 在批处理文件的顶部使用setlocal enableDelayedExpansion
  • 然后使用!...!而不是%...%来引用变量,即!CommitMessage!
  • 使用&&链接命令,以便后续命令仅在前一个命令成功时执行。
    PowerShell透视图(在Windows和类Unix平台上):
  • PowerShell具有灵活的string literals,包括支持 * 多行 * 文字。
  • 下面使用的here-string变体有助于提高可读性,并避免了对嵌入的引号进行转义。
# NOTE: In Windows PowerShell and PowerShell (Core) 7.2-,
#       you must manually \-escape the embedded " chars.
#       (... -m \"$CommitMessage\")
#       $CommitMessage is expanded *by PowerShell*, up front.
git submodule foreach @"
  git checkout main && 
  git add --all && 
  git diff-index --quiet HEAD || git commit -m "$CommitMessage" && 
  git push
"@

重要

  • 如代码注解中所述,Windows PowerShell和_PowerShell(Core)](https://github.com/PowerShell/PowerShell/blob/master/README.md)版本 * 直至v7.2.x* 不幸地需要嵌入"字符。在将参数传递给外部程序(如git)时显式地进行\-转义,幸运的是,PowerShell(Core)7.3+中不再需要此参数
  • 请参阅this answer了解更多信息。
  • 由于PowerShell也使用sigil $作为变量引用,因此您必须```-转义任何您想要保留的$字符,作为git执行的(POSIX兼容)shell命令的一部分;例如,为了传递逐字的$name以引用子模块名称,使用``$name`
  • 但是,这仅在使用"..."引号时才有必要,即 expandable 字符串,而这仅在需要PowerShell的 * 字符串插值 *(扩展)时才有必要,例如如上所示嵌入 *PowerShell变量 * $CommitMessage的值。
  • 如果不需要字符串插值,则使用'...'引号,即一个 verbatim 字符串('...'),在这种情况下传递$字符。不需要逃跑。
  • Larsks的Unix解决方案可以在PowerShell(Core)7.3+中按原样使用,但只能在类似 Unix 的环境中使用(包括WSL,如果你也安装了PowerShell(Core)*),因为标准的Unix shell /bin/sh被显式调用。
  • 顺便说一句:因此,这种技术涉及每个子模块的 * 额外 * sh进程,但很方便,因为-e选项(当命令失败时中止)允许单独指定命令,而不必将它们与&&链接在一起

相关问题