Wyświetl podmoduły w repozytorium Git

247

Mam repozytorium Git, które zawiera kilka podmodułów. Jak wyświetlić nazwy wszystkich podmodułów po git submodule inituruchomieniu?

git submodule foreachKomenda mogła echo imiona modułem, ale to działa tylko jeżeli zostały one sprawdzone z których się nie stało po kroku Init. Jest więcej kroków w łańcuchu, które muszą się zdarzyć, zanim będą mogły zostać wyewidencjonowane, i nie chcę wprowadzać sztywnych nazw podmodułów do skryptu.

Czy istnieje więc polecenie Git, aby uzyskać nazwy wszystkich aktualnie zarejestrowanych, ale jeszcze nie sprawdzonych submodułów?

tpg2114
źródło
4
Super głupie, że tak nie jest, ale odpowiedź Sandeepa pokazuje, że git submodulezachowuje się tak, jak oczekiwałem hipotetycznego git submodule listzachowania - po prostu nigdy nie myślałem, aby sprawdzić, co się stanie bez argumentów git submodule. (Cieszę się, że przetestowałem ten link, ponieważ początkowo złapałem niewłaściwy link „Udostępnij”!)
mędrzec
4
Przybyłem tutaj, ponieważ git submodule listnie istniałem i git submodule helpnie pomogłem (według tego ostatniego rozwiązanie git submodulenie jest poprawne).
user2394284,
Większość odpowiedzi (w tym jedna zaakceptowana) zawiera podmoduł paths, namesa nie łamie się, gdy zawierają znaki specjalne. Próbowałem udzielić odpowiedzi zarówno na nazwy, jak i ścieżki, które powinny być bezpieczne: stackoverflow.com/a/56912913/3215929
Ente

Odpowiedzi:

175

Możesz użyć tego samego mechanizmu, co git submodule initsam w sobie, czyli popatrzeć .gitmodules. Te pliki wyliczają każdą ścieżkę podmodułu i adres URL, do którego się odnosi.

Na przykład z katalogu głównego repozytorium cat .gitmoduleswydrukuje zawartość na ekranie (zakładając, że masz cat).

Ponieważ pliki .gitmodule mają format konfiguracji Git, możesz użyć git config do parsowania tych plików:

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

Pokaże wszystkie wpisy submodułów i

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

dostaniesz tylko samą ścieżkę submodułu.

Ikke
źródło
Ale nie drukuje niczego na konsoli.
IgorGanapolsky
2
@IgorGanapolsky - możesz drukować na konsoli, jeśli robisz to cat .gitmodulesw katalogu głównym repozytorium ...
sdaau
awkCzęść nie, jeśli masz spacji w ścieżce submodule.
maikel
@Ikke Chciałbym pobrać listę submodułów, w tym nazwę, ścieżkę i adres URL. Próbowałem następującego polecenia Git, ale nic nie zwraca: git config --file = .gitmodules --get-regexp. *? Submodule (. *)] Path = (. *) Url = (. *) I próbowałem git config --plik = .gitmodules --get-regexp. *? (submodule). *? (ścieżka). *? (adres URL). Być może masz rozwiązanie. Z góry dziękuję.
Odrai,
8
UWAGA: awknie działa w przypadku submodułów ze spacjami! Polecenie powinno brzmieć git config -z --file .gitmodules --get-regexp '\.path$' | sed -nz 's/^[^\n]*\n//p' | tr '\0' '\n'(potrzebujesz nowoczesnego sedz -z). Nie udaje się to w przypadku ścieżek z nowymi liniami (można je tworzyć git mv). Jeśli chcesz się przed nimi zabezpieczyć, porzuć | tr '\0' '\n'i użyj czegoś takiego jak ... | while IFS='' read -d '' path; do ...do dalszego przetwarzania za pomocą bash. To wymaga nowoczesnej bash, która rozumie read -d ''(nie zapomnij o przestrzeni między -di '').
Tino
110

Możesz użyć git submodule statuslub opcjonalnie, git submodule status --recursivejeśli chcesz wyświetlić zagnieżdżone podmoduły.

Z dokumentacji Git:

Pokaż status submodułów. Spowoduje to wydrukowanie SHA-1 aktualnie wyrejestrowanego zatwierdzenia dla każdego podmodułu, wraz ze ścieżką do podmodułu i wyjściem git opisującym dla SHA-1. Każdy SHA-1 będzie miał przedrostek - jeśli podmoduł nie zostanie zainicjowany, + jeśli aktualnie sprawdzone zatwierdzenie podmodułu nie pasuje do SHA-1 znalezionego w indeksie zawierającego repozytorium i U, jeśli podmoduł ma konflikty scalania.

Jon Koops
źródło
2
Wystarczy uruchomić, git submodule update --init --recursiveaby zainicjować wszystkie submoduły.
Jon Koops
2
@IgorGanapolsky właśnie przeczytał komentarz Stefaana: tego rodzaju polecenia nie działają, jeśli submoduły nie zostały jeszcze zainicjowane . Brak danych wyjściowych = brak submodułu (pusta lista).
Tim
6
To zdecydowanie należy oznaczyć jako najlepszą odpowiedź na użycie prostej i natywnej gitkomendy bez żadnej pomocy bash. To rozwiązanie jest eleganckie, ponieważ działa dobrze w dowolnym punkcie kopii roboczej (ale oczywiście same podmoduły, których wynik dotyczy bezpośrednio ich samych).
Tim
Jak mówi odpowiedź Sandeepa Gilla , git submodulebez argumentów jest to samo, co git submodule status, więc możesz zaoszczędzić sobie wpisując 7 znaków ;-)
Sam
@Sam Nie są takie same, ponieważ git submodule status --recursivedziała, ale git submodule --recursivenie. Te 7 postaci coś ci kupuje. To zależy od twoich potrzeb.
Kevin Rak
60

Aby zwrócić tylko nazwy zarejestrowanych podmodułów, możesz użyć tego polecenia:

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

Pomyśl o tym, ponieważ git submodule --listto nie istnieje.

mholm815
źródło
3
Zamiast tego użyj, perl -ne '/^\s*path =\s*(.*)/ and push(@submods, $1); END { print(join("\n", sort(@submods)));}' "$(git rev-parse --show-toplevel)/.gitmodules"które w porównaniu z tą odpowiedzią (1) działa z dowolnego podkatalogu (choć nie w podmodule); (2) sortuje submoduły według nazwy; i (3) ignoruje komentowane wiersze w .gitmodules.
Colin D Bennett,
6
I niezapomniany jest rozruch!
Dan
1
Zauważ, że jest to bardzo niedbały sposób, jak to pathmoże być obecne w submodule name ( git submodule add https://github.com/commercialhaskell/path.git). Ale pewnie już o tym wiedziałeś. Jeśli chcesz uzyskać dostęp .gitconfigz dowolnego miejsca w drzewie roboczym lub chcesz uruchomić to w --barerepozytorium, możesz użyć czegoś takiego git cat-file -p HEAD:.gitmodules | .... Jeśli potrzebujesz odwołać się do pliku „etapowego”, możesz to zrobić git cat-file -p :.gitmodules | ..., jednak wymaga to indexobecności git .
Tino
57

Następujące polecenie wyświetli listę podmodułów:

git submodule--helper list

Wynik jest mniej więcej taki:

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

Uwaga: Wymaga Git 2.7.0 lub nowszej wersji.

W
źródło
1
Wspaniały!. Gdzie jest to polecenie udokumentowane. Działa na Git for Windwos, ale nie może znaleźć żadnych dokumentów na git-scm.com
DarVar
1
git ls-files --stage | grep ^160000(z odpowiedzi stackoverflow.com/a/29325219 ) wydaje się dawać ten sam wynik, więc być może jest to dobry zamiennik, jeśli chcesz być kompatybilny ze starszymi gitsami.
Tino
Zwróć uwagę na --podwójne myślniki wsubmodule--helper
it3xl
25

Posługiwać się:

$ git submodule

Wyświetli listę wszystkich podmodułów w określonym repozytorium Git.

Sandeep Gill
źródło
3
Jest to w rzeczywistości duplikat dwóch pozostałych odpowiedzi, które wspominają git submodule [status](uwaga statusjest sugerowana, jeśli zostanie pominięta, więc jest taka sama).
Colin D Bennett,
Nie zawsze działa fatal: no submodule mapping found in .gitmodules for path 'bla-bla/foo-bar'. Najpierw musisz usunąć wszystkie wewnętrzne repozytoria, które nie zostały jeszcze poddane podmodulowi.
it3xl
1
Najlepsza odpowiedź (• ̀ ω • ́) ✧
Răzvan Flavius ​​Panda
Pamiętaj, że jeśli chcesz użyć --recursiveflagi, musisz jawnie dodać statuspolecenie: git submodule status --recursivedziała, ale git submodule --recursivenie działa.
Sam
17

Używam tego:

git config --list|egrep ^submodule
Robert Sjödahl
źródło
1
@IgorGanapolsky właśnie przeczytał komentarz Stefaana: To nie działa, jeśli submoduły nie zostały jeszcze zainicjowane . Brak danych wyjściowych = brak submodułu (pusta lista).
Tim
Właśnie tego potrzebowałem. Pokazuje podfoldery submodułów i adresy URL ich pilotów.
thinsoldier
17

Zauważyłem, że polecenie podane w odpowiedzi na to pytanie dało mi informacje, których szukałem:

W .gitmodule nie znaleziono mapowania submodułów dla ścieżki, która nie jest submodułem

git ls-files --stage | grep 160000
Max Cantor
źródło
Ta odpowiedź jest ładna i czysta, czy są jakieś wady w porównaniu z analizowaniem odpowiedzi mholm815 .gitmodules ?
Colin D Bennett,
BTW, jeśli chcesz tylko nazwy submodułów, użyjgit ls-files --stage | grep 160000 | perl -ne 'chomp;split;print "$_[3]\n"'
Colin D Bennett
To działało dla mnie, ponieważ nie miałem .gimodulesnic .git/config. (Nie jestem pewien, jak to się stało, mam repozytorium w tym stanie. To był błąd, więc było rozwiązanie git rm).
wenzeslaus
1
Działa z nagimi transakcjami repo. W przeciwieństwie do rozwiązania .gitmodules.
kupson
1
To najlepsza odpowiedź. Tylko mała nitka: grep "^160000 "byłaby nieco bardziej wytrzymała.
Lassi
12

Jeśli nie masz nic przeciwko operowaniu tylko na zainicjowanych submodułach, możesz użyć, git submodule foreachaby uniknąć parsowania tekstu.

git submodule foreach --quiet 'echo $name'
Benesch
źródło
1
Ta odpowiedź jest wyjątkowa, ponieważ działa tylko w przypadku zainicjowanych podmodułów. W zależności od tego, czego potrzebujesz, może to być pożądane zachowanie (ale może być również nieoczekiwane i niepożądane).
Seth Johnson
9

Możesz użyć:

git submodule | awk '{ print $2 }'
fabceolin
źródło
1
Wydaje się, że generuje to samo wyjście, co stackoverflow.com/a/23490756/895245, ale jest krótszy.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功 法轮功
Doceniony. To polecenie jest niebezpieczne, ponieważ kończy się niepowodzeniem dla podmodułu o nazwie test (master)(nazwa ze spacją i nawiasami okrągłymi), co jest prawidłową nazwą podmodułu . Polecenia również nie można naprawić, ponieważ git albo drukuje, modulealbo module (branch). I jest jeszcze gorzej, ponieważ to polecenie nie jest porcelaną, więc wynik polecenia może ulec zmianie bez wcześniejszego powiadomienia.
Tino
7

Używam tego:

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

Dane wyjściowe (ścieżka + wersja):

tools/deploy_utils (0.2.4)
Skarab
źródło
Wadą tej wersji jest to, że jest powolna. Wygląda na to, że dokonuje pewnego rodzaju sprawdzania stanu w każdym podmodule, może blisko drugiego na podmoduł na moim komputerze, więc w projektach z wieloma podmodułami nie jest to dobre rozwiązanie, lub jeśli powinno być uruchamiane ze skryptu itp.
Colin D Bennett,
7

Aby wyświetlić wszystkie submoduły według nazwy:

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

bGorle
źródło
7

To działało dla mnie:

git ls-files --stage | grep ^160000

Opiera się na tym świetnym artykule: Zrozumienie Git Submodules

Musi przeczytać grep ^160000.

LTK
źródło
1
git ls-files --stage | grep ^160000wydaje się dawać takie same wyniki, jak git submodule--helper listz odpowiedzi stackoverflow.com/a/40877379
Tino
5

Proszę tylko o ścieżki submodułu , proszę pani ...

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

👍🏼

Alex Gray
źródło
4
Chociaż jest to prawdopodobnie poprawna odpowiedź na pytanie, oto kilka zastrzeżeń: Działa to tylko w przypadku podmodułów, które nie zawierają kropek w nazwie. Kropka jest całkowicie poprawna w nazwach modułów. Nie ogranicza się to do .urlkluczy, więc mogą pojawiać się również inne wpisy (zwykle nie ma żadnych, ale gówno się zdarza). Powinieneś użyć --localtutaj, ponieważ nie chcesz widzieć --globali --systemustawień. I na koniec należy pamiętać, ponieważ można go przeoczyć, działa tylko w przypadku podmodułów, które są już obecne w .git/config(jak po git submodule init, patrz pytanie).
Tino
5

git configpozwala określić plik konfiguracyjny.
I .gitmodules jest plikiem konfiguracyjnym.

Tak więc za pomocą „ użyj spacji jako separatora z poleceniem cięcia ”:

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

Spowoduje to wyświetlenie tylko ścieżek, po jednej na zadeklarowany podmoduł.

Jak zauważa Tino w komentarzach :

  • Nie udaje się to w przypadku podmodułów ze spacjami .
  • ścieżki podmodułów mogą zawierać nowe linie , jak w

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

Jako bardziej niezawodną alternatywę, Tino proponuje:

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

W przypadku ścieżek z nowymi liniami (można je tworzyć git mv), pozostaw | tr '\0' '\n'i użyj czegoś takiego jak ... | while IFS='' read -d '' path; do ...do dalszego przetwarzania za pomocą bash.
To wymaga nowoczesnej bash, która rozumie read -d ''(nie zapomnij o przestrzeni między -d and '').

VonC
źródło
hmmm ... „musi istnieć lepszy sposób”
oto
zgadnij, że i tak mógłbym uzyskać alias tego polecenia w profilu bash itp.
arcseldon
Nie udaje się to w przypadku podmodułów ze spacjami. Zauważ też, że ścieżki mogą zawierać Newlines ( git submodule add https://github.com/hilbix/bashy.git "sub module"; git mv 'sub module' $'sub\nmodule'). Zobacz mój komentarz do zaakceptowanej odpowiedzi, która jest bardzo podobna do twojej.
Tino
@Tino Dobre punkty. W odpowiedzi umieściłem twój komentarz dla większej widoczności.
VCC
3

W mojej wersji Git [1] każdy podmoduł Git ma a namei a path. Niekoniecznie muszą być takie same [2] . Uzyskanie obu w niezawodny sposób, bez uprzedniego sprawdzenia submodułów ( git update --init), jest trudnym czarodziejstwem powłoki.

Uzyskaj listę submodułów names

Nie mogę znaleźć sposób, jak to osiągnąć stosując git configlub innego gitpolecenia. Dlatego wróciliśmy do wyrażenia regularnego .gitmodules(super brzydkie). Ale wydaje się to nieco bezpieczne, ponieważ gitogranicza możliwą przestrzeń kodu dozwoloną dla podmodułu names. Ponadto, ponieważ prawdopodobnie chcesz użyć tej listy do dalszego przetwarzania powłoki, rozwiązanie poniżej oddzielne wpisy za pomocą 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"

I w twoim skrypcie:

#!/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"
)

Uwaga : read -rd ''wymaga bashi nie będzie działać sh.

Uzyskaj listę submodułów paths

W moim podejściu staram nie przetwarzać dane wyjściowe git config --get-regexpz awk, tr, sed, ... ale zamiast przechodzić to zerowy bajt oddzielone z powrotem git config --get. Ma to na celu uniknięcie problemów z znakami nowej linii, spacjami i innymi znakami specjalnymi (np. Unicode) w submodule paths. Ponadto, ponieważ prawdopodobnie chcesz użyć tej listy do dalszego przetwarzania powłoki, rozwiązanie poniżej oddzielne wpisy za pomocą NULL-bytes ( \0).

$ git config --null --file .gitmodules --name-only --get-regexp '\.path$' \
| xargs -0 -n1 git config --null --file .gitmodules --get

Na przykład w skrypcie Bash możesz:

#!/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
)

Uwaga : read -rd ''wymaga bashi nie będzie działać sh.


Przypisy

[1] Wersja Git

$ git --version
git version 2.22.0

[2] Submoduł z rozbieżnymi nameipath

Skonfiguruj repozytorium testowe:

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

Przesuń submoduł, aby utworzyć namei pathrozdzielić:

$ 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

Testowanie

Skonfiguruj repozytorium testowe:

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

Pobierz listę submodułów 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

Pobierz listę submodułów 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
Ente
źródło
0

Jeśli nie ma żadnego .gitmodulespliku, ale konfiguracja submodułów istnieje w .git/modules/:

find .git/modules/ -name config -exec grep url {} \;
MrSwed
źródło
0

Oto inny sposób na parsowanie nazw podmodułów Git z .gitmodules bez potrzeby ustawiania sed lub fantazyjnych ustawień 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
źródło
Ponadto wydaje się, że to rozwiązanie poprawnie obsługuje przykład podwójnego cudzysłowu, podczas gdy powyższe rozwiązanie generuje wyjście. Co może nie być poprawne w niektórych przypadkach. ;-)
devC0de
„powyżej” i „poniżej” tak naprawdę nie działa w kolejności sortowania opartej na głosowaniu.
Wejdź