296

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

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

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

4

19 回答 19

218

您可以使用与使用本身相同的机制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 }'

你只会得到子模块路径本身。

于 2012-09-28T14:16:46.240 回答
161

如果要显示嵌套的子模块,您可以使用git submodule status或可选。git submodule status --recursive

来自 Git 文档:

显示子模块的状态。这将打印每个子模块的当前签出提交的 SHA-1,以及 SHA-1 的子模块路径和 git describe 的输出。每个 SHA-1 将带有前缀 - 如果子模块未初始化,+ 如果当前签出的子模块提交与包含存储库的索引中找到的 SHA-1 不匹配,如果子模块存在合并冲突,则为 U。

于 2014-05-06T09:25:00.590 回答
74

以下命令将列出子模块:

git submodule--helper list

输出是这样的:

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

注意:它需要 Git 2.7.0 或更高版本。

于 2016-11-29T23:01:59.910 回答
62

要仅返回已注册子模块的名称,可以使用以下命令:

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

把它想象成git submodule --list不存在的。

于 2013-06-17T21:48:36.713 回答
34

利用:

$ git submodule

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

于 2014-09-28T10:31:58.093 回答
17

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

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

git ls-files --stage | grep 160000
于 2014-06-09T14:21:50.393 回答
17

我用这个:

git config --list|egrep ^submodule
于 2013-06-13T13:32:25.757 回答
15

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

git submodule foreach --quiet 'echo $name'
于 2017-07-05T18:45:30.637 回答
10

您可以使用:

git submodule | awk '{ print $2 }'
于 2014-12-21T22:11:31.437 回答
9

按名称列出所有子模块:

git submodule --quiet foreach --recursive 'echo $name'

于 2018-01-27T07:30:03.430 回答
8

这对我有用:

git ls-files --stage | grep ^160000

它基于这篇很棒的文章:了解 Git 子模块

它必须阅读grep ^160000

于 2015-03-29T03:08:52.940 回答
8

我用这个:

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

输出(路径+版本):

tools/deploy_utils (0.2.4)
于 2013-10-29T13:14:30.183 回答
5

请只是模块路径,女士...

git config --list | grep \^submodule | cut -f 2 -d .
Vendor/BaseModel
Vendor/ObjectMatcher
Vendor/OrderedDictionary
Vendor/_ObjC
Vendor/XCodeHelpers

于 2015-06-02T18:25:17.793 回答
5

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 '')。

于 2015-07-29T09:02:46.117 回答
4

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

git submodule foreach -q git config -l

或者只是 URL-s:

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

从这里偷来的。

于 2021-01-26T12:53:47.950 回答
3

在我的 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.


脚注

[1] Git 版本

$ git --version
git version 2.22.0

[2]具有发散namepath

设置测试存储库:

$ 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 = ./

移动子模块使namepath发散:

$ 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
于 2019-07-06T09:42:43.617 回答
1

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

find .git/modules/ -name config -exec grep url {} \;
于 2018-07-25T10:36:14.887 回答
0

这是从 .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-)
于 2019-07-06T14:17:04.783 回答
0

获取路径

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

在 repos 中获取名称

grep path .gitmodules | sed 's/.*= //'
于 2020-08-27T06:41:16.283 回答