Listen Sie Submodule in einem Git-Repository auf

246

Ich habe ein Git-Repository, das mehrere Submodule enthält. Wie liste ich die Namen aller Submodule auf, nachdem git submodule initsie ausgeführt wurden?

Der git submodule foreachBefehl könnte die Namen des Submoduls wiedergeben, dies funktioniert jedoch nur, wenn sie ausgecheckt wurden, was nach dem Init-Schritt nicht geschehen ist. Es gibt weitere Schritte in der Kette, die ausgeführt werden müssen, bevor sie ausgecheckt werden können, und ich möchte nicht die Namen von Submodulen fest in das Skript einbinden müssen.

Gibt es also einen Git-Befehl, um die Namen aller aktuell registrierten, aber noch nicht ausgecheckten Submodule abzurufen?

tpg2114
quelle
4
Super dumm, dass es nicht so ist, aber Sandeeps Antwort zeigt, dass es git submodulesich so verhält, wie ich es von einer Hypothese erwartet hatte git submodule list- ich hätte einfach nie gedacht zu überprüfen, was ohne Argumente passiert git submodule. (Ich bin froh, dass ich diesen Link getestet habe, da ich anfangs den falschen 'Share'-Link gefunden habe!)
Salbei
4
Ich bin hierher gekommen, weil git submodule listes nicht existierte und git submodule helpnicht geholfen hat (laut letzterer ist die Lösung git submodulekeine gültige Verwendung).
user2394284
Die meisten Antworten (einschließlich der akzeptierten) listen das Submodul auf und brechen pathsnicht names, wenn sie Sonderzeichen enthalten. Ich habe versucht, eine Antwort für Namen und Pfade zu geben, die sicher sein sollten: stackoverflow.com/a/56912913/3215929
Ente

Antworten:

175

Sie könnten den gleichen Mechanismus verwenden wie git submodule initsich selbst, nämlich betrachten .gitmodules. Diese Datei listet jeden Submodulpfad und die URL auf, auf die er verweist.

Beispielsweise werden vom Stammverzeichnis des Repositorys cat .gitmodulesInhalte auf dem Bildschirm gedruckt (vorausgesetzt, Sie haben dies getan cat).

Da Gitmodule-Dateien das Git-Konfigurationsformat haben, können Sie diese Dateien mit git config analysieren:

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

Würde dir alle Submoduleinträge zeigen, und mit

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

Sie würden nur den Submodulpfad selbst erhalten.

Ikke
quelle
Es wird jedoch nichts auf der Konsole ausgedruckt.
IgorGanapolsky
2
@IgorGanapolsky - Sie können auf der Konsole drucken, wenn Sie cat .gitmodulesim Repository-Stamm tun ...
Sdaau
Der awkTeil schlägt fehl, wenn Sie Leerzeichen im Submodulpfad haben.
Maikel
@Ikke Ich möchte eine Liste von Submodulen abrufen, einschließlich Name, Pfad und URL. Ich habe den folgenden Git-Befehl ausprobiert, aber er gibt nichts zurück: git config --file = .gitmodules --get-regexp. *? Submodule (. *)] Path = (. *) Url = (. *) I. versuchte git config --file = .gitmodules --get-regexp. *? (Submodul). *? (Pfad). *? (URL) ebenfalls. Vielleicht haben Sie eine Lösung. Vielen Dank im Voraus.
Odrai
8
WARNUNG: awkFehler bei Submodulen mit Leerzeichen! Der Befehl sollte lauten git config -z --file .gitmodules --get-regexp '\.path$' | sed -nz 's/^[^\n]*\n//p' | tr '\0' '\n'(Sie benötigen eine moderne sedmit -z). Dies schlägt für Pfade mit Zeilenumbrüchen fehl (sie können mit erstellt werden git mv). Wenn Sie gegen diese sicher sein möchten, lassen Sie das weg | tr '\0' '\n'und verwenden Sie so etwas ... | while IFS='' read -d '' path; do ...für die weitere Verarbeitung mit bash. Dies erfordert eine moderne Bash, die versteht read -d ''(vergessen Sie nicht den Raum zwischen -dund '').
Tino
109

Sie können git submodule statusoder optional verwenden, git submodule status --recursivewenn Sie verschachtelte Submodule anzeigen möchten.

Aus der Git-Dokumentation:

Zeigt den Status der Submodule an. Dies druckt die SHA-1 des aktuell ausgecheckten Commits für jedes Submodul zusammen mit dem Submodulpfad und der Ausgabe von git, die für die SHA-1 beschrieben wird. Jedem SHA-1 wird ein Präfix vorangestellt - wenn das Submodul nicht initialisiert ist, + wenn das aktuell ausgecheckte Submodul-Commit nicht mit dem SHA-1 übereinstimmt, das im Index des enthaltenen Repositorys gefunden wurde, und U, wenn das Submodul Zusammenführungskonflikte aufweist.

Jon Koops
quelle
2
Führen Sie einfach aus git submodule update --init --recursive, um alle Submodule zu initialisieren.
Jon Koops
2
@IgorGanapolsky hat gerade bei Stefaans Kommentar gelesen: Diese Art von Befehlen funktioniert nicht, wenn die Submodule noch nicht initialisiert sind . Keine Ausgabe = kein Submodul (leere Liste).
Tim
6
Dies sollte auf jeden Fall als beste Antwort für die Verwendung eines einfachen und nativen gitBefehls ohne Hilfe von bash markiert werden . Und diese Lösung ist insofern elegant, als sie an jedem Punkt der Arbeitskopie gut funktioniert (aber natürlich die Submodule selbst, für die das Ergebnis direkt auf sich selbst zutrifft).
Tim
Wie die Antwort von Sandeep Gill sagt, ist es git submoduleohne Argumente dasselbe wie git submodule status, also können Sie sich sparen, 7 Zeichen einzugeben ;-)
Sam
@ Sam Sie sind nicht ganz gleich, da git submodule status --recursivefunktioniert, aber git submodule --recursivenicht. Diese 7 Charaktere kaufen dir etwas. Es hängt jedoch von Ihren Bedürfnissen ab.
Kevin Rak
60

Mit diesem Befehl können Sie nur die Namen der registrierten Submodule zurückgeben:

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

Betrachten Sie es als das, git submodule --listwas es nicht gibt.

mholm815
quelle
3
Verwenden Sie stattdessen, perl -ne '/^\s*path =\s*(.*)/ and push(@submods, $1); END { print(join("\n", sort(@submods)));}' "$(git rev-parse --show-toplevel)/.gitmodules"was im Vergleich zu dieser Antwort (1) in einem beliebigen Unterverzeichnis funktioniert (jedoch nicht in einem Submodul). (2) sortiert die Submodule nach Namen; und (3) ignoriert kommentierte Zeilen in Gitmodulen.
Colin D Bennett
6
Und es ist unvergesslich zu booten!
Dan
1
Beachten Sie, dass dies eine sehr schlampige Methode ist, wie pathsie im Submodulnamen ( git submodule add https://github.com/commercialhaskell/path.git) enthalten sein kann. Aber das wussten Sie wahrscheinlich schon vorher. Wenn Sie .gitconfigvon einer beliebigen Stelle in einem Arbeitsbaum aus zugreifen möchten oder diese in einem --bareRepository ausführen müssen , können Sie Folgendes verwenden git cat-file -p HEAD:.gitmodules | .... Wenn Sie auf die "bereitgestellte" Datei verweisen müssen, können Sie dies tun git cat-file -p :.gitmodules | ..., jedoch muss ein Git indexvorhanden sein.
Tino
56

Der folgende Befehl listet die Submodule auf:

git submodule--helper list

Die Ausgabe ist ungefähr so:

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

Hinweis: Es erfordert Git 2.7.0 oder höher.

BEIM
quelle
1
Toll!. Wo ist dieser Befehl dokumentiert? Funktioniert auf Git für Windwos, kann aber keine Dokumente auf git-scm.com finden
DarVar
1
git ls-files --stage | grep ^160000(von Answer stackoverflow.com/a/29325219 ) scheint das gleiche Ergebnis zu liefern. Vielleicht ist dies ein guter Ersatz, wenn Sie mit älteren Gits kompatibel sein müssen.
Tino
--submodule--helper
Achten Sie
25

Verwenden:

$ git submodule

Es werden alle Submodule im angegebenen Git-Repository aufgelistet.

Sandeep Gill
quelle
3
Dies ist effektiv eine doppelte Antwort der beiden anderen Antworten, die erwähnt werden git submodule [status](Hinweis, der statusimpliziert wird, wenn er weggelassen wird, also ist dies der gleiche).
Colin D Bennett
Funktioniert nicht immer. fatal: no submodule mapping found in .gitmodules for path 'bla-bla/foo-bar'. Zuerst müssen Sie alle inneren Repositorys löschen, die noch nicht submoduliert sind.
it3xl
1
Beste Antwort (• ̀ ω • ́) ✧
Răzvan Flavius ​​Panda
Beachten Sie, dass Sie --recursiveden statusBefehl explizit hinzufügen müssen , wenn Sie das Flag verwenden möchten : git submodule status --recursivefunktioniert, aber git submodule --recursivenicht.
Sam
17

Ich benutze das:

git config --list|egrep ^submodule
Robert Sjödahl
quelle
1
@IgorGanapolsky las gerade bei Stefaans Kommentar: Dies funktioniert nicht, wenn die Submodule noch nicht initialisiert sind . Keine Ausgabe = kein Submodul (leere Liste).
Tim
Das ist genau das, was ich brauchte. Es zeigt die Unterordner der Submodule und die URLs ihrer Fernbedienungen.
Thinsoldier
17

Ich bemerkte, dass der Befehl in einer Antwort auf diese Frage mir die Informationen gab, nach denen ich suchte:

In .gitmodule wurde keine Submodulzuordnung für einen Pfad gefunden, der kein Submodul ist

git ls-files --stage | grep 160000
Max Cantor
quelle
Diese Antwort ist schön und sauber. Gibt es Nachteile im Vergleich zur Analyse von .gitmodules durch mholm815 ?
Colin D Bennett
Übrigens, wenn Sie nur die Namen der Submodule wollen, verwenden Siegit ls-files --stage | grep 160000 | perl -ne 'chomp;split;print "$_[3]\n"'
Colin D Bennett
Das hat bei mir funktioniert, da ich nichts .gimodulesoder nichts drin hatte .git/config. (Ich bin nicht sicher, wie es passiert ist, ich habe das Repository in diesem Zustand. Es war ein Fehler, also war die Lösung git rm.)
Wenzeslaus
1
Es funktioniert mit nackten Repos. Im Gegensatz zu .gitmodules Lösung.
Kupson
1
Dies ist die beste Antwort. Nur eine kleine Kleinigkeit: grep "^160000 "wäre etwas robuster.
Lassi
12

Wenn es Ihnen nichts ausmacht, nur mit initialisierten Submodulen zu arbeiten, können Sie das git submodule foreachParsen von Text vermeiden.

git submodule foreach --quiet 'echo $name'
benesch
quelle
1
Diese Antwort ist insofern einzigartig, als sie nur für initialisierte Submodule funktioniert. Je nachdem, was Sie benötigen, kann dies ein gewünschtes Verhalten sein (es kann jedoch auch unerwartet und unerwünscht sein).
Seth Johnson
9

Sie können verwenden:

git submodule | awk '{ print $2 }'
Fabceolin
quelle
1
Dies scheint die gleiche Ausgabe wie stackoverflow.com/a/23490756/895245 zu erzeugen , ist jedoch kürzer.
Ciro Santilli 11 冠状 病 六四 事件 11
Abgestimmt. Dieser Befehl ist gefährlich, da er für ein Submodul iE mit dem Namen test (master)(Name mit einem Leerzeichen gefolgt von Klammern) fehlschlägt , bei dem es sich um einen gültigen Submodulnamen handelt . Der Befehl kann auch nicht behoben werden, da git entweder druckt moduleoder module (branch). Und es ist noch schlimmer, da dieser Befehl kein Porzellan ist und sich die Ausgabe des Befehls in Zukunft ohne vorherige Ankündigung ändern kann.
Tino
7

Ich benutze dieses:

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

Ausgabe (Pfad + Version):

tools/deploy_utils (0.2.4)
Skarab
quelle
Der Nachteil dieser Version ist, dass sie langsam ist. Es scheint eine Art Statusprüfung für jedes Submodul durchzuführen, möglicherweise fast eine Sekunde pro Submodul auf meinem Computer. Bei Projekten mit vielen Submodulen ist dies keine gute Lösung, oder wenn es über ein Skript usw. ausgeführt werden sollte.
Colin D Bennett
7

So listen Sie alle Submodule nach Namen auf:

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

bGorle
quelle
7

Das hat bei mir funktioniert:

git ls-files --stage | grep ^160000

Es basiert auf diesem großartigen Artikel: Git-Submodule verstehen

Es muss lesen grep ^160000.

LTK
quelle
1
git ls-files --stage | grep ^160000scheint die gleiche Ausgabe zu erzeugen wie git submodule--helper listvon answer stackoverflow.com/a/40877379
Tino
5

Nur die Submodulpfade bitte, Ma'am ...

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

👍🏼

Alex Gray
quelle
4
Während dies wahrscheinlich eine vollständig gültige Antwort auf die Frage ist, sind hier einige Einschränkungen: Dies funktioniert nur für Submodule, deren Namen keine Punkte enthalten. Ein Punkt ist in Modulnamen vollständig gültig. Es ist nicht auf .urlSchlüssel beschränkt, daher werden möglicherweise auch andere Einträge angezeigt (normalerweise gibt es keine, aber es passiert Scheiße). Sie sollten --localhier verwenden, da Sie --globalund --systemEinstellungen nicht sehen möchten . Und zuletzt, weil es übersehen werden könnte, funktioniert es nur für Submodule, die bereits in vorhanden sind .git/config(wie danach git submodule init, siehe Frage).
Tino
5

git configermöglicht die Angabe einer Konfigurationsdatei.
Und .gitmodules ist eine Konfigurationsdatei.

Also, mit Hilfe von " Leerzeichen als Trennzeichen mit Befehl cut verwenden ":

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

Dadurch werden nur die Pfade aufgelistet, einer pro deklariertem Submodul.

Wie Tino weist darauf hin , in den Kommentaren :

  • Dies schlägt für Submodule mit Leerzeichen fehl .
  • Submodulpfade können Zeilenumbrüche enthalten , wie in

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

Als robustere Alternative schlägt Tino vor:

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

Lassen Sie für Pfade mit Zeilenumbrüchen (mit denen sie erstellt werden können git mv) das weg | tr '\0' '\n'und verwenden Sie so etwas wie ... | while IFS='' read -d '' path; do ...für die weitere Verarbeitung mit bash.
Dies erfordert eine moderne Bash, die versteht read -d ''(vergessen Sie nicht den Raum dazwischen -d and '').

VonC
quelle
hmmm ... "es muss einen besseren Weg geben" sind meine unmittelbaren Gedanken
arcseldon
Ich denke, ich könnte diesen Befehl in Bash-Profil usw. alias. Trotzdem danke.
Arcseldon
Dies schlägt für Submodule mit Leerzeichen fehl. Beachten Sie auch, dass Pfade Newlines ( git submodule add https://github.com/hilbix/bashy.git "sub module"; git mv 'sub module' $'sub\nmodule') enthalten können . Siehe meinen Kommentar zu der akzeptierten Antwort, die Ihrer sehr ähnlich ist.
Tino
@Tino Gute Punkte. Ich habe Ihren Kommentar zur besseren Sichtbarkeit in die Antwort aufgenommen.
VonC
3

In meiner Version von Git [1] hat jedes Git-Submodul ein nameund ein path. Sie müssen nicht unbedingt gleich sein [2] . Beides auf zuverlässige Weise zu erhalten, ohne zuerst die Submodule zu überprüfen ( git update --init), ist eine schwierige Aufgabe der Shell-Zauberei.

Holen Sie sich eine Liste der Submodule names

Ich habe keinen Weg gefunden, dies mit git configeinem anderen gitBefehl zu erreichen. Deshalb sind wir wieder bei Regex .gitmodules(super hässlich). Es scheint jedoch etwas sicher zu sein, da gitder mögliche Codebereich für das Submodul begrenzt ist names. Da Sie diese Liste wahrscheinlich für die weitere Shell-Verarbeitung verwenden möchten, werden in der folgenden Lösung Einträge mit NULL-bytes ( \0) getrennt.

$ sed -nre \
  's/^\[submodule \"(.*)\"]$/\1\x0/p' \
  "$(git rev-parse --show-toplevel)/.gitmodules" \
| tr -d '\n' \
| xargs -0 -n1 printf "%b\0"

Und in Ihrem Skript:

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

Hinweis : read -rd ''erfordert bashund funktioniert nicht mit sh.

Holen Sie sich eine Liste der Submodule paths

In meinem Ansatz versuche ich nicht die Ausgabe von zu verarbeiten git config --get-regexpmit awk, tr, sed, ... , sondern gebe es einen Null - Byte wieder getrennt git config --get. Dies dient dazu, Probleme mit Zeilenumbrüchen, Leerzeichen und anderen Sonderzeichen (z. B. Unicode) im Submodul zu vermeiden paths. Da Sie diese Liste wahrscheinlich für die weitere Shell-Verarbeitung verwenden möchten, werden in der folgenden Lösung Einträge mit NULL-bytes ( \0) getrennt.

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

In einem Bash-Skript könnten Sie beispielsweise Folgendes tun:

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

Hinweis : read -rd ''erfordert bashund funktioniert nicht mit sh.


Fußnoten

[1] Git-Version

$ git --version
git version 2.22.0

[2] Submodul mit divergierenden nameundpath

Test-Repository einrichten:

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

Verschieben Sie das Submodul, um Folgendes zu erstellen nameund zu pathtrennen:

$ 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

Testen

Test-Repository einrichten:

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

Liste der Submodule abrufen 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

Liste der Submodule abrufen 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
quelle
0

Wenn keine .gitmodulesDatei vorhanden ist, aber eine Submodulkonfiguration vorhanden ist in .git/modules/:

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

Hier ist eine andere Möglichkeit, Git-Submodulnamen aus .gitmodules zu analysieren, ohne dass sed oder ausgefallene IFS-Einstellungen erforderlich sind. :-)

#!/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
quelle
Außerdem scheint diese Lösung das Beispiel für doppelte Anführungszeichen korrekt zu behandeln, während die obige Lösung eine maskierte Ausgabe erzeugt. Was in einigen Fällen möglicherweise nicht korrekt ist. ;-)
devC0de
"oben" und "unten" funktioniert in einer stimmungsbasierten Sortierreihenfolge nicht wirklich.
Ente