我有一个Git存储库,其中有几个子模块。如何在git子模块init运行后列出所有子模块的名称?

git子模块foreach命令可以回显子模块的名称,但这只有在它们被签出后才有效,而在init步骤之后没有发生。在签出之前,链中还有更多的步骤需要执行,我不希望将子模块的名称硬连接到脚本中。

那么是否存在一个Git命令来获取所有当前已注册但尚未签出的子模块的名称?


你可以使用与git子模块init使用自身相同的机制,即查看.gitmodules。该文件枚举每个子模块路径及其引用的URL。

例如,从存储库的根目录,cat .gitmodules将把内容打印到屏幕上(假设你有cat)。

因为.gitmodule文件有Git配置格式,你可以使用Git配置来解析这些文件:

git config --file .gitmodules --name-only --get-regexp path

将显示所有子模块条目,并与

git config --file .gitmodules --get-regexp path | awk '{ print $2 }'

您只能得到子模块路径本身。


我用这个:

git config --list|egrep ^submodule

为了只返回已注册的子模块的名称,你可以使用这个命令:

grep path .gitmodules | sed 's/.*= //'

可以把它看成是git子模块list,它并不存在。


我用的是这个:

git submodule status | cut -d' ' -f3-4 

输出(路径+版本):

tools/deploy_utils (0.2.4)

如果你想要显示嵌套的子模块,你可以使用git submodule status或者git submodule status——recursive。

从Git文档中:

显示子模块的状态。的SHA-1 的子模块的当前签出提交 子模块路径和git的输出为SHA-1描述。每一个 如果子模块未初始化,SHA-1将以-作为前缀,+ 如果当前检出的子模块提交不匹配SHA-1 在包含该子模块的存储库的索引中找到U 存在合并冲突。


我注意到在回答这个问题时提供的命令为我提供了我正在寻找的信息:

在.gitmodule中找不到非子模块路径的子模块映射

git ls-files --stage | grep 160000

Use:

$ git submodule

它将列出指定Git存储库中的所有子模块。


你可以使用:

git submodule | awk '{ print $2 }'

这招对我很管用:

git ls-files --stage | grep ^160000

它基于这篇伟大的文章:理解Git子模块

它必须读取grep ^160000。


Git配置允许指定配置文件。 gitmodules是一个配置文件。

因此,在“使用空格作为cut命令的分隔符”的帮助下:

git config --file=.gitmodules --get-regexp ^^submodule.*\.path$ | cut -d " " -f 2

它将只列出路径,每个声明的子模块一个路径。

Tino在评论中指出:

这对于包含空格的子模块无效。 子模块路径可能包含换行符,如 Git子模块添加https://github.com/hilbix/bashy.git“子模块” Git mv 'sub module' $'sub\nmodule'

作为一个更强大的替代方案,Tino提出:

Git config -z——file . Git modules——get-regexp ` \。路径$' | \ Sed -nz 's/^[^\n]*\n//p' | \ Tr '\0' '\n' 对于有换行符的路径(可以用git mv创建),去掉| tr '\0' '\n',使用类似于…| while IFS= " read -d " path;做……用于使用bash进行进一步处理。 这需要一个现代bash,它能理解read -d "(不要忘记-d和"之间的空格)。


下面的命令将列出子模块:

git submodule--helper list

输出如下所示:

<mode> <sha1> <stage> <location>

注意:需要Git 2.7.0或以上版本。


如果你不介意只对初始化的子模块进行操作,你可以使用git子模块foreach来避免文本解析。

git submodule foreach --quiet 'echo $name'

按名称列出所有子模块:

Git子模块——quiet foreach——递归echo $name


如果没有任何.gitmodules文件,但在.git/modules/中存在子模块配置:

find .git/modules/ -name config -exec grep url {} \;

下面是另一种从. Git modules解析Git子模块名称的方法,不需要sed或花哨的IFS设置。: -)

#!/bin/env bash

function stripStartAndEndQuotes {
  temp="${1%\"}"
  temp="${temp#\"}"
  echo "$temp"
}

function getSubmoduleNames {
  line=$1
  len=${#line} # Get line length
  stripStartAndEndQuotes "${line::len-1}" # Remove last character
}

while read line; do
  getSubmoduleNames "$line"
done < <(cat .gitmodules | grep "\[submodule.*\]" | cut -d ' ' -f 2-)

获取路径

grep url .gitmodules | sed 's/.*= //'

在回购中得到名字

grep path .gitmodules | sed 's/.*= //'

使用内置git函数显示每个子模块的所有信息:

git submodule foreach -q git config -l

或者只是url:

git submodule foreach -q git config remote.origin.url

从这里偷来的。


只是一个简单的子模块列表:

git submodule--helper list | cut -d$'\t' -f 2

Tino的评论显示了一个很好的替代方案:

git config --null --file .gitmodules --get-regexp "\.path\$" | \
sed -nz "s/^[^\\n]*\n//p" | \
xargs --null rm -v;

但是——null/-z选项不适用于BusyBox上的sed或xargs。然后,这是我能想到的最好的替代方案(xargs不会在空格上中断):

grep "^\s*path\s*=" .gitmodules | \
sed -e "s/.*=\s*\"*//" -e "s/\"*\s*\$//" | \
xargs -n 1 -I mark rm -v "mark";

但它有一个缺点,因为xargs调用时不带——null,而我们使用的是-I标记,它正在吞噬前导空白。要修复它,不要使用xargs并将名称写入文件:

grep "^\s*path\s*=" .gitmodules | \
sed -e "s/.*=\s*\"*//" -e "s/\"*\s*\$//" > tempfilefordanmxargsmotherbroked.txt;
while IFS= read -r line; do
   echo ".$line."
done <"tempfilefordanmxargsmotherbroked.txt"
rm "tempfilefordanmxargsmotherbroked.txt"

更正:BusyBox上的xargs没有删除前导空白,但完整版本可以。


假设你目前已经注册了,但还没有签出子模块,如下:

$ cat .gitmodules
[submodule ".github/workflows/packages"]
        path = .github/workflows/packages
        url = https://github.com/MarketLeader/Packages
[submodule ".github/workflows/builders"]
        path = .github/workflows/builders
        url = https://github.com/chetabahana/runner
[submodule "docs"]
        path = docs
        url = https://github.com/eq19/lexer

下面是Git命令来获取存储库的根目录:

$ git submodule foreach -q '[[ "$sm_path" == */* ]] || git config remote.origin.url'
https://github.com/eq19/lexer

下面是Git命令在特定路径上获取列表:

$ git submodule foreach -q '[[ ! "$sm_path" == .github/* ]] || git config remote.origin.url'
https://github.com/chetabahana/runner
https://github.com/MarketLeader/Packages

当然,你也可以用其他命令修改git config remote.origin.url。

顺便说一下,我使用的是git 2.38.1版