Список подмодулей в репозитории Git

У меня есть Git-репозиторий, в котором есть несколько подмодулей. Как мне перечислить имена всех подмодулей после git submodule init?

Команда git submodule foreach может отображать имена подмодулей, но это работает только после того, как они извлечены, чего не произошло после шага инициализации. Есть еще несколько шагов в цепочке, которые необходимо выполнить, прежде чем их можно будет извлечь, и я не хочу привязывать имена субмодулей к сценарию.

Так есть ли команда Git, чтобы получить имена всех зарегистрированных в настоящее время, но еще не проверенных подмодулей?

Ответ 1

Вы можете использовать тот же механизм, что и в 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 }'

вы получите только сам путь субмодуля.

Ответ 2

Вы можете использовать git submodule status или необязательно git submodule status --recursive, если хотите показать вложенные подмодули.

В GIT документах SCM:

Показывать статус подмодулей. Это напечатает SHA-1 в настоящее время проверяется фиксация для каждого подмодуля, а также путь субмодуля и вывод GIT описывают SHA-1. каждый SHA-1 будет иметь префикс - если подмодуль не инициализирован, + если зафиксированный в настоящий момент подмодуль не соответствует SHA-1 найденный в индексе содержащего репозитория и U, если подмодуль имеет конфликты слияния.

Ответ 3

Чтобы вернуть только имена зарегистрированных подмодулей, вы можете использовать эту команду:

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

Думайте об этом как о git submodule --list который не существует.

Ответ 4

Следующая команда перечисляет подмодули:

git submodule--helper list

Результат выглядит примерно так:

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

Примечание. Требуется git 2.7.0 или выше.

Ответ 5

Я вижу, что ответ был выбран, но для всех, кто достигает этой страницы:

$ git submodule

отобразит все подмодули в указанном репо git.

Приветствия

Ответ 6

Я использую это:

git config --list|egrep ^submodule

Ответ 8

Вы можете использовать:

git submodule | awk '{ print $2 }'

Ответ 9

Если вы не против работы только с инициализированными подмодулями, вы можете использовать git submodule foreach, чтобы избежать разбора текста.

git submodule foreach --quiet 'echo $name'

Ответ 10

Я использую этот:

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

Выход (путь + версия):

tools/deploy_utils (0.2.4)

Ответ 12

Чтобы вывести список всех подмодулей по имени:

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

Ответ 13

Просто пути подмодулей, пожалуйста, ma'am...

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

👍🏼

Ответ 14

git config позволяет указать файл конфигурации.
И .gitmodules - это файл конфигурации.

Итак, с помощью " использовать пробел в качестве разделителя с командой cut ":

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'
    

В качестве более надежной альтернативы Тино предлагает:

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.
Для этого нужен современный bash, который понимает read -d '' (не забывайте пробел между -d and '').

Ответ 15

В моей версии git [1] каждый подмодуль git имеет name и path. Они не обязательно должны быть одинаковыми [2]. Получение обоих надежным способом без предварительной проверки субмодулей (git update --init) - сложная git update --init оболочки.

Получить список names субмодулей

Я не нашел способа добиться этого, используя git config или любую другую команду git. Поэтому мы вернулись к регулярному выражению на .gitmodules (супер уродливо). Но это кажется несколько безопасным, поскольку git ограничивает возможное пространство кода, разрешенное для names подмодулей. Кроме того, так как вы, вероятно, хотите использовать этот список для дальнейшей обработки оболочки, решение ниже разделяет записи с 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 с помощью awk, tr, sed ,... но вместо этого git config --get нулевой байт, разделенный обратно, в git config --get. Это сделано для того, чтобы избежать проблем с символами новой строки, пробелами и другими специальными символами (например, юникодом) в paths подмодулей. Кроме того, так как вы, вероятно, хотите использовать этот список для дальнейшей обработки оболочки, решение ниже разделяет записи с 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] Подмодуль с разными 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

Ответ 16

Если нет .gitmodules, но конфигурация подмодулей существует в .git/modules/

find .git/modules/ -name config -exec grep url {} \;

Ответ 17

Вот еще один способ разобрать имена подмодулей git из .gitmodules без необходимости использования 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-)