我有一个 Git 存储库,其中包含多个子模块。运行后如何列出所有子模块的名称git submodule init
?
该git submodule foreach
命令可以回显子模块的名称,但只有在它们被签出后才有效,而这在 init 步骤之后没有发生。在签出之前需要执行链中的更多步骤,我不想将子模块的名称硬连接到脚本中。
那么是否有一个 Git 命令来获取所有当前注册但尚未签出的子模块的名称?
我有一个 Git 存储库,其中包含多个子模块。运行后如何列出所有子模块的名称git submodule init
?
该git submodule foreach
命令可以回显子模块的名称,但只有在它们被签出后才有效,而这在 init 步骤之后没有发生。在签出之前需要执行链中的更多步骤,我不想将子模块的名称硬连接到脚本中。
那么是否有一个 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 --quiet foreach --recursive 'echo $name'
我用这个:
git submodule status | cut -d' ' -f3-4
输出(路径+版本):
tools/deploy_utils (0.2.4)
请只是子模块路径,女士...
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
),请不要使用 bash| tr '\0' '\n'
并使用类似的东西... | while IFS='' read -d '' path; do ...
进行进一步处理。
这需要一个现代的 bash 可以理解read -d ''
(不要忘记 之间的空格-d and ''
)。
使用内置的 git 函数显示有关每个子模块的所有信息:
git submodule foreach -q git config -l
或者只是 URL-s:
git submodule foreach -q git config remote.origin.url
从这里偷来的。
在我的 Git [1]版本中,每个 Git 子模块都有一个name
和一个path
. 它们不一定必须相同[2]。以可靠的方式获取两者,而不首先检查子模块(git update --init
),是一个棘手的 shell 巫术。
names
我没有找到如何使用git config
或任何其他git
命令来实现此目的的方法。因此我们回到正则表达式.gitmodules
(超级丑陋)。但它似乎有点安全,因为git
限制了 submodule 允许的可能代码空间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
在我的方法中,我尝试不处理来自git config --get-regexp
with awk
, tr
, sed
, ... 的输出,而是将其传递给分隔回的零字节git config --get
。这是为了避免子模块中出现换行符、空格和其他特殊字符(例如 Unicode)的问题paths
。此外,由于您可能希望将此列表用于进一步的 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 {} \;
这是从 .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/.*= //'