git submodule foreach - 递归提交子模块的鲁棒方式?

12

有没有一种强大的递归深度优先git submodule foreach命令的方法?我正在使用foreach --recursive命令,它可以完成工作,但它是广度优先的。这是一个问题,因为如果我有以下结构:

  • A
    • B
  • C

并且我在所有三个中都有提交,foreach --recursive add -A && git commit ...将会遍历 A、B、C,这会导致如果我想要在那个时候让超级模块捕捉 B 的提交就会出现问题。

我发现了这个讨论(英文链接),但看起来推荐的功能都不在我拥有的当前版本的 Git 中(1.7.9.5)。

我写了一个小的 Bash 函数来实现这个功能(名称缩写可能有点简陋):

function git-sfed() { git submodule foreach "git submodule foreach '$*' && $*"; }

并且使用以下奇妙的命令进行测试似乎有效:

git-sfed 'python -c "import sys; print sys.argv" $path'

这个命令看起来很强大,还是有其他常见的方法吗?


注意:现在一些命令已经支持子模块,例如 git grep -e "bar" --recurse-submodules 可以在 Git 2.12 中使用:https://dev59.com/xGMk5IYBdhLWcg3w-Ceq#41788645 - VonC
3个回答

18

你可以尝试这个

git submodule  foreach --recursive  |  tail  -r | sed 's/Entering//' | xargs -I% cd % ; git add -A \& git commit

这个命令会递归列出所有子模块,然后将列表反转,使用tail -r,这样您就可以按照所需顺序获取目录(从子目录开始),进入该目录并在其中执行任何操作。


比我的回答更有趣、更完整。+1 - VonC
1
谢谢这个!不幸的是,我在Ubuntu上没有-r选项,但是通过这篇帖子,有了tac命令。因此,使用不同类型的xargs,创建了另一种变体:git submodule foreach --recursive | tac | sed 's/Entering //' | xargs -n 1 bash -c 'cd $1 && git status' _ - eacousineau
我已经尝试了我的方法,但是如果我想在所有子模块和超级模块上运行提交,我相信会出现错误。稍后我将测试您的方法,看看它是否更加健壮。一旦我测试完毕,我会回来看看它的。 - eacousineau
抱歉让你久等了,但我一直在尝试使用单引号时遇到了一些问题(不能写入有点糟糕),通过多层bash命令进行转义有点混乱哈哈。目前,我正在考虑下一个最佳选项是尝试提交git-submodule的补丁,所以我会尝试一下。 - eacousineau

3

我没有找到比您的功能更好的方法来执行深度优先foreach命令。

测试将是检查它是否能够递归深度超过一个。

A
  B
    D
  C

我一直在处理使用单引号时的命令问题(不能直接写入有点糟糕) - 通过多层bash命令进行转义有点令人困惑。Git 1.9/2.0 (2014年第一季度)应该会简化这个问题,来自Anders Kaseorg (andersk)的commit 1c4fb13。'eval "$@"'会创建一个额外的shell解释层,这对于传递多个参数给git子模块循环的用户来说可能不是期望的行为。
 $ git grep "'"
 [searches for single quotes]
 $ git submodule foreach git grep "'"
 Entering '[submodule]'
 /usr/lib/git-core/git-submodule: 1: eval: Syntax error: Unterminated quoted string
 Stopping at '[submodule]'; script returned non-zero status.

为了解决这个问题,如果用户传递多个参数,则直接执行"$@"而不是将其传递给eval
示例:
典型用法在添加额外的引号层级时是传递一个表示要传递给shell的整个命令的单个参数。这并不改变这一点。
可以想象有人将不受信任的输入作为参数输入:
    git submodule foreach git grep "$variable"

那目前存在一个不明显的Shell代码注入漏洞。像这个补丁一样直接执行参数命名的命令,可以解决问题。

自Git 2.21(2017年第二季度)以来,您可以使用git grep -e "bar" --recurse-submodules命令。


我测试了mb14和我的技术,它们似乎都有效。我在pastebin上发布了一个示例 - eacousineau

0
你的方法实际上只会执行两层深度。要实现完整的递归,你需要递归地调用你的脚本本身。像下面这样的代码应该可以做到...
#!/bin/bash
SCRIPT=$(realpath "$0")
SCRIPTDIR=$(dirname "$SCRIPT")
git submodule foreach "$SCRIPT '$1' && $1"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接