Список субмодулів у сховищі Git


247

У мене є сховище Git, в якому є кілька підмодулів. Як перерахувати назви всіх підмодулів післяgit submodule init запуску?

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

Так є команда Git, щоб отримати імена всіх зареєстрованих на даний момент, але ще не перевірених підмодулів?


4
Супер нерозумно, що це не так, але відповідь Сандіпа показує, що він git submoduleведе себе так, як я очікував, що гіпотетично git submodule listповодитись - я просто ніколи не думав перевіряти, що відбувається без аргументів git submodule. (Радий, що я перевірив це посилання, оскільки спочатку я схопив неправильне посилання "Поділитися")
мудрець

4
Я прийшов сюди, тому git submodule listщо не існував і git submodule helpне допомагав (на думку останнього, рішення, git submoduleнеправомірне використання).
користувач2394284

Більшість відповідей (включаючи прийняту) містить підмодуль paths, а не namesпереривається, коли вони містять спеціальні символи. Я намагався дати відповідь і на імена, і на шляхи, які повинні бути безпечними: stackoverflow.com/a/56912913/3215929
Ente

Відповіді:


175

Ви можете використовувати той самий механізм, що і git submodule initсам, а саме, дивіться.gitmodules . Ці файли перераховують кожен шлях субмодуля та URL, на який він посилається.

Наприклад, з кореня сховища cat .gitmodulesбуде надруковано вміст на екран (якщо припустити, що він є)cat ).

Оскільки файли .gitmodule мають формат конфігурації Git, ви можете використовувати конфігурацію git для розбору цих файлів:

git config --file .gitmodules --name-only --get-regexp path

Показав би всі записи в підмодулі та з

git config --file .gitmodules --get-regexp path | awk '{ print $2 }'

ви отримаєте лише сам шлях підмодуля.


Але він нічого не друкує на консолі.
ІгорГанапольський

2
@IgorGanapolsky - ви можете друкувати на консолі, якщо ви робите cat .gitmodulesв кореневому сховищі ...
sdaau

awkЧастина зазнає невдачі , якщо у вас є прогалини в дорозі подмодуль.
maikel

@Ikke Я хотів би отримати список підмодулів, включаючи ім'я, шлях та URL. Я спробував таку команду Git, але вона нічого не повертає: git config --file = .gitmodules --get-regexp. *? Submodule (. *)] Path = (. *) Url = (. *) I спробував також git config --file = .gitmodules --get-regexp. *? (підмодуль). *? (path). *? (url). Можливо, у вас є рішення. Спасибі заздалегідь.
Одрай

8
УВАГА: awkвиходить з ладу для субмодулів з пробілами! Команда повинна читати git config -z --file .gitmodules --get-regexp '\.path$' | sed -nz 's/^[^\n]*\n//p' | tr '\0' '\n'(вам потрібен сучасний sedз -z). Це не вдається для шляхів з новими рядками в них (їх можна створити за допомогою git mv). Якщо ви хочете бути в безпеці від них, залиште подалі | tr '\0' '\n'і використовуйте щось на зразок ... | while IFS='' read -d '' path; do ...для подальшої обробки bash. Для цього потрібен сучасний баш, який розуміє read -d ''(не забувайте пробіл між -dі '').
Тіно

110

Ви можете використовувати git submodule statusабо за бажаннямgit submodule status --recursive якщо ви хочете показати вкладені підмодулі.

З документації Git:

Показати стан підмодулів. Це надрукує SHA-1 поточної перевіреної комісії для кожного підмодуля, разом із підмодульним контуром та вихідним описом git для SHA-1. Кожен SHA-1 буде встановлений з префіксом - якщо підмодуль не ініціалізований, + якщо перевірена в даний час фіксація підмодуля не відповідає SHA-1, знайденому в індексі сховища, що містить, і U, якщо підмодуль має конфлікти злиття.


2
Просто запустіть, git submodule update --init --recursiveщоб ініціалізувати весь підмодуль.
Джон Купс

2
@IgorGanapolsky просто прочитав у коментарі Стефаана: такі команди не працюють, якщо підмодулі ще не ініціалізовані . Немає виводу = немає підмодуля (порожній список).
Тім

6
Це, безумовно, слід позначати як найкращу відповідь для використання простої та рідної gitкоманди без будь-якої допомоги bash. І це рішення елегантне тим, що воно добре працює в будь-якій точці робочої копії (але самі підмодулі, звичайно, для чого результат стосується безпосередньо їх самих).
Тім

Як йдеться у відповіді Сандіп Гілла , git submoduleбез аргументів це те саме git submodule status, що ви можете врятувати себе, набравши 7 символів ;-)
Сем

@Sam Вони не зовсім однакові, оскільки git submodule status --recursiveпрацюють, але git submodule --recursiveні. Ці 7 символів щось купують тобі. Однак це залежить від ваших потреб.
Кевін Рак

60

Щоб повернути лише імена зареєстрованих підмодулів, ви можете використовувати цю команду:

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

Подумайте про це як таке, git submodule --listщо не існує.


3
Натомість використання, perl -ne '/^\s*path =\s*(.*)/ and push(@submods, $1); END { print(join("\n", sort(@submods)));}' "$(git rev-parse --show-toplevel)/.gitmodules"яке порівняно з цією відповіддю (1) працює з будь-якого підкаталогу (хоча не всередині підмодуля); (2) сортує підмодулі за назвою; і (3) ігнорує коментовані рядки в .gitmodules.
Колін Д Беннетт

6
І це незабутнє завантаження!
Dan

1
Зауважте, що це дуже неохайний спосіб зробити це, як це pathможе бути присутнім у назві підмодуля ( git submodule add https://github.com/commercialhaskell/path.git). Але ви, мабуть, це вже знали раніше. Якщо ви хочете отримати доступ .gitconfigз будь-якого місця робочого дерева або вам потрібно запустити це в --bareсховищі, ви можете використовувати щось подібне git cat-file -p HEAD:.gitmodules | .... Якщо вам потрібно посилатися на "поетапний" файл, ви можете це зробити git cat-file -p :.gitmodules | ..., однак для цього потрібен git index.
Тіно

57

Наступна команда перелічить підмодулі:

git submodule--helper list

Вихід виглядає приблизно так:

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

Примітка. Для цього потрібен Git 2.7.0 або вище.


1
Чудово !. Де це задокументоване командування. Працює над Git для Windwos, але не може знайти жодного документа на git-scm.com
DarVar

1
git ls-files --stage | grep ^160000(від відповіді stackoverflow.com/a/29325219 ), здається, дає такий же результат, тому, можливо, це хороша заміна, якщо вам потрібно сумісність із старими гейтами.
Тіно

Зверніть увагу на --подвійні тире вsubmodule--helper
it3xl

25

Використання:

$ git submodule

Він перелічить усі підмодулі у вказаному репозиторії Git.


3
Це фактично повторювана відповідь двох інших відповідей, які згадуються git submodule [status](зауважте, що statusмається на увазі, якщо пропущено, тож це те саме).
Колін Д Беннетт

Це не завжди працює. fatal: no submodule mapping found in .gitmodules for path 'bla-bla/foo-bar'. Спочатку потрібно видалити всі внутрішні сховища, які ще не підмодельовані.
it3xl

1
Найкраща відповідь (• ̀ ω • ́) ✧
Разван Флавій Панда

Зауважте, що якщо ви хочете використовувати --recursiveпрапор, вам потрібно явно додати statusкоманду: git submodule status --recursiveпрацює, але git submodule --recursiveне.
Сем

17

Я використовую це:

git config --list|egrep ^submodule

1
@IgorGanapolsky щойно прочитав у коментарі Стефаана: Це не працює, якщо підмодулі ще не ініціалізовані . Немає виводу = немає підмодуля (порожній список).
Тім

Це конкретність, що мені було потрібно. Він показує підпапки субмодулів та URL-адреси їх віддалених.
thinsoldier

17

Я помітив, що команда, надана у відповіді на це запитання, дала мені інформацію, яку я шукав:

Не знайдено відображення підмодуля у .gitmodule для шляху, який не є підмодулем

git ls-files --stage | grep 160000

Ця відповідь є приємною та чистою, чи є недоліки порівняно з розбором відповідей mholm815 .gitmodules ?
Колін Д Беннетт

BTW, якщо ви просто хочете назвати підмодулі, використовуйтеgit ls-files --stage | grep 160000 | perl -ne 'chomp;split;print "$_[3]\n"'
Colin D Bennett

Це працювало на мене, оскільки я не мав нічого .gimodulesабо нічого в .git/config. (Я не впевнений, як це відбувається, я отримав сховище в такому стані. Це була якась помилка, тому рішення було git rm.)
wenzeslaus

1
Це працює з голими репостами. На відміну від .gitmodules розчину.
kupson

1
Це найкраща відповідь. Просто невелика нітка: grep "^160000 "була б трохи міцнішою.
Лассі

12

Якщо ви не заперечуєте проти роботи лише з ініціалізованими підмодулями, ви можете використовувати git submodule foreachдля уникнення розбору тексту.

git submodule foreach --quiet 'echo $name'

1
Ця відповідь унікальна тим, що працює лише для підмодулів, які були ініціалізовані. Залежно від того, що вам потрібно, це може бути бажана поведінка (але це може бути і несподіваним і небажаним.)
Сет Джонсон,

9

Ви можете використовувати:

git submodule | awk '{ print $2 }'

1
Це, здається, дає такий самий вихід, що і stackoverflow.com/a/23490756/895245, але коротший.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Захищений. Ця команда є небезпечною, оскільки вона не відповідає для імені підмодуля iE test (master)(ім'я з пробілом, за яким слідують дужки), що є дійсним іменем підмодуля . Команду також не можна виправити, оскільки git друкує moduleабо module (branch). І ще гірше, оскільки ця команда не є порцеляновою, тому вихід команди може змінитися в майбутньому без попереднього повідомлення.
Тіно

7

Я використовую цей:

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

Вихід (шлях + версія):

tools/deploy_utils (0.2.4)

Недоліком, який я бачу в цій версії, є те, що вона повільна. Здається, що я перевіряю статус на кожному підмодулі, можливо, близький до секунди на підмодуль на моїй машині, тому для проектів із багатьма підмодулями це не є гарним рішенням, або якщо його слід запускати зі сценарію тощо
Colin D Bennett

7

Щоб перелічити всі підмодулі за назвою:

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



5

Всього на подмодуль шляху , будь ласка, мем ...

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

👍🏼


4
Хоча це, ймовірно, цілком коректна відповідь на питання, ось деякі застереження: Це працює лише для підмодулів, які не містять крапок у своєму імені. Точка цілком дійсна в назвах модулів. Він не обмежується .urlклавішами, тому можуть з'являтися й інші записи (зазвичай таких немає, але лайно трапляється). Ви повинні використовувати --localтут, тому що ви не хочете бачити --globalта --systemналаштування. І останнє зауваження, оскільки це, можливо, не помічено, він працює лише для підмодулів, які вже є в .git/config(наприклад, після git submodule init, див. Питання).
Тіно

5

git configдозволяє вказати конфігураційний файл.
І .gitmodules є конфігураційний файл.

Отже, за допомогою " використовувати простір як роздільник з командою cut ":

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

Тут буде вказано лише шляхи, по одному на заявлений підмодуль.

Як Tino вказує в коментарях :

  • Це не вдається для субмодулів з пробілами .
  • Шлях субмодуля може містити нові рядки , як у

    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 ''(не забувайте пробіл між -d and '').


хммм ... "повинен бути кращий шлях" - це мої негайні думки
arcseldon

Гадаю, я міг би псевдонім цю команду в баш-профілі і т. д. спасибі все одно.
arcseldon

Це не вдається для субмодулів з пробілами. Також зауважте, що шляхи можуть містити Newlines ( git submodule add https://github.com/hilbix/bashy.git "sub module"; git mv 'sub module' $'sub\nmodule'). Дивіться мій коментар до прийнятої відповіді, яка дуже схожа на вашу.
Тіно

@Tino Гарні моменти. Я включив ваш коментар у відповідь для більшої наочності.
VonC

3

У моїй версії Git [1] кожен підмодуль Git має a nameі a path. Вони не обов'язково повинні бути однаковими [2] . Отримання обох надійним способом, не перевіряючи підмодулі спочатку ( 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. Це дозволяє уникнути проблем з новими рядками, пробілами та іншими спеціальними символами (наприклад, Unicode) в підмодулі 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

0

Якщо .gitmodulesфайлів немає, але конфігурація підмодулів існує в .git/modules/:

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

0

Ось ще один спосіб проаналізувати імена підмодуля 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-)

Плюс до цього рішення, здається, правильно керує прикладом подвійних лапок, тоді як вищевказане рішення дає результат, який уникнув. Що може бути неправильним у деяких випадках. ;-)
devC0de

"Вгорі" і "Внизу" насправді не працює в порядку сортування на основі голосування.
Енте
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.