Listar submódulos em um repositório Git


246

Eu tenho um repositório Git que possui vários submódulos. Como listar os nomes de todos os submódulos após a git submodule initexecução?

O git submodule foreachcomando poderia ecoar os nomes do submódulo, mas isso só funciona depois que eles foram retirados, o que não aconteceu após a etapa init. Há mais etapas na cadeia que precisam acontecer antes que possam ser verificadas, e não quero ter que conectar os nomes dos submódulos ao script.

Existe um comando Git para obter os nomes de todos os submódulos registrados atualmente, mas ainda não verificados?


4
Super bobo que não, mas a resposta de Sandeep mostra que git submodulese comporta como eu esperava que um git submodule listcomportamento hipotético - eu nunca pensei em verificar o que acontece sem argumentos git submodule. (Ainda bem que testei esse link, desde que peguei o link errado 'Share' inicialmente!) #
— 196

4
Eu vim aqui porque git submodule listnão existia e git submodule helpnão ajudou (de acordo com o último, a solução, git submodulenão é um uso válido).
— user2394284

A maioria das respostas (incluindo a aceita) lista o submódulo paths, namese não é interrompido quando contêm caracteres especiais. Eu tentei dar uma resposta para nomes e caminhos que devem ser seguros: stackoverflow.com/a/56912913/3215929
— Ente

Respostas:


175

Você pode usar o mesmo mecanismo que o git submodule initpróprio usa, ou seja, observe .gitmodules. Esses arquivos enumeram cada caminho do sub-módulo e a URL a que se refere.

Por exemplo, a partir da raiz do repositório, cat .gitmodulesimprimirá o conteúdo na tela (supondo que você tenha cat).

Como os arquivos .gitmodule têm o formato de configuração Git, você pode usar o git config para analisar esses arquivos:

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

Mostraria todas as entradas do submódulo e com

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

você apenas obteria o próprio caminho do submódulo.


Mas não imprime nada no console.
— IgorGanapolsky

2
@IgorGanapolsky - você pode imprimir no console, se fizer cat .gitmodulesna raiz do repositório ...
— sdaau

A awkpeça falhará se você tiver espaços no caminho do submódulo.
— Maikel

@ Ikke Eu gostaria de recuperar uma lista de submódulos, incluindo nome, caminho e URL. Tentei o seguinte comando Git, mas ele não retorna nada: git config --file = .gitmodules --get-regexp. *? Submodule (. *)] Path = (. *) Url = (. *) I tentei git config --file = .gitmodules --get-regexp. *? (submódulo). *? (caminho). *? (url) também. Talvez você tenha uma solução. Agradeço antecipadamente.
— Odrai 17/11/19

8
AVISO: awkfalha para submódulos com espaços! O comando deve ler git config -z --file .gitmodules --get-regexp '\.path$' | sed -nz 's/^[^\n]*\n//p' | tr '\0' '\n'(você precisa de um moderno sedcom -z). Isso falha nos caminhos com Novas Linhas (eles podem ser criados com git mv). Se você quiser se proteger contra isso, deixe o | tr '\0' '\n'e use algo como ... | while IFS='' read -d '' path; do ...para processamento adicional com o bash. Isso precisa de uma festança moderna que entenda read -d ''(não esqueça o espaço entre -de '').
— Tino

109

Você pode usar git submodule statusou, opcionalmente, git submodule status --recursivese desejar mostrar submódulos aninhados.

Na documentação do Git:

Mostrar o status dos submódulos. Isso imprimirá o SHA-1 da confirmação atualmente registrada para cada submódulo, junto com o caminho do submódulo e a saída do git description para o SHA-1. Cada SHA-1 será prefixado com - se o submódulo não for inicializado, + se a confirmação do submódulo com check-out atualmente não corresponder ao SHA-1 encontrado no índice do repositório que contém e U se o submódulo tiver conflitos de mesclagem.


2
Basta executar git submodule update --init --recursivepara inicializar todo o submódulo.
— Jon Koops 11/02

2
@IgorGanapolsky acabou de ler no comentário de Stefaan: esse tipo de comando não funciona se os submódulos ainda não foram inicializados . Sem saída = sem sub-módulo (lista vazia).
— Tim

6
Definitivamente, isso deve ser marcado como a melhor resposta para o uso de um gitcomando simples e baseado em nativo sem qualquer ajuda do bash. E essa solução é elegante da maneira que funciona bem em qualquer ponto da cópia de trabalho (mas é claro que os próprios submódulos, para os quais o resultado se aplica diretamente a eles mesmos).
— Tim

Como a resposta de Sandeep Gill diz, git submodulesem argumentos é o mesmo que git submodule statusvocê pode salvar 7 digitando 7 caracteres ;-) #
— Sam

@ Sam Eles não são exatamente os mesmos desde que git submodule status --recursivefuncionam, mas git submodule --recursivenão. Esses 7 caracteres compram algo para você. Depende de suas necessidades embora.
— Kevin Rak

60

Para retornar apenas os nomes dos submódulos registrados, você pode usar este comando:

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

Pense nisso como o git submodule --listque não existe.


3
Em vez disso, o uso perl -ne '/^\s*path =\s*(.*)/ and push(@submods, $1); END { print(join("\n", sort(@submods)));}' "$(git rev-parse --show-toplevel)/.gitmodules"que, comparado a esta resposta (1), funciona a partir de qualquer subdiretório (embora não dentro de um submódulo); (2) classifica os submódulos por nome; e (3) ignora as linhas comentadas nos módulos .git.
— Colin D Bennett

6
E é memorável para inicializar!
— Dan

1
Observe que essa é uma maneira muito desleixada de fazê-lo, como pathpode estar presente no nome do submódulo ( git submodule add https://github.com/commercialhaskell/path.git). Mas você provavelmente já sabia disso antes. Se você deseja acessar .gitconfigde qualquer lugar em uma árvore de trabalho ou precisar executá-lo em um --barerepositório, pode usar algo como git cat-file -p HEAD:.gitmodules | .... Se você precisar consultar o arquivo "faseado", poderá fazê-lo git cat-file -p :.gitmodules | ..., no entanto, isso precisa de um git indexpara estar presente.
— Tino

56

O comando a seguir listará os submódulos:

git submodule--helper list

A saída é algo como isto:

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

Nota: Requer Git 2.7.0 ou superior.


1
Ótimo!. Onde esse comando está documentado. Funciona no Git for Windwos, mas não consegue encontrar documentos no git-scm.com
— DarVar

1
git ls-files --stage | grep ^160000(da resposta stackoverflow.com/a/29325219 ) parece produzir o mesmo resultado, portanto, talvez este seja um bom substituto se você precisar ser compatível com gits mais antigos.
— Tino

Preste atenção aos --traços de casal emsubmodule--helper
— it3xl

25

Usar:

$ git submodule

Ele listará todos os submódulos no repositório Git especificado.


3
Esta é efetivamente uma resposta duplicada das duas outras respostas mencionadas git submodule [status](observe que statusestá implícito se omitido, portanto é o mesmo).
— Colin D Bennett

Nem sempre funciona. fatal: no submodule mapping found in .gitmodules for path 'bla-bla/foo-bar'. Primeiro, você deve excluir todos os repositórios internos que ainda não estão submodulados.
— it3xl

1
Melhor resposta (̀ ω • ́) ✧
— Răzvan Flavius ​​Panda

Observe que, se você deseja usar o --recursivesinalizador, é necessário adicionar explicitamente o statuscomando: git submodule status --recursivefunciona, mas git submodule --recursivenão.
— Sam

17

Eu uso isso:

git config --list|egrep ^submodule

1
@IgorGanapolsky acabou de ler no comentário de Stefaan: Isso não funciona se os submódulos ainda não foram inicializados . Sem saída = sem sub-módulo (lista vazia).
— Tim

Isso é exatamente o que eu precisava. Ele mostra as subpastas dos submódulos e os URLs de seus controles remotos.
— Dez15

17

Percebi que o comando fornecido em resposta a esta pergunta me deu as informações que eu estava procurando:

Nenhum mapeamento de submódulo encontrado no .gitmodule para um caminho que não é um submódulo

git ls-files --stage | grep 160000

Esta resposta é agradável e limpa. Existem desvantagens em comparação com a resposta do mholm815 que analisa .gitmodules ?
— Colin D Bennett

BTW, se você quiser apenas os nomes dos submódulos, usegit ls-files --stage | grep 160000 | perl -ne 'chomp;split;print "$_[3]\n"'
— Colin D Bennett

Isso funcionou para mim desde que eu não tinha nada .gimodulesou nada .git/config. (Eu não sei como isso acontecer, eu tenho o repositório neste estado Foi um engano, de modo solução foi. git rm.)
— Wenzeslaus

1
Está trabalhando com repositórios nus. Ao contrário da solução .gitmodules.
— Kupson

1
Esta é a melhor resposta. Apenas um pequeno detalhe: grep "^160000 "seria um pouco mais robusto.
— Lassi

12

Se você não se importa de operar apenas em submódulos inicializados, pode usar git submodule foreachpara evitar a análise de texto.

git submodule foreach --quiet 'echo $name'

1
Essa resposta é única, pois só funciona para submódulos que foram inicializados. Dependendo do que você precisa, esse pode ser o comportamento desejado (mas também pode ser inesperado e indesejado).
— Seth Johnson

9

Você pode usar:

git submodule | awk '{ print $2 }'

1
Isso parece produzir a mesma saída que stackoverflow.com/a/23490756/895245, mas é mais curto.
— Ciro Santilli # 11/16

Votado. Este comando é perigoso, porque falha no sub-módulo iE chamado test (master)(nome com um espaço seguido por parênteses), que é um nome válido para o sub-módulo . O comando também não pode ser corrigido, porque o git imprime moduleou module (branch). E é ainda pior, como esse comando não é de porcelana, portanto a saída do comando pode mudar no futuro sem aviso prévio.
— Tino

7

Eu uso este:

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

Saída (caminho + versão):

tools/deploy_utils (0.2.4)

A desvantagem que vejo desta versão é que ela é lenta. Parece estar fazendo algum tipo de verificação de status em cada submódulo, talvez perto de um segundo por submódulo na minha máquina; portanto, em projetos com muitos submódulos, essa não é uma boa solução, ou se deve ser executada a partir de um script etc.
— Colin D Bennett

7

Para listar todos os submódulos por nome:

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



5

Apenas os caminhos do submódulo, por favor, senhora ...

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

👍🏼


4
Embora essa seja provavelmente uma resposta completamente válida para a pergunta, aqui estão algumas ressalvas: Isso funciona apenas para submódulos que não contêm pontos em seu nome. Um ponto é completamente válido nos nomes dos módulos. Ele não se restringe às .urlchaves; portanto, outras entradas também podem aparecer (geralmente não existem, mas as coisas acontecem). Você deve usar --localaqui, porque não deseja ver --globale --systemconfigurações. E por último, porque pode ser esquecido, funciona apenas para submódulos, que já estão presentes .git/config(como depois git submodule init, veja a pergunta).
— Tino

5

git configpermite especificar um arquivo de configuração.
E .gitmodules é um arquivo de configuração.

Portanto, com a ajuda de " use o espaço como um delimitador com o comando cut ":

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

Isso listará apenas os caminhos, um por sub-módulo declarado.

Como Tino aponta nos comentários :

  • Isso falha para submódulos com espaços nele.
  • caminhos do submódulo podem conter novas linhas , como em

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

Como uma alternativa mais robusta, Tino propõe:

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

Para caminhos com novas linhas (eles podem ser criados com git mv), deixe o | tr '\0' '\n'e use algo como ... | while IFS='' read -d '' path; do ...para processamento adicional com o bash.
Isso precisa de uma festança moderna que entenda read -d ''(não esqueça o espaço entre elas -d and '').


hmmm ... "deve haver uma maneira melhor" são os meus pensamentos imediatos
— arcseldon

acho que eu poderia alias que comando no perfil bash etc. obrigado de qualquer maneira.
— Arcseldon 01/03/19

Isso falha nos submódulos com espaços nele. Observe também que os caminhos podem conter Novas Linhas ( git submodule add https://github.com/hilbix/bashy.git "sub module"; git mv 'sub module' $'sub\nmodule'). Veja meu comentário na resposta aceita, que é muito semelhante à sua.
— Tino

@Tino Bons pontos. Incluímos seu comentário na resposta para obter mais visibilidade.
— VonC

3

Na minha versão do Git [1] , todo submódulo do Git possui a namee a path. Eles não precisam necessariamente ser os mesmos [2] . Obter os dois de maneira confiável, sem verificar primeiro os submódulos ( git update --init), é um pouco complicado de assistente de shell.

Obter uma lista do submódulo names

Não encontrei uma maneira de conseguir isso usando git configou qualquer outro gitcomando. Portanto, estamos de volta à regex em .gitmodules(super feia). Mas parece ser um pouco seguro, pois gitlimita o possível espaço de código permitido para o submódulo names. Além disso, como você provavelmente deseja usar esta lista para processamento de shell adicional, a solução abaixo separa as entradas com 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 no seu script:

#!/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 ''requer bashe não funcionará sh.

Obter uma lista do submódulo paths

Na minha abordagem que eu tente não para processar a saída git config --get-regexpcom awk, tr, sed, ... mas em vez passá-lo a zero bytes separados de volta para git config --get. Isso é para evitar problemas com novas linhas, espaços e outros caracteres especiais (por exemplo, Unicode) no submódulo paths. Além disso, como você provavelmente deseja usar esta lista para processamento de shell adicional, a solução abaixo separa as entradas com NULL-bytes ( \0).

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

Por exemplo, em um script Bash, você pode:

#!/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 ''requer bashe não funcionará sh.


Notas de rodapé

[1] versão Git

$ git --version
git version 2.22.0

[2] Submódulo com divergentes nameepath

Configure o repositório de teste:

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

Mova o submódulo para criar namee pathdivergir:

$ 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

Teste

Configure o repositório de teste:

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

Obter lista de submódulo 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

Obter lista de submódulo 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 não houver nenhum .gitmodulesarquivo, mas existir uma configuração de submódulos em .git/modules/:

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

0

Aqui está outra maneira de analisar nomes de submodulos Git de .gitmodules sem a necessidade de configurações IFS sed ou sofisticadas. :-)

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

Além disso, esta solução parece manipular o exemplo de aspas duplas com escape corretamente, enquanto a solução acima produz uma saída com escape. O que pode não estar correto em alguns casos. ;-)
— devC0de

"acima" e "abaixo" realmente não funcionam em uma ordem de classificação baseada em votação.
— Ente
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.