列出Git存储库中的子模块

时间:2012-09-28 13:58:38

标签: git git-submodules

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

git submodule foreach命令可以回显子模块的名称,但只有在检出后才能使用,这在init步骤之后没有发生。链中有更多的步骤需要在签出之前发生,我不希望将子模块的名称硬连接到脚本中。

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

19 个答案:

答案 0 :(得分:126)

您可以使用与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 }'

你只能获得子模块路径。

答案 1 :(得分:73)

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

来自GIT SCM文档:

  

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

答案 2 :(得分:58)

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

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

将其视为不存在的git submodule --list

答案 3 :(得分:47)

以下命令将列出子模块:

<?php
$html = file_get_contents('test.html');
$dom = new DOMDocument;
@$dom->loadHTML($html);
//Some code needs to go here! 
$tags = $dom->getElementsByTagName('strong');
?>

输出是这样的:

git submodule--helper list

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

答案 4 :(得分:18)

我可以看到已经选择了答案,但对于到达此页面的任何其他人:

$ git submodule

将列出指定git仓库中的所有子模块。

干杯

答案 5 :(得分:16)

我用这个:

git config --list|egrep ^submodule

答案 6 :(得分:16)

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

No submodule mapping found in .gitmodule for a path that's not a submodule

git ls-files --stage | grep 160000

答案 7 :(得分:9)

您可以使用:

git submodule | awk '{ print $2 }'

答案 8 :(得分:9)

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

git submodule foreach --quiet 'echo $name'

答案 9 :(得分:8)

我用这个:

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

输出(路径+版本):

tools/deploy_utils (0.2.4)

答案 10 :(得分:7)

这对我有用:

git ls-files --stage | grep ^160000

基于这篇伟大的文章:http://www.speirs.org/blog/2009/5/11/understanding-git-submodules.html

编辑:必须阅读grep ^160000

答案 11 :(得分:7)

按名称列出所有子模块:

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

答案 12 :(得分:5)

  

子模块路径请,马上...

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

答案 13 :(得分:5)

git config允许指定配置文件 .gitmodules 配置文件。

所以,在&#34; use space as a delimiter with cut command&#34;:

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

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

由于Tino指出in the comments

  
      
  • 对于包含空格的子模块,此操作失败。
  •   
  • 子模块路径可能包含换行符,如

    git submodule add https://github.com/hilbix/bashy.git "sub module"
      git mv 'sub module' $'sub\nmodule'
    
  •   

作为一个更强大的替代方案,蒂诺建议:

git config -z --file .gitmodules --get-regexp '\.path$' | \
  sed -nz 's/^[^\n]*\n//p' | \
  tr '\0' '\n' 
     

对于包含换行符的路径(可以使用git mv创建),请不要使用| tr '\0' '\n'并使用类似... | while IFS='' read -d '' path; do ...的内容进行进一步处理bash。
  这需要一个理解read -d ''的现代bash(不要忘记-d and ''之间的空格。)

答案 14 :(得分:2)

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

#[derive(Eq, PartialEq, Debug)]
struct StructA {
    f: StructB
}

#[derive(Eq, PartialEq, Debug)]
struct StructB {
    g: i32
}

impl From<i32> for StructB {
    fn from(v: i32) -> Self {
        Self {
            g: v
        }
    }
}

impl<T> From<T> for StructA
where
    T: Into<StructB>
{
    fn from(t: T) -> StructA {
        let structb = t.into();
        StructA {
            f: structb
        }
    }
}

fn main() {
    let a1: StructA = StructB { g: 12 }.into();
    let a2: StructA = 12.into();
    assert_eq!(a1, a2);
}

或者只是 URL-s:

git submodule foreach -q git config -l

here窃取。

答案 15 :(得分:1)

在我的git [1] 版本中,每个git子模块都有一个name和一个path。它们不一定必须是相同的 [2] 。以可靠的方式获取这两者,而无需先检出子模块(git update --init),这是Shell向导中的棘手问题。

获取子模块names的列表

我找不到使用git config或任何其他git命令来实现此目标的方法。因此,我们回到.gitmodules上的正则表达式(非常难看)。但这似乎有点安全,因为git限制了子模块names允许的代码空间。另外,由于您可能希望将此列表用于进一步的Shell处理,因此下面的解决方案将NULL字节(\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-regexpawktr等来处理sed的输出,但是...将零字节传回git config --get。这是为了避免子模块paths中的换行符,空格和其他特殊字符(例如unicode)出现问题。另外,由于您可能希望将此列表用于进一步的Shell处理,因此下面的解决方案将NULL字节(\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

答案 16 :(得分:0)

如果没有.gitmodules,但.git / modules /

中存在子模块配置
interface Global {
    document: Document;
    window: Window;
    navigator: Navigator;
}

答案 17 :(得分: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-)

答案 18 :(得分:0)

获取路径

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

要像回购中那样获取名称

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