![](/img/trans.png)
[英]How to get a list of git submodules of repository before `git clone`?
[英]List submodules in a Git repository
我有一个 Git 存储库,其中有几个子模块。 运行git submodule init
后,如何列出所有子模块的名称?
git submodule foreach
命令可以回显子模块的名称,但这只有在它们被检出后才有效,而这在初始化步骤之后没有发生。 链中有更多步骤需要在它们被检出之前发生,我不想将子模块的名称硬连接到脚本中。
那么是否有一个 Git 命令来获取所有当前已注册但尚未签出的子模块的名称?
您可以使用与git submodule init
自身相同的机制,即查看.gitmodules
。 此文件枚举每个子模块路径及其引用的 URL。
例如,从存储库的根目录, cat .gitmodules
会将内容打印到屏幕上(假设您有cat
)。
因为 .gitmodule 文件具有 Git 配置格式,所以您可以使用 git config 来解析这些文件:
git config --file .gitmodules --name-only --get-regexp path
将向您显示所有子模块条目,并使用
git config --file .gitmodules --get-regexp path | awk '{ print $2 }'
你只会得到子模块路径本身。
如果要显示嵌套的子模块,可以使用git submodule status
或可选的git submodule status --recursive
。
来自 Git 文档:
显示子模块的状态。 这将打印每个子模块的当前签出提交的 SHA-1,以及 SHA-1 的子模块路径和 git describe 的输出。 每个 SHA-1 将带有前缀 - 如果子模块未初始化,+ 如果当前签出的子模块提交与包含存储库的索引中找到的 SHA-1 不匹配,如果子模块存在合并冲突,则为 U。
以下命令将列出子模块:
git submodule--helper list
输出是这样的:
<mode> <sha1> <stage> <location>
注意:它需要 Git 2.7.0 或更高版本。
要仅返回已注册子模块的名称,可以使用以下命令:
grep path .gitmodules | sed 's/.*= //'
将其视为不存在的git submodule --list
。
利用:
$ git submodule
它将列出指定 Git 存储库中的所有子模块。
我用这个:
git config --list|egrep ^submodule
如果您不介意只对已初始化的子模块进行操作,则可以使用git submodule foreach
来避免文本解析。
git submodule foreach --quiet 'echo $name'
您可以使用:
git submodule | awk '{ print $2 }'
我用这个:
git submodule status | cut -d' ' -f3-4
输出(路径+版本):
tools/deploy_utils (0.2.4)
按名称列出所有子模块:
git submodule --quiet foreach --recursive 'echo $name'
使用内置的 git 函数显示有关每个子模块的所有信息:
git submodule foreach -q git config -l
或者只是 URL-s:
git submodule foreach -q git config remote.origin.url
从这里偷来的。
请只是子模块路径,女士...
git config --list | grep \^submodule | cut -f 2 -d .
Vendor/BaseModel Vendor/ObjectMatcher Vendor/OrderedDictionary Vendor/_ObjC Vendor/XCodeHelpers
👍🏼
git config
允许指定一个配置文件。
.gitmodules
是一个配置文件。
因此,在“使用空格作为分隔符和剪切命令”的帮助下:
git config --file=.gitmodules --get-regexp ^^submodule.*\.path$ | cut -d " " -f 2
这将只列出路径,每个声明的子模块一个。
- 对于其中包含空格的子模块,这将失败。
子模块路径可能包含换行符,如
git submodule add https://github.com/hilbix/bashy.git "sub module" git mv 'sub module' $'sub\nmodule'
作为更强大的替代方案,Tino 建议:
git config -z --file .gitmodules --get-regexp '\.path$' | \ sed -nz 's/^[^\n]*\n//p' | \ tr '\0' '\n'
对于其中包含换行符的路径(可以使用
git mv
创建),请不要使用| tr '\0' '\n'
| tr '\0' '\n'
并使用类似... | while IFS='' read -d '' path; do ...
... | while IFS='' read -d '' path; do ...
... | while IFS='' read -d '' path; do ...
使用 bash 进行进一步处理。
这需要一个理解read -d ''
的现代 bash (不要忘记-d and ''
之间的空格)。
在我的 Git [1]版本中,每个 Git 子模块都有一个name
和一个path
。 它们不一定必须相同[2] 。 以可靠的方式获得两者,而不首先检查子模块( git update --init
),是一个棘手的 shell 巫术。
names
列表我没有找到如何使用git config
或任何其他git
命令来实现这一点的方法。 因此我们回到.gitmodules
上的正则表达式(超级丑陋)。 但它似乎有点安全,因为git
限制了子模块names
允许的可能代码空间。 此外,由于您可能希望将此列表用于进一步的 shell 处理,因此下面的解决方案使用NULL
-bytes ( \0
) 分隔条目。
$ sed -nre \
's/^\[submodule \"(.*)\"]$/\1\x0/p' \
"$(git rev-parse --show-toplevel)/.gitmodules" \
| tr -d '\n' \
| xargs -0 -n1 printf "%b\0"
在你的脚本中:
#!/usr/bin/env bash
while IFS= read -rd '' submodule_name; do
echo submodule name: "${submodule_name}"
done < <(
sed -nre \
's/^\[submodule \"(.*)\"]$/\1\x0/p' \
"$(git rev-parse --show-toplevel)/.gitmodules" \
| tr -d '\n' \
| xargs -0 -n1 printf "%b\0"
)
注意: read -rd ''
需要bash
并且不能与sh
一起使用。
paths
列表在我的方法中,我尝试不使用awk
、 tr
、 sed
来处理来自git config --get-regexp
的输出,而是将其传递给一个零字节,并将其分隔回git config --get
。 这是为了避免子模块paths
中出现换行符、空格和其他特殊字符(例如 Unicode)的问题。 此外,由于您可能希望将此列表用于进一步的 shell 处理,因此下面的解决方案使用NULL
-bytes ( \0
) 分隔条目。
$ git config --null --file .gitmodules --name-only --get-regexp '\.path$' \
| xargs -0 -n1 git config --null --file .gitmodules --get
例如,在 Bash 脚本中,您可以:
#!/usr/bin/env bash
while IFS= read -rd '' submodule_path; do
echo submodule path: "${submodule_path}"
done < <(
git config --null --file .gitmodules --name-only --get-regexp '\.path$' \
| xargs -0 -n1 git config --null --file .gitmodules --get
)
注意: read -rd ''
需要bash
并且不能与sh
一起使用。
$ git --version
git version 2.22.0
name
和path
不同的子模块设置测试存储库:
$ git init test-name-path
$ cd test-name-path/
$ git checkout -b master
$ git commit --allow-empty -m 'test'
$ git submodule add ./ submodule-name
Cloning into '/tmp/test-name-path/submodule-name'...
done.
$ ls
submodule-name
$ cat .gitmodules
[submodule "submodule-name"]
path = submodule-name
url = ./
移动子模块以使name
和path
发散:
$ git mv submodule-name/ submodule-path
$ ls
submodule-path
$ cat .gitmodules
[submodule "submodule-name"]
path = submodule-path
url = ./
$ git config --file .gitmodules --get-regexp '\.path$'
submodule.submodule-name.path submodule-path
设置测试存储库:
$ git init test
$ cd test/
$ git checkout -b master
$ git commit --allow-empty -m 'test'
$
$ git submodule add ./ simplename
Cloning into '/tmp/test/simplename'...
done.
$
$ git submodule add ./ 'name with spaces'
Cloning into '/tmp/test/name with spaces'...
done.
$
$ git submodule add ./ 'future-name-with-newlines'
Cloning into '/tmp/test/future-name-with-newlines'...
done.
$ git mv future-name-with-newlines/ 'name
> with
> newlines'
$
$ git submodule add ./ 'name-with-unicode-💩'
Cloning into '/tmp/test/name-with-unicode-💩'...
done.
$
$ git submodule add ./ sub/folder/submodule
Cloning into '/tmp/test/sub/folder/submodule'...
done.
$
$ git submodule add ./ name.with.dots
Cloning into '/tmp/test/name.with.dots'...
done.
$
$ git submodule add ./ 'name"with"double"quotes'
Cloning into '/tmp/test/name"with"double"quotes'...
done.
$
$ git submodule add ./ "name'with'single'quotes"
Cloning into '/tmp/test/name'with'single'quotes''...
done.
$ git submodule add ./ 'name]with[brackets'
Cloning into '/tmp/test/name]with[brackets'...
done.
$ git submodule add ./ 'name-with-.path'
Cloning into '/tmp/test/name-with-.path'...
done.
.gitmodules
:
[submodule "simplename"]
path = simplename
url = ./
[submodule "name with spaces"]
path = name with spaces
url = ./
[submodule "future-name-with-newlines"]
path = name\nwith\nnewlines
url = ./
[submodule "name-with-unicode-💩"]
path = name-with-unicode-💩
url = ./
[submodule "sub/folder/submodule"]
path = sub/folder/submodule
url = ./
[submodule "name.with.dots"]
path = name.with.dots
url = ./
[submodule "name\"with\"double\"quotes"]
path = name\"with\"double\"quotes
url = ./
[submodule "name'with'single'quotes"]
path = name'with'single'quotes
url = ./
[submodule "name]with[brackets"]
path = name]with[brackets
url = ./
[submodule "name-with-.path"]
path = name-with-.path
url = ./
names
列表$ sed -nre \
's/^\[submodule \"(.*)\"]$/\1\x0/p' \
"$(git rev-parse --show-toplevel)/.gitmodules" \
| tr -d '\n' \
| xargs -0 -n1 printf "%b\0" \
| xargs -0 -n1 echo submodule name:
submodule name: simplename
submodule name: name with spaces
submodule name: future-name-with-newlines
submodule name: name-with-unicode-💩
submodule name: sub/folder/submodule
submodule name: name.with.dots
submodule name: name"with"double"quotes
submodule name: name'with'single'quotes
submodule name: name]with[brackets
submodule name: name-with-.path
paths
列表$ git config --null --file .gitmodules --name-only --get-regexp '\.path$' \
| xargs -0 -n1 git config --null --file .gitmodules --get \
| xargs -0 -n1 echo submodule path:
submodule path: simplename
submodule path: name with spaces
submodule path: name
with
newlines
submodule path: name-with-unicode-💩
submodule path: sub/folder/submodule
submodule path: name.with.dots
submodule path: name"with"double"quotes
submodule path: name'with'single'quotes
submodule path: name]with[brackets
submodule path: name-with-.path
如果没有任何.gitmodules
文件,但.git/modules/
中存在子模块配置:
find .git/modules/ -name config -exec grep url {} \;
假设您目前已全部注册,但尚未签出如下子模块:
$ 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
这是从 .gitmodules 解析 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/.*= //'
在 repos 中获取名称
grep path .gitmodules | sed 's/.*= //'
只是子模块的直接列表:
git submodule--helper list | cut -d$'\t' -f 2
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 mark
,它正在吃前导空格。 要修复它,请不要使用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"
xargs
没有删除前导空格,但完整版本是。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.