Elenca i sottomoduli in un repository Git


247

Ho un repository Git che contiene diversi sottomoduli. Come posso elencare i nomi di tutti i sottomoduli dopo l' git submodule initesecuzione?

Il git submodule foreachcomando potrebbe fare eco ai nomi del sottomodulo, ma funziona solo dopo che sono stati estratti, cosa che non è avvenuta dopo il passaggio di init. Ci sono altri passaggi nella catena che devono accadere prima che possano essere verificati e non voglio dover collegare i nomi dei sottomoduli allo script.

Quindi c'è un comando Git per ottenere i nomi di tutti i sottomoduli attualmente registrati, ma non ancora estratti?


5
Super sciocco che non lo fa, ma la risposta di Sandeep mostra che git submodulesi comporta come mi aspettavo che si comportasse un ipotetico git submodule list- non ho mai pensato di controllare cosa succede senza argomentazioni git submodule. (Sono contento di aver testato quel link, dato che inizialmente ho catturato il link 'Condividi' sbagliato!)
saggio

4
Sono venuto qui perché git submodule listnon esisteva e git submodule helpnon ha aiutato (secondo quest'ultima, la soluzione, git submodulenon è un utilizzo valido).
user2394284

La maggior parte delle risposte (inclusa quella accettata) elenca il sottomodulo paths, non si namesinterrompe quando contengono caratteri speciali. Ho provato a dare una risposta sia per i nomi che per i percorsi che dovrebbero essere sicuri: stackoverflow.com/a/56912913/3215929
Ente

Risposte:


175

Potresti usare lo stesso meccanismo degli git submodule initusi stessi, vale a dire, guarda .gitmodules. Questo file enumera ogni percorso del sottomodulo e l'URL a cui fa riferimento.

Ad esempio, dalla radice del repository, cat .gitmodulesstamperà i contenuti sullo schermo (supponendo che tu li abbia cat).

Dato che i file .gitmodule hanno il formato di configurazione Git, puoi usare git config per analizzare quei file:

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

Ti mostrerebbe tutte le voci del sottomodulo e con

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

otterresti solo il percorso del sottomodulo stesso.


Ma non stampa nulla sulla console.
IgorGanapolsky,

2
@IgorGanapolsky - puoi stampare sulla console, se lo fai cat .gitmodulesnella radice del repository ...
sdaau

La awkparte ha esito negativo se si hanno spazi nel percorso del sottomodulo.
maggio

@Ikke Vorrei recuperare un elenco di sottomoduli tra cui nome, percorso e url. Ho provato il seguente comando Git, ma non restituisce nulla: git config --file = .gitmodules --get-regexp. *? Submodule (. *)] Path = (. *) Url = (. *) I provato git config --file = .gitmodules --get-regexp. *? (sottomodulo). *? (percorso). *? (url). Forse hai una soluzione. Grazie in anticipo.
Odrai,

8
ATTENZIONE: awkfallisce per sottomoduli con spazi! Il comando dovrebbe leggere git config -z --file .gitmodules --get-regexp '\.path$' | sed -nz 's/^[^\n]*\n//p' | tr '\0' '\n'(è necessario un moderno sedcon -z). Questo non riesce per i percorsi con Newline (possono essere creati con git mv). Se vuoi essere al sicuro da questi, lascia perdere | tr '\0' '\n'e usa qualcosa di simile ... | while IFS='' read -d '' path; do ...per un'ulteriore elaborazione con bash. Questo ha bisogno di un bash moderno che capisca read -d ''(non dimenticare lo spazio tra -de '').
Tino,

111

È possibile utilizzare git submodule statuso facoltativamente git submodule status --recursivese si desidera mostrare sottomoduli nidificati.

Dalla documentazione Git:

Mostra lo stato dei sottomoduli. Questo stamperà lo SHA-1 del commit attualmente estratto per ciascun sottomodulo, insieme al percorso del sottomodulo e all'output di git descrivono per lo SHA-1. A ogni SHA-1 verrà aggiunto il prefisso: se il sottomodulo non è inizializzato, + se il commit del sottomodulo attualmente estratto non corrisponde allo SHA-1 trovato nell'indice del repository contenente e U se il sottomodulo presenta conflitti di unione.


2
Basta eseguire git submodule update --init --recursiveper inizializzare tutto il sottomodulo.
Jon Koops,

2
@IgorGanapolsky ha appena letto il commento di Stefaan: questo tipo di comandi non funziona se i sottomoduli non sono ancora inizializzati . Nessun output = nessun sottomodulo (elenco vuoto).
Tim

6
Questo dovrebbe sicuramente essere contrassegnato come migliore risposta per l'utilizzo di un gitcomando semplice e basato su nativi senza alcun aiuto da parte di bash. E questa soluzione è elegante nel modo in cui funziona bene in qualsiasi punto della copia di lavoro (ma ovviamente i sottomoduli stessi, per i quali il risultato si applica direttamente a se stessi).
Tim

Come dice la risposta di Sandeep Gill , git submodulesenza argomenti è uguale a git submodule status, quindi puoi salvarti digitando 7 caratteri ;-)
Sam

@Sam Non sono più gli stessi poiché git submodule status --recursivefunzionano, ma git submodule --recursivenon lo fanno. Quei 7 personaggi ti comprano qualcosa. Tuttavia dipende dalle tue esigenze.
Kevin Rak

60

Per restituire solo i nomi dei sottomoduli registrati, è possibile utilizzare questo comando:

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

Pensalo come git submodule --listse non esistesse.


3
Invece, usa perl -ne '/^\s*path =\s*(.*)/ and push(@submods, $1); END { print(join("\n", sort(@submods)));}' "$(git rev-parse --show-toplevel)/.gitmodules"quale rispetto a questa risposta (1) funziona da qualsiasi sottodirectory (sebbene non all'interno di un sottomodulo); (2) ordina i sottomoduli per nome; e (3) ignora le righe commentate in .gitmodules.
Colin D Bennett,

6
Ed è memorabile l'avvio!
Dan,

1
Si noti che questo è un modo molto sciatto di farlo, come pathpotrebbe essere presente nel nome del sottomodulo ( git submodule add https://github.com/commercialhaskell/path.git). Ma probabilmente lo sapevi già prima. Se si desidera accedere .gitconfigda qualsiasi punto di un worktree o è necessario eseguirlo in un --barerepository, è possibile utilizzare qualcosa di simile git cat-file -p HEAD:.gitmodules | .... Se devi fare riferimento al file "messo in scena", puoi farlo git cat-file -p :.gitmodules | ..., tuttavia è necessario indexche sia presente un git .
Tino,

58

Il seguente comando elencherà i sottomoduli:

git submodule--helper list

L'output è qualcosa del genere:

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

Nota: richiede Git 2.7.0 o versioni successive.


1
Grande!. Dove è documentato questo comando. Funziona su Git per Windwos ma non riesce a trovare alcun documento su git-scm.com
DarVar

1
git ls-files --stage | grep ^160000(da Risposta stackoverflow.com/a/29325219 ) sembra produrre lo stesso risultato, quindi forse questo è un buon rimpiazzo se devi essere compatibile con gits più vecchi.
Tino,

Presta attenzione ai --trattini doppi insubmodule--helper
it3xl

26

Uso:

$ git submodule

Elencherà tutti i sottomoduli nel repository Git specificato.


3
Questa è effettivamente una risposta duplicata delle altre due risposte che menzionano git submodule [status](nota che statusè implicita se omessa, quindi questa è la stessa).
Colin D Bennett,

Non sempre funziona. fatal: no submodule mapping found in .gitmodules for path 'bla-bla/foo-bar'. Innanzitutto devi eliminare tutti i repository interni che non sono stati ancora sottoposti a sottomodulazione.
it3xl,

1
Migliore risposta (• ̀ ω • ́) ✧
Răzvan Flavius ​​Panda

Nota che se vuoi usare il --recursiveflag, devi aggiungere esplicitamente il statuscomando: git submodule status --recursivefunziona, ma git submodule --recursivenon lo fa.
Sam,

17

Io lo uso questo:

git config --list|egrep ^submodule

1
@IgorGanapolsky ha appena letto il commento di Stefaan: questo non funziona se i sottomoduli non sono ancora inizializzati . Nessun output = nessun sottomodulo (elenco vuoto).
Tim

Questo è esattamente ciò di cui avevo bisogno. Mostra le sottocartelle dei sottomoduli e gli URL dei loro telecomandi.
tholdoldier il

17

Ho notato che il comando fornito in una risposta a questa domanda mi ha dato le informazioni che stavo cercando:

Nessuna mappatura del sottomodulo trovata in .gitmodule per un percorso che non è un sottomodulo

git ls-files --stage | grep 160000

Questa risposta è bella e pulita, ci sono degli svantaggi rispetto alla risposta di mholm815 che analizza .gitmodules ?
Colin D Bennett,

A proposito, se vuoi solo i nomi dei sottomoduli, usagit ls-files --stage | grep 160000 | perl -ne 'chomp;split;print "$_[3]\n"'
Colin D Bennett il

Questo ha funzionato per me dal momento che non avevo niente .gimoduleso niente dentro .git/config. (Non sono sicuro di come sia successo, ho ottenuto il repository in questo stato. È stato un errore, quindi la soluzione è stata git rm.)
Wenzeslaus,

1
Funziona con repository nudi. A differenza della soluzione .gitmodules.
kupson,

1
Questa è la risposta migliore Solo una piccola novità: grep "^160000 "sarebbe leggermente più robusto.
Lassi,

12

Se non ti dispiace operare solo su sottomoduli inizializzati, puoi usare git submodule foreachper evitare l'analisi del testo.

git submodule foreach --quiet 'echo $name'

1
Questa risposta è unica in quanto funziona solo per i sottomoduli che sono stati inizializzati. A seconda di ciò di cui hai bisogno, questo potrebbe essere il comportamento desiderato (ma potrebbe anche essere inaspettato e indesiderato.)
Seth Johnson

9

Puoi usare:

git submodule | awk '{ print $2 }'

1
Ciò sembra produrre lo stesso output di stackoverflow.com/a/23490756/895245 ma è più breve.
Ciro Santilli 11 冠状 病 六四 事件 法轮功

Downvoted. Questo comando è pericoloso perché non riesce per un sottomodulo iE denominato test (master)(nome con uno spazio seguito da parentesi), che è un nome di sottomodulo valido . Inoltre, il comando non può essere risolto, perché git stampa moduleo module (branch). Ed è anche peggio, poiché questo comando non è porcellain, quindi l'output del comando potrebbe cambiare in futuro senza preavviso.
Tino,

7

Io uso questo:

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

Output (percorso + versione):

tools/deploy_utils (0.2.4)

Lo svantaggio che vedo di questa versione è che è lento. Sembra che stia facendo una sorta di controllo dello stato su ciascun sottomodulo, forse vicino a un secondo per sottomodulo sulla mia macchina, quindi su progetti con molti sottomoduli questa non è una buona soluzione, o se dovrebbe essere eseguita da uno script ecc.
Colin D Bennett il

7

Per elencare tutti i sottomoduli per nome:

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



5

Solo i percorsi del sottomodulo, per favore, signora ...

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

👍🏼


4
Sebbene questa sia probabilmente una risposta completamente valida per la domanda, qui ci sono alcuni avvertimenti: questo funziona solo per i sottomoduli che non contengono punti nel loro nome. Un punto è completamente valido nei nomi dei moduli. Non si limita alle .urlchiavi, quindi potrebbero apparire anche altre voci (di solito non ce ne sono, ma succede merda). Dovresti usare --localqui, perché non vuoi vedere --globale le --systemimpostazioni. E ultimo da notare, poiché potrebbe essere trascurato, funziona solo per i sottomoduli, che sono già presenti in .git/config(come dopo git submodule init, vedi domanda).
Tino,

5

git configconsente di specificare un file di configurazione.
Ed .gitmodules è un file di configurazione.

Quindi, con l'aiuto di " usa lo spazio come delimitatore con il comando cut ":

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

Verranno elencati solo i percorsi, uno per sottomodulo dichiarato.

Come sottolinea Tino nei commenti :

  • Questo non riesce per i sottomoduli con spazi all'interno.
  • i percorsi del sottomodulo possono contenere newline , come in

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

Come alternativa più solida, Tino propone:

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

Per i percorsi con nuove linee (possono essere creati con git mv), lascia da parte | tr '\0' '\n'e usa qualcosa di simile ... | while IFS='' read -d '' path; do ...per un'ulteriore elaborazione con bash.
Ciò ha bisogno di un bash moderno che capisca read -d ''(non dimenticare lo spazio tra -d and '').


hmmm ... "ci deve essere un modo migliore" sono i miei pensieri immediati
arcseldon

suppongo che potrei alias quel comando nel profilo bash ecc. grazie comunque.
arcseldon,

Questo non riesce per i sottomoduli con spazi all'interno. Inoltre, i percorsi possono contenere Newlines ( git submodule add https://github.com/hilbix/bashy.git "sub module"; git mv 'sub module' $'sub\nmodule'). Vedi il mio commento alla risposta accettata che è molto simile alla tua.
Tino,

@Tino Punti positivi. Ho incluso il tuo commento nella risposta per una maggiore visibilità.
VonC

3

Nella mia versione di Git [1] , ogni sottomodulo Git ha a namee a path. Non devono necessariamente essere gli stessi [2] . Ottenere entrambi in modo affidabile, senza prima verificare i sottomoduli ( git update --init), è un po 'complicato della procedura guidata della shell.

Ottieni un elenco di sottomodulo names

Non ho trovato un modo per ottenere questo usando git configo qualsiasi altro gitcomando. Quindi torniamo alla regex su .gitmodules(super brutta). Ma sembra essere un po 'sicuro poiché gitlimita il possibile spazio di codice consentito per il sottomodulo names. Inoltre, poiché probabilmente si desidera utilizzare questo elenco per un'ulteriore elaborazione della shell, la soluzione sotto voci separate con 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"

E nella tua sceneggiatura:

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

Nota : read -rd ''richiede bashe non funziona con sh.

Ottieni un elenco di sottomodulo paths

Nel mio approccio provo non per elaborare l'output git config --get-regexpcon awk, tr, sed, ... ma invece passare un byte zero separato ritorna git config --get. Questo per evitare problemi con newline, spazi e altri caratteri speciali (ad es. Unicode) nel sottomodulo paths. Inoltre, poiché probabilmente si desidera utilizzare questo elenco per un'ulteriore elaborazione della shell, la soluzione sotto voci separate con NULL-bytes ( \0).

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

Ad esempio, in uno script Bash potresti quindi:

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

Nota : read -rd ''richiede bashe non funziona con sh.


Le note

[1] Versione Git

$ git --version
git version 2.22.0

[2] Sottomodulo con divergenti nameepath

Imposta repository di prova:

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

Sposta sottomodulo per creare namee pathdivergere:

$ 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

analisi

Imposta repository di prova:

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

Ottieni l'elenco dei sottomoduli 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

Ottieni l'elenco dei sottomoduli 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

Se non è presente alcun .gitmodulesfile, ma esiste una configurazione di sottomoduli in .git/modules/:

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

0

Ecco un altro modo per analizzare i nomi dei sottomoduli Git da .gitmodules senza la necessità di impostazioni IFS sed o di fantasia. :-)

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

Inoltre, questa soluzione sembra gestire correttamente l'esempio di virgolette doppie con escape mentre la soluzione precedente produce un output con escape. Il che potrebbe non essere corretto in alcuni casi. ;-)
devC0de

"above" e "below" non funzionano realmente in un ordinamento basato sul voto.
Ente,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.