我有一个 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-regexpwith 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/.*= //'