Como removo um submódulo?

3539

Como faço para remover um submódulo Git?

A propósito, existe uma razão que eu não posso simplesmente fazer git submodule rm whatever?

R. Martinho Fernandes
fonte
109
A resposta simples stackoverflow.com/a/21211232/94687 agora é a correta e deve ser marcada com sim. Agora, é simplesmente git rm modulenameerm -rf .git/modules/modulename
imz - Ivan Zakharyaschev 15/06/2015
10
Na verdade, isso não é verdade. Essa resposta não aborda a remoção da entrada do submódulo .git/config. A resposta aceita mostra a maneira atualizada de remover completamente um submódulo. Também é explicado de forma mais sucinta nesta resposta: stackoverflow.com/a/36593218/1562138
fvgs:
Eu achei este artigo muito útil na remoção de submódulos. Ele inclui informações sobre como remover entradas nos .gitsubmodules e .git / config ligar
Ri_
12
Por favor, salve-se algum tempo e ir diretamente a resposta que as obras (em 2017): stackoverflow.com/a/36593218/528313
Vincenzo PII
Eu luto com problemas no submódulo há dois dias. A descoberta veio quando eu encontrei isso: forums.developer.apple.com/thread/13102 . Basicamente, o Xcode e talvez outros aplicativos lutam para expandir os URLs que contêm '~'. Depois de alterar o ssh: //[email protected]/~/git/MyRepo.git para ssh: //[email protected]/home/username/git/MyRepo.git (procure o caminho real no seu servidor), toda a estranheza desapareceu em dez minutos. Veja também stackoverflow.com/questions/32833100/…
Elise van Looij

Respostas:

2214

Desde o git1.8.3 (22 de abril de 2013) :

Não havia uma maneira de porcelana dizer "Não estou mais interessado neste submódulo", uma vez que você expressa seu interesse em um submódulo com " submodule init".
" submodule deinit" é a maneira de fazer isso.

O processo de exclusão também usa git rm(desde git1.8.5 de outubro de 2013).

Sumário

O processo de remoção em três etapas seria:

0. mv a/submodule a/submodule_tmp

1. git submodule deinit -f -- a/submodule    
2. rm -rf .git/modules/a/submodule
3. git rm -f a/submodule
# Note: a/submodule (no trailing slash)

# or, if you want to leave it in your working tree and have done step 0
3.   git rm --cached a/submodule
3bis mv a/submodule_tmp a/submodule

Explicação

rm -rf: Isso é mencionado em Daniel Schroeder 's resposta , e resumidos por Eonil nos comentários :

Isso deixa .git/modules/<path-to-submodule>/inalterado.
Portanto, se você excluir um submódulo com esse método e adicioná-los novamente novamente, isso não será possível porque o repositório já está corrompido.


git rm: Veja commit 95c16418 :

Atualmente, usar " git rm" em um submódulo remove a árvore de trabalho do submódulo da do superprojeto e o gitlink do índice.
Mas a seção do submódulo em .gitmodulesé deixada intocada, o que é uma sobra do submódulo agora removido e pode irritar os usuários (em oposição à configuração em .git/config, isso deve permanecer como um lembrete de que o usuário mostrou interesse nesse submódulo para que seja repovoado posteriormente quando um commit mais antigo é retirado).

Deixe git rmo usuário " " ajudar não apenas removendo o submódulo da árvore de trabalho, mas também " submodule.<submodule name>" removendo a seção do .gitmodulesarquivo e preparando ambos.


git submodule deinit: Decorre deste patch :

Com " git submodule init" o usuário pode dizer ao git que se preocupa com um ou mais submódulos e quer que ele seja preenchido na próxima chamada para " git submodule update".
Mas atualmente não há uma maneira fácil de dizer ao git que eles não se importam mais com um submódulo e querem se livrar da árvore de trabalho local (a menos que o usuário conheça muito sobre os componentes internos do submódulo e remova a submodule.$name.urlconfiguração " " de .git/configjunto com o trabalho árvore).

Ajude esses usuários fornecendo um deinitcomando ' '.
Isso remove a submodule.<name>seção inteira do .git/config(s) submodulo (s) fornecido (s) (ou de todos aqueles que foram inicializados se ' .' for fornecido).
Falha se a árvore de trabalho atual contiver modificações, a menos que seja forçado.
Reclame quando, para um submódulo fornecido na linha de comando, a configuração da URL não pode ser encontrada .git/config, mas mesmo assim não falha.

Isso cuida se as etapas de (des) inicialização ( .git/confige .git/modules/xxx)

Desde git1.8.5, o git rmleva também cuidar da:

  • ' add' etapa que registra o URL de um submódulo no .gitmodulesarquivo: é necessário removê-lo.
  • a entrada especial do sub-módulo (como ilustrado por esta pergunta ): o git rm remove-o do índice:
    git rm --cached path_to_submodule(sem barra)
    Isso remove o diretório armazenado no índice com um modo especial "160000", marcando-o como um diretório raiz do sub-módulo .

Se você esquecer essa última etapa e tentar adicionar o que era um submódulo como um diretório regular, você receberá uma mensagem de erro como:

git add mysubmodule/file.txt 
Path 'mysubmodule/file.txt' is in submodule 'mysubmodule'

Nota: desde o Git 2.17 (Q2 2018), o submódulo git deinit não é mais um script de shell.
É uma chamada para uma função C.

Consulte commit 2e61273 , commit 1342476 (14 de janeiro de 2018) por Prathamesh Chavan ( pratham-pc) .
(Incorporado por Junio ​​C Hamano - gitster- in commit ead8dbe , 13 de fevereiro de 2018)

git ${wt_prefix:+-C "$wt_prefix"} submodule--helper deinit \
  ${GIT_QUIET:+--quiet} \
  ${prefix:+--prefix "$prefix"} \
  ${force:+--force} \
  ${deinit_all:+--all} "$@"
VonC
fonte
18
Você pode dar um exemplo de uso submodule deinit?
Zakdances 28/04
5
@yourfriendzak aqui está um exemplo de alguém usando com êxito: stackoverflow.com/a/16161950/6309 . Mas lembre-se de que, ao contrário do que eu acreditava originalmente, o 1.8.3 ainda não foi lançado! No Unix, você pode compilá-lo a partir das fontes.
VonC 28/04
2
@HamishDowner a entrada especial deve desaparecer (o diretório não é mais um submódulo) e .gitmodulesdeve estar ok, mas eu ainda verificaria novamente qualquer coisa com o .gitdiretório (por exemplo, a configuração local , dentro do seu repositório local: isso não é modificado por a git pull)
VonC
2
@ Jayen sim, se você confirmar a remoção da .gitmodulesentrada e a remoção da entrada especial no índice e pressionar esse repositório, outras pessoas poderão acessá-lo e esse submódulo desaparecerá.
VonC 02/08/19
3
No git atual (v1.9 +), o simples e antigo git rm submodulefaz exatamente o que você deseja, como outras pessoas já disseram.
Pete Peterson
3445

Na página Tutorial do submódulo Git :

Para remover um submódulo, você precisa:

  1. Exclua a seção relevante do .gitmodulesarquivo.
  2. Encene as .gitmodulesalterações:
    git add .gitmodules
  3. Exclua a seção relevante de .git/config.
  4. Remova os arquivos do submódulo da árvore de trabalho e indexe:
    git rm --cached path_to_submodule(sem barra).
  5. Remova o .gitdiretório do submódulo :
    rm -rf .git/modules/path_to_submodule
  6. Confirme as alterações:
    git commit -m "Removed submodule <name>"
  7. Exclua os arquivos do submodulo agora não rastreados:
    rm -rf path_to_submodule

Consulte também : etapas alternativas abaixo .

John Douthat
fonte
410
"E, a propósito, há uma razão pela qual eu não posso simplesmente usar o submódulo rm?" ?
abernier
48
@abernier Uma resposta curta poderia ser "porque esse comando não existe". Meu palpite é que eles estão tentando tornar explícita a remoção dos arquivos do submódulo versus a configuração do submódulo para evitar a perda acidental de dados. Talvez uma pessoa pense que isso git submodule rmsimplesmente remove o registro do sub-módulo e ficaria surpreso se o comando também excluísse o repositório local. Quaisquer mudanças locais seriam irremediavelmente perdidas. E talvez outra pessoa pense que apenas os arquivos serão removidos.
precisa saber é o seguinte
119
Francamente, não sei por que. Espero que eles adicionem um comando, no entanto. Estes 4 passos são muito complicados.
precisa saber é o seguinte
25
Aqui está um script que remove um sub-módulo, basta criar um alias de git para submodule-rm;) gist.github.com/2491147
Capi Etheriel
33
também precisa de rm -rf .git \ modules \ submodule name?
Rogerdpack #
484

Apenas uma nota. Desde o git 1.8.5.2, dois comandos farão:

git rm the_submodule
rm -rf .git/modules/the_submodule

Como a resposta de @Mark Cheverton apontou corretamente, se a segunda linha não for usada, mesmo que você tenha removido o submódulo por enquanto, a pasta remanescente .git / modules / the_submodule impedirá que o mesmo submódulo seja adicionado ou substituído no futuro . Além disso, como o @VonC mencionado, git rmfará a maior parte do trabalho em um submódulo.

- Atualização (05/05/2017) -

Apenas para esclarecer, the_submoduleé o caminho relativo do submódulo dentro do projeto. Por exemplo, é subdir/my_submodulese o submódulo estiver dentro de um subdiretório subdir.

Conforme indicado corretamente nos comentários e outras respostas , os dois comandos (embora funcionais o suficiente para remover um submódulo) deixam um rastro na [submodule "the_submodule"]seção .git/config(a partir de julho de 2017), que pode ser removida usando um terceiro comando:

git config -f .git/config --remove-section submodule.the_submodule 2> /dev/null
tinlyx
fonte
5
Estou na versão 2.4.9 do git (Apple Git-60) e tudo que eu precisava fazer era rm the_submodule. Enviei isso novamente e depois adicionei uma pasta com o mesmo nome do submódulo e funcionou sem problemas.
David Silva Smith
19
Isso não remove a entrada do submódulo de .git/config. Consulte stackoverflow.com/a/36593218/1562138 para obter a maneira completa de remover um submódulo.
precisa saber é
2
@ drevicko Acabei de testar isso com o Git 2.11.1 e observo o mesmo comportamento de antes. git init && git submodule add <repository> && git rm <name>deixa para trás a .git/configentrada e o .git/modules/<name>diretório e seu conteúdo. Talvez você não tenha inicializado o submódulo antes de removê-lo?
Fevgs 22/02
2
eu me sinto mais seguro executar este primeiro .. git submódulo deinit -f the_submodule
danday74
1
@JarrodSmith Sim, é o caminho. por favor, veja a atualização.
tinlyx
478

A maioria das respostas a esta pergunta está desatualizada, incompleta ou desnecessariamente complexa.

Um submódulo clonado usando o git 1.7.8 ou mais recente deixará no máximo quatro traços de si no seu repositório local. O processo para remover esses quatro rastreamentos é dado pelos três comandos abaixo:

# Remove the submodule entry from .git/config
git submodule deinit -f path/to/submodule

# Remove the submodule directory from the superproject's .git/modules directory
rm -rf .git/modules/path/to/submodule

# Remove the entry in .gitmodules and remove the submodule directory located at path/to/submodule
git rm -f path/to/submodule
fvgs
fonte
39
Por que essa resposta tem tão poucos votos positivos? Todas essas respostas populares perdem alguma coisa, essa é a única que realmente remove todos os traços de um submódulo, da maneira mais simples possível. E note: a ordem dos comandos é importante.
Mdevpl # 7/16
2
Para responder a minha própria pergunta: stackoverflow.com/questions/97875/rm-rf-equivalent-for-windows
Thomas
5
O @mbdevpl veio três anos após a resposta aceita, e acho que ninguém conseguiu convencer o OP a aceitá-lo.
Andy
10
Esta é a resposta não complicada em 2018?
22718 Warren P
9
o .gitmodules arquivo ainda parece não afetado executando estes comandos
Fractalf
206

Passos simples

  1. Remova as entradas de configuração:
    git config -f .git/config --remove-section submodule.$submodulename
    git config -f .gitmodules --remove-section submodule.$submodulename
  2. Remova o diretório do índice:
    git rm --cached $submodulepath
  3. Confirmar
  4. Exclua arquivos não utilizados:
    rm -rf $submodulepath
    rm -rf .git/modules/$submodulename

Observe: $submodulepath não contém barras iniciais ou finais.

fundo

Quando você faz git submodule addisso, ele apenas o adiciona .gitmodules, mas depois que você o fez git submodule init, ele adiciona .git/config.

Portanto, se você deseja remover os módulos, mas conseguir restaurá-lo rapidamente, faça o seguinte:

git rm --cached $submodulepath
git config -f .git/config --remove-section submodule.$submodulepath

É uma boa ideia fazer git rebase HEADprimeiro e git commit no final, se você colocar isso em um script.

Também dê uma olhada em uma resposta para Posso despovoar um submódulo Git? .

errordeveloper
fonte
1
Eu tinha muitos submódulos (e uma bagunça maior), então tive que passar por um loop for. Como a maioria deles estava em um diretório específico e em ls, a saída continha barras finais. Eu fiz algo parecido for dir in directory/*; do git rm --cached $dir; done.
Pablo Olmos de Aguilera C.
Para obter esta lista, que pode ser usado em roteiro para exclusão recursiva - git config -f .git/config -l | cut -d'=' -f1 | grep "submodule.$MODPATH" | sed 's/^submodule\.//' | sed 's/\.url$//'- - parece que você tem que realmente fazer isso no caso, se há algo confuso, caso contrário apenasgit submodule | grep -v '^+' | cut -d' ' -f3
errordeveloper
2
para obter a lista de módulos, onde há alterações locais tinham sido feitas -git submodule | grep '^+' | cut -d' ' -f2
errordeveloper
nota, eu tive que incluir submodulenameentre aspas "submodulename".. referindo o .git/configarquivo
múon
Simples. Eficiente. Na versão 2.25.0, após a etapa 1, é necessário executar as alterações .gitmodules antes da etapa 2.
Michel Donais
83

Além das recomendações, eu também precisava rm -Rf .git/modules/path/to/submoduleadicionar um novo submódulo com o mesmo nome (no meu caso, eu estava substituindo um garfo pelo original)

Mark Cheverton
fonte
1
Eu estava tendo problemas com isso também. Se você tentar reinstalar um submódulo no mesmo caminho, as informações da filial serão armazenadas em cache no local mencionado, o que atrapalha as coisas.
Jangosteve #
Obrigado, eu também precisava disso. @Anton, eu concordo e editei a resposta mais votada para adicionar essas informações.
William Denniss
Eu usei a opção --name para fazer a substituição funcionar ... consulte stackoverflow.com/questions/14404704/…
joseph.hainline
60

Para remover um submódulo adicionado usando:

git submodule add [email protected]:repos/blah.git lib/blah

Corre:

git rm lib/blah

É isso aí.

Para versões antigas do git (aproximadamente ~ 1.8.5), use:

git submodule deinit lib/blah
git rm lib/blah
git config -f .gitmodules --remove-section submodule.lib/blah
Doug
fonte
1
+1 de fato. Esta é a única resposta correta do git 1.8.3 em diante. Deve ser aceito como o correto.
Xananax
6
git rmfolhas ainda encher em .git/modules/. (2.5.4)
Rudolf Adamkovič
1
@RudolfAdamkovic funciona para mim? Observe que ele remove apenas a entrada do submódulo se o caminho exato corresponder; se você moveu um submódulo e o usa git rm, não; Um teste rápido com o 2.5.4 no meu mac atualiza o arquivo .gitmodules, conforme descrito na documentação aqui: git-scm.com/docs/git-rm#_submodules ... mas se você encontrou algum tipo de combinação de plataforma / versão onde isso não acontece, você provavelmente deve apresentar um bug sobre isso.
Doug
2
Esta resposta não está totalmente correta. git rmdeixa coisas no .git/modules/diretório e no .git/configarquivo (ubuntu, git 2.7.4). Outra resposta funciona 100%: stackoverflow.com/a/36593218/4973698
mbdevpl
50

Você deve remover a entrada .gitmodulese .git/config, e remover o diretório do módulo do histórico:

git rm --cached path/to/submodule

Se você escrever na lista de discussão do git, provavelmente alguém fará um shell script para você.

Carmine Paolino
fonte
Não há necessidade de qualquer script shell, outra resposta tem comandos para remover todos os vestígios de um sub-módulo: stackoverflow.com/a/36593218/4973698
mbdevpl
42

Você pode usar um alias para automatizar as soluções fornecidas por outras pessoas:

[alias]
  rms = "!f(){ git rm --cached \"$1\";rm -r \"$1\";git config -f .gitmodules --remove-section \"submodule.$1\";git config -f .git/config --remove-section \"submodule.$1\";git add .gitmodules; }; f"

Coloque isso na sua configuração do git e você poderá: git rms path/to/submodule

Charles
fonte
-1, pois isso está errado demais. PRIMEIRO: Isso pressupõe que o nome e o caminho do submódulo sejam idênticos, o que geralmente não é o caso . IE git clone https://github.com/hilbix/empty.git; cd empty; git submodule add https://github.com/hilbix/empty.git one; git mv one two; git rms two. SEGUNDO: Você deve executar isso a partir do caminho correto. gitos aliases devem funcionar em qualquer lugar da árvore de trabalho (ou falhar normalmente). TERCEIRO: git config -f .git/configfalha nos submódulos, como .gitgeralmente há um arquivo lá.
Tino
42

Para resumir, é isso que você deve fazer:

  1. Defina path_to_submodulevar (sem barra):

    path_to_submodule=path/to/submodule

  2. Exclua a linha relevante do arquivo .gitmodules:

    git config -f .gitmodules --remove-section submodule.$path_to_submodule

  3. Exclua a seção relevante de .git / config

    git config -f .git/config --remove-section submodule.$path_to_submodule

  4. Desestágio e remova $ path_to_submodule apenas do índice (para evitar a perda de informações)

    git rm --cached $path_to_submodule

  5. Rastrear alterações feitas em .gitmodules

    git add .gitmodules

  6. Confirmar o superprojeto

    git commit -m "Remove submodule submodule_name"

  7. Exclua os arquivos do submodulo agora não rastreados

    rm -rf $path_to_submodule

    rm -rf .git/modules/$path_to_submodule

luissquall
fonte
para que todo mundo que puxe minha alteração tenha que executar rm -rf $ path_to_submodule rm -rf .git / modules / $ path_to_submodule para remover o cache do submodulo?
J2emanue
Eu recomendo atualizar git submodule update,. E se os caminhos dos submódulos não foram atualizados corretamente (o git lança um erro), remova-os:rm -rf .git/modules/<submodule> && rm -rf <submodule> && git submodule update
luissquall
40

Se o submódulo foi adicionado acidentalmente porque você adicionou, confirmou e enviou uma pasta que já era um repositório Git (contido .git), você não terá um .gitmodulesarquivo para editar ou qualquer outra coisa .git/config. Nesse caso, tudo que você precisa é:

git rm --cached subfolder
git add subfolder
git commit -m "Enter message here"
git push

FWIW , eu também removi a .gitpasta antes de fazer o git add.

Oli Studholme
fonte
exatamente o meu caso
zhekaus
37

Eu achei deinittrabalhos bons para mim:

git submodule deinit <submodule-name>    
git rm <submodule-name>

Dos documentos do git :

deinitar

Cancele o registro dos submódulos fornecidos, ou seja, remova a submodule.$name seção inteira do .git / config junto com sua árvore de trabalho.

Damjan Pavlica
fonte
Concordo encontrou a mesma solução. É a melhor maneira hoje em 2018)
woto
1
não removeu .git / modules / ... Você deve removê-los, veja a resposta por @fvgs
Vilém Kurz
Não sei por que este simples e fácil solução não é o número 1
Marc Magon
AFAICS esta parece ser a resposta mais segura para mais recentes gits que conhecemos deinit, como a outra resposta remove o .git/modules/submodulediretório muito cedo, o que parece fazer mais recente gits para falhar agora ou depois. Além disso (veja meu comentário aqui), a remoção .git/modules/submodulepode ser o caminho errado; portanto, essa é uma etapa perigosa, que deve ser tomada mais tarde apenas quando githouver reclamações (ou se você tiver 299% de certeza que é isso que deseja, é o caminho correto e realmente necessário).
Tino
Eu também precisava git commitconfirmar alterações em etapas no dir de trabalho: modified .gitmodulese deleted <submodule-path>.
Yuriy Pozniak
20

Depois de experimentar todas as respostas diferentes neste site, acabei com esta solução:

#!/bin/sh
path="$1"
if [ ! -f "$path/.git" ]; then
  echo "$path is no valid git submodule"
  exit 1
fi
git submodule deinit -f $path &&
git rm --cached $path &&
rm -rf .git/modules/$path &&
rm -rf $path &&
git reset HEAD .gitmodules &&
git config -f .gitmodules --remove-section submodule.$path

Isso restaura exatamente o mesmo estado de antes de você adicionar o submódulo. Você pode adicionar imediatamente o submódulo novamente, o que não foi possível com a maioria das respostas aqui.

git submodule add $giturl test
aboveScript test

Isso deixa você com uma verificação geral limpa, sem alterações a serem confirmadas.

Isso foi testado com:

$ git --version
git version 1.9.3 (Apple Git-50)
udondan
fonte
Por que você usa git rm --cached $pathentão em rm -rf $pathvez de git rm -r $path?
bfontaine
-1 Não funciona se você tentar remover um submódulo dentro de um submódulo (o submódulo pode formar árvores!). Além disso, isso é perigosamente danificado devido à falta de citações! Exemplo git submodule add https://github.com/hilbix/empty.git 'dangerous .. submodule'-> quando você tentar remover 'perigoso .. submodule' com seu script, esta vontade rm -rf ..que é mais provável não o que você quer ..
Tino
17

O que estou fazendo atualmente em dezembro de 2012 (combina a maioria dessas respostas):

oldPath="vendor/example"
git config -f .git/config --remove-section "submodule.${oldPath}"
git config -f .gitmodules --remove-section "submodule.${oldPath}"
git rm --cached "${oldPath}"
rm -rf "${oldPath}"              ## remove src (optional)
rm -rf ".git/modules/${oldPath}" ## cleanup gitdir (optional housekeeping)
git add .gitmodules
git commit -m "Removed ${oldPath}"
Lance Rushing
fonte
15

Aqui está o que eu fiz:

1.) Exclua a seção relevante do arquivo .gitmodules. Você pode usar o comando abaixo:

git config -f .gitmodules --remove-section "submodule.submodule_name"

2.) Encene as .gitmodulesmudanças

git add .gitmodules

3.) Exclua a seção relevante de .git/config. Você pode usar o comando abaixo:

git submodule deinit -f "submodule_name"

4.) Remova o gitlink (sem barra):

git rm --cached path_to_submodule

5.) Limpe o .git/modules:

rm -rf .git/modules/path_to_submodule

6.) Comprometa-se:

git commit -m "Removed submodule <name>"

7.) Exclua os arquivos do submodulo agora não rastreados

rm -rf path_to_submodule
Ishan Liyanage
fonte
Obrigado por isso. Para mim, tive que reorganizar a ordem dos três primeiros passos para 3), 1), 2). O fatal: no submodule mapping found in .gitmodules for path 'submodule_name'passo 1) deu o primeiro passo no passo 3. Ambos os passos foram necessários. (git v2.8.2)
U007D 25/08
13

Recentemente, descobri um projeto git que inclui muitos comandos úteis relacionados ao git: https://github.com/visionmedia/git-extras

Instale-o e digite:

git-delete-submodule submodule

Então as coisas são feitas. O diretório do submódulo será removido do seu repositório e ainda existe no seu sistema de arquivos. Você pode então confirmar a alteração como: git commit -am "Remove the submodule".

Chien-Wei Huang
fonte
Você pode chamar isso como git delete-submodule, conforme git-extrasnecessário, no caminho para o trabalho. Observe também que eu recomendo não usargit-extras , pois muitas partes dele são extremamente difíceis e perigosas . O IE git-delete-submodulepossivelmente remove o caminho errado abaixo .git/modules/*, pois assume que o módulo e o caminho são idênticos (o que geralmente não é o caso) e não funcionará corretamente se você tentar remover um submódulo dentro de um submódulo. git-extraspode ser 99% útil, mas não reclame se tudo der errado ao usá-lo. VOCÊ FOI AVISADO!
Tino
10

Eu tive que seguir os passos de John Douthat um passo adiante e cdentrar no diretório do submódulo e remover o repositório Git:

cd submodule
rm -fr .git

Então eu poderia confirmar os arquivos como parte do repositório Git pai sem a referência antiga a um submódulo.

Kyle Clegg
fonte
Eu também precisei fazer isso para passar por um erro "fatal: não é um repositório git:" ao tentar executar a git rm --cacheetapa.
RickDT
9

Aqui estão as 4 etapas que eu achei necessárias ou úteis (primeiro as importantes):

git rm -f the_submodule
rm -rf .git/modules/the_submodule
git config -f .git/config --remove-section submodule.the_submodule
git commit -m "..."

Em teoria , git rmna etapa 1 deve cuidar disso. Felizmente, a segunda parte da pergunta do OP pode ser respondida positivamente um dia (isso pode ser feito em um comando).

Mas a partir de julho de 2017, a etapa 2 é necessária para remover os dados; .git/modules/caso contrário, você não poderá, por exemplo, adicionar o submódulo no futuro.

Provavelmente, você pode se safar das duas etapas acima para o git 1.8.5+, como observou a resposta do tinlyx , pois todos os git submodulecomandos parecem funcionar.

A etapa 3 remove a seção the_submoduleno arquivo .git/config. Isso deve ser feito para ser completo. (A entrada pode causar problemas nas versões mais antigas do git, mas não tenho uma para testar).

Para isso, a maioria das respostas sugere o uso git submodule deinit. Acho mais explícito e menos confuso de usar git config -f .git/config --remove-section. De acordo com a documentação git-submódulo , git deinit:

Unregister os submódulos dadas ... Se você realmente deseja remover um sub-módulo do repositório e cometer esse uso git-rm [1] em vez .

Por último, mas não menos importante, se não o fizer git commit, você / poderá receber um erro ao fazê-lo git submodule summary(a partir do git 2.7):

fatal: Not a git repository: 'the_submodule/.git'
* the_submodule 73f0d1d...0000000:

Isso independentemente de você executar as etapas 2 ou 3.

laser
fonte
7
project dir:     ~/foo_project/
submodule:       ~/foo_project/lib/asubmodule
- - - - - - - - - - - - - - - - - - - - - - - - -
run:
  1.   cd ~/foo_project
  2.   git rm lib/asubmodule && 
          rm .git/modules/lib/asubmodule && 
            git submodule lib/asubmodule deinit --recursive --force

fonte
7

Acabei de encontrar o arquivo oculto .submodule (esqueci o nome exato), ele tem uma lista ... você pode apagá-los individualmente dessa maneira. Eu tinha apenas um, então o apaguei. Simples, mas pode atrapalhar o Git, já que não sei se há algo anexado ao submódulo. Parece ok até agora, além do problema de atualização usual da libetpan, mas isso (espero) não está relacionado.

Percebeu que ninguém postou apagamento manual, então adicionou

Stephen J
fonte
É.gitmodules
Arialdo Martini
7

Com o git 2.17 e acima, é apenas:

git submodule deinit -f {module_name}
git add {module_name}
git commit
Albert Tobac
fonte
Não funcionou, nem por git 2.17.1nem git 2.20.1. No entanto, usando em git rmvez de git addtrabalhar para ambos. Notas: -fnão é necessário se as coisas estiverem limpas. Certifique-se de não usar as opções com gitse você deseja proteger contra perda de dados não intencional. Observe também que isso deixa .git/modules/{module_name}no lugar. É uma boa prática mantê-lo lá, porque gitimprime a ajuda correta (!) Como proceder se algo estiver bloqueado devido a isso.
Tino
4

Se você acabou de adicionar o submódulo e, por exemplo, simplesmente adicionou o submódulo errado ou o local errado, git stashexclua a pasta. Isso pressupõe que a adição do submódulo seja a única coisa que você fez no repo recente.

botbot
fonte
3

Para o benefício do leitor, isso aqui tenta resumir e fornecer um guia passo a passo sobre como fazê-lo, se as coisas não funcionarem conforme o esperado. A seguir, é apresentada a maneira testada e segura da gitversão 2.17e da versão anterior para se livrar de um submódulo :

submodule="path/to/sub"              # no trailing slash!
git submodule deinit -- "$submodule"
git rm -- "$submodule"
  • Se isso não funcionar, veja abaixo.
  • Sem opções. Nada perigoso. E nem pense em fazer mais!
  • Testado com Debian Buster 2.20.1e Ubuntu 18.042.17.1 .
  • "$submodule" é apenas enfatizar onde colocar o nome e que você deve ter cuidado com espaços e coisas do gênero
  • Se no Windows, ignore a primeira linha e substitua "$submodule"pela maneira do Windows de um caminho especificado corretamente para o submódulo. (Eu não sou Windows)

Atenção!

Nunca toque você mesmo no interior do .gitdiretório! Edição interna.git entra no lado escuro. Fique longe a todo custo!

E sim, você pode culpar gitpor isso, pois muitas coisas úteis estavam faltandogit passado. Como uma maneira adequada de remover submódulos novamente.

Eu acho que há uma parte muito perigosa na documentação do git submodule. Ele recomenda se remover $GIT_DIR/modules/<name>/. No meu entendimento, isso não é apenas errado, é extremamente perigoso e provoca grandes dores de cabeça no futuro! Ver abaixo.

Observe que

git module deinit

é o inverso direto para

git module init

mas

git submodule deinit -- module
git rm -- module

também é bastante inverso a

git submodule add -- URL module
git submodule update --init --recursive -- module

porque alguns comandos basicamente precisam fazer mais do que apenas uma coisa:

  • git submodule deinit -- module
    • (1) atualizações .git/config
  • git rm
    • (2) remove os arquivos do módulo
    • (3) assim remove recursivamente os submódulos do submódulo
    • (4) atualizações .gitmodules
  • git submodule add
    • puxa os dados para .git/modules/NAME/
    • (1) faz git submodule init, então as atualizações.git/config
    • (2) faz git submodule update, portanto, check-out não-recursivo do módulo
    • (4) atualizações .gitmodules
  • git submodule update --init --recursive -- module
    • extrai mais dados, se necessário
    • (3) verifica os submódulos do submódulo recursivamente

Isso não pode ser totalmente simétrico, pois mantê-lo estritamente simétrico não faz muito sentido. Simplesmente não há necessidade de mais de dois comandos. Também "puxar os dados" está implícito, porque você precisa, mas a remoção das informações em cache não é feita, porque isso não é necessário e pode limpar dados preciosos.

Isso realmente é intrigante para os recém-chegados, mas basicamente é uma coisa boa: gitsimplesmente faz a coisa óbvia e faz o que é certo, e nem sequer tenta fazer mais. gité uma ferramenta que deve fazer um trabalho confiável, em vez de ser apenas mais um "Eierlegende Wollmilchsau" ("Eierlegende Wollmilchsau" significa para mim "uma versão maligna de um canivete suíço").

Então eu entendo as reclamações das pessoas, dizendo "Por que não faz gito óbvio por mim". Isso ocorre porque "óbvio" aqui depende do ponto de vista. Confiabilidade em cada situação é muito mais importante. Portanto, o que é óbvio para você muitas vezes não é a coisa certa em todas as situações técnicas possíveis. Lembre-se de que: AFAICSgit segue o caminho técnico, não o social. (Daí o nome inteligente: git)

Se isso falhar

Os comandos acima podem falhar devido ao seguinte:

  • Você gité muito velho. Então use um novogit . (Veja abaixo como.)
  • Você possui dados não confirmados e pode perder dados. Então é melhor cometer primeiro.
  • Seu submódulo não está limpo em um git clean sentido. Em seguida, limpe seu submódulo usando esse comando. (Ver abaixo.)
  • Você fez algo no passado que não é suportado por git. Então você está no lado escuro e as coisas ficam feias e complicadas. (Talvez o uso de outra máquina conserte.)
  • Talvez haja mais maneiras de falhar que eu não conheço (sou apenas um gitusuário avançado).

Possíveis correções a seguir.

Use um mais novo git

Se a sua máquina for muito antiga, não há submodule deinitna sua git. Se você não deseja (ou pode) atualizar o seu git, basta usar outra máquina com uma nova git! gitdeve ser totalmente distribuído, para que você possa usar outro gitpara realizar o trabalho:

  • workhorse:~/path/to/worktree$ git status --porcelain não deve produzir nada! Se isso acontecer, limpe as coisas primeiro!
  • workhorse:~/path/to/worktree$ ssh account@othermachine
  • othermachine:~$ git clone --recursive me@workhorse path/to/worktree/.git TMPWORK && cd TMPWORK
  • Agora faça o material do submódulo
  • othermachine:~/TMPWORK$ git commit . -m . && exit
  • workhorse:~/path/to/worktree$ git fetch account@othermachine:TMPWORK/.git
  • workhorse:~/path/to/worktree$ git merge --ff-only FETCH_HEAD. Se isso não funcionar, usegit reset --soft FETCH_HEAD
  • Agora limpe as coisas, até que git statusesteja limpo novamente. Você pode fazer isso porque já o limpou antes, graças ao primeiro passo.

Esta othermachinepode ser uma VM, ou algum Ubuntu WSL no Windows, qualquer que seja. Mesmo um chroot(mas suponho que você não seja root, porque se for root, deve ser mais fácil atualizar para o mais novo git).

Observe que, se você não pode sshentrar, existem várias maneiras de transportar gitrepositórios. Você pode copiar sua árvore de trabalho em um pen drive (incluindo o .gitdiretório) e cloná-lo. Clone a cópia, apenas para obter as coisas de uma maneira limpa novamente. Pode ser uma PITA, caso seus submódulos não sejam acessíveis diretamente de outra máquina. Mas há uma solução para isso também:

git config --add url.NEWURLPREFIX.insteadOf ORIGINALURLPREFIX

Você pode usar isso multiplicar, e isso é salvo em $HOME/.gitconfig. Algo como

git config --add 'url./mnt/usb/repo/.insteadof' https://github.com/

reescreve URLs como

https://github.com/XXX/YYY.git

para dentro

/mnt/usb/repo/XXX/YYY.git

É fácil se você se acostumar a gitrecursos poderosos como esse.

Limpar as coisas primeiro

A limpeza manual é boa, pois dessa forma você talvez detecte algumas coisas que esqueceu.

  • Se o git se queixar de coisas não salvas, faça o commit e leve-o para um local seguro.
  • Se o git reclama de algumas sobras, git statuse git clean -ixfdé seu amigo
  • Tente se abster de opções para rme deinitcontanto que você puder. Opções (como -f) para gitsão boas se você é um profissional. Mas como você veio aqui, provavelmente não tem tanta experiência na submoduleárea. Então é melhor prevenir do que remediar.

Exemplo:

$ git status --porcelain
 M two
$ git submodule deinit two
error: the following file has local modifications:
    two
(use --cached to keep the file, or -f to force removal)
fatal: Submodule work tree 'two' contains local modifications; use '-f' to discard them
$ cd two
$ git submodule deinit --all
error: the following file has local modifications:
    md5chk
(use --cached to keep the file, or -f to force removal)
fatal: Submodule work tree 'md5chk' contains local modifications; use '-f' to discard them
$ cd md5chk
$ git submodule deinit --all
error: the following file has local modifications:
    tino
(use --cached to keep the file, or -f to force removal)
fatal: Submodule work tree 'tino' contains local modifications; use '-f' to discard them
$ cd tino
$ git status --porcelain
?? NEW
$ git clean -i -f -d
Would remove the following item:
  NEW
*** Commands ***
    1: clean                2: filter by pattern    3: select by numbers    4: ask each
    5: quit                 6: help
What now> 1
Removing NEW
$ cd ../../..
$ git status --porcelain
$ git submodule deinit two
Cleared directory 'two'
Submodule 'someunusedname' (https://github.com/hilbix/src.git) unregistered for path 'two'

Você vê, não há -fnecessidade submodule deinit. Se as coisas estão limpas, em certo git cleansentido. Observe também que git clean -xnão é necessário. Isso significa que git submodule deinitremove incondicionalmente arquivos não rastreados que são ignorados. Geralmente é isso que você deseja, mas não se esqueça disso. Às vezes, arquivos ignorados podem ser preciosos, como dados em cache, que levam horas ou dias para serem calculados novamente.

Por que nunca remover $GIT_DIR/modules/<name>/?

Provavelmente, as pessoas desejam remover o repositório em cache, porque têm medo de encontrar um problema posteriormente. Isso é verdade, mas encontrar esse "problema" é a maneira correta de resolvê-lo! Como a correção é fácil e bem feita, você será capaz de viver feliz para sempre. Isso evita problemas mais pesados ​​do que quando você remove os dados por conta própria.

Exemplo:

mkdir tmptest &&
cd tmptest &&
git init &&
git submodule add https://github.com/hilbix/empty.git two &&
git commit -m . &&
git submodule deinit two &&
git rm two &&
git commit -m . &&
git submodule add https://github.com/hilbix/src.git two

A última linha gera o seguinte erro:

A git directory for 'two' is found locally with remote(s):
  origin    https://github.com/hilbix/empty.git
If you want to reuse this local git directory instead of cloning again from
  https://github.com/hilbix/src.git
use the '--force' option. If the local git directory is not the correct repo
or you are unsure what this means choose another name with the '--name' option.

Por que esse erro? Como .git/modules/two/anteriormente foi preenchido em https://github.com/hilbix/empty.git e agora deve ser preenchido novamente de outra coisa, ou seja, https://github.com/hilbix/src.git . Você não verá isso se o preencher novamente em https://github.com/hilbix/empty.git

O que fazer agora? Bem, faça exatamente o que foi dito! Usar--name someunusedname

git submodule add --name someunusedname https://github.com/hilbix/src.git two

.gitmodules então parece

[submodule "someunusedname"]
    path = two
    url = https://github.com/hilbix/src.git

ls -1p .git/modules/

someunusedname/
two/

Dessa forma, no futuro, você pode alternar entre ramificações / confirmação e avançar e nunca mais voltará a ter problemas , devido à two/existência de dois repositórios upstream diferentes (e possivelmente incompatíveis). E o melhor é: você também mantém os dois em cache localmente.

  • Isso não é verdade apenas para você. Isso também é válido para todos os outros usuários do seu repositório.
  • E você não perde a história. Caso você se esqueça de enviar a versão mais recente do submódulo antigo, poderá inserir a cópia local e fazê-lo posteriormente. Observe que é bastante comum que alguém esqueça de empurrar alguns submódulos (porque esse é um PITA para os recém-chegados, até que eles se acostumaram git).

No entanto, se você removeu o diretório em cache, os dois caixas diferentes tropeçarão um no outro, porque você não usará as --nameopções, certo? Portanto, toda vez que você faz o checkout, talvez seja necessário remover o .git/modules/<module>/diretório várias vezes. Isso é extremamente complicado e dificulta o uso de algo parecido git bisect.

Portanto, há um motivo muito técnico para manter esse diretório de módulo como um espaço reservado. As pessoas que recomendam remover algo abaixo .git/modules/não sabem melhor ou esquecem de informar que isso cria recursos poderosos, comogit bisect quase impossíveis o uso de se isso ultrapassar uma incompatibilidade desse sub-módulo.

Uma outra razão é mostrada acima. Olhe para o ls. O que você vê lá?

Bem, a segunda variante do módulo two/não está abaixo .git/modules/two/, está abaixo .git/modules/someunusedname/! Então, coisas como git rm $module; rm -f .git/module/$moduleestão totalmente erradas! Você deve consultar module/.gitou .gitmodulesencontrar a coisa certa a remover!

Portanto, não apenas a maioria das outras respostas cai nessa perigosa armadilha, mas mesmo as gitextensões muito populares tinham esse bug ( agora está corrigido aqui )! Portanto, é melhor manter as mãos no .git/diretório, se você não fizer exatamente o que está fazendo!

E do ponto de vista filosófico, limpar a história está sempre errado! Exceto pela mecânica quântica , como sempre, mas isso é algo completamente diferente.

Para sua informação, você provavelmente adivinhou: hilbix é minha conta do GitHub.

Tino
fonte
Esta enciclopédia de um post deve ser dividida em seções mais claras com subtítulos maiores / mais claros para indicar a resposta real e as diferentes seções "solução de problemas" / etc.
Andrew
2

Para resumir, é isso que você deve fazer:

Defina path_to_submodule var (sem barra):

path_to_submodule=path/to/submodule

Exclua a linha relevante do arquivo .gitmodules:

git config -f .gitmodules --remove-section submodule.$path_to_submodule

Exclua a seção relevante de .git / config

git config -f .git/config --remove-section submodule.$path_to_submodule

Desestágio e remova $ path_to_submodule apenas do índice (para evitar a perda de informações)

git rm --cached $path_to_submodule

Rastrear alterações feitas em .gitmodules

git add .gitmodules

Confirmar o superprojeto

git commit -m "Remove submodule submodule_name"

Exclua os arquivos do submodulo agora não rastreados

rm -rf $path_to_submodule

rm -rf .git/modules/$path_to_submodule

Consulte também: Linhas-guia alternativas

Rahul Dapke
fonte
Você pode estender isso com a forma de remover um submódulo após um 'add submódulo git', mas sem nunca ter cometido isso? Eu suponho que, nesse caso, nenhuma confirmação seja necessária para remover o submódulo, certo?
Carlo Wood
Eu acho que você precisa trocar o git rm --cached $path_to_submodulee git add .gitmodulesnão? Eu recebi um erro no primeiro comando: fatal: Please stage your changes to .gitmodules or stash them to proceedporque eu tinha alterações sem etapas no .gitmodules. Fazendo o git add .gitmodulesprimeiro resolve isso.
Carlo Wood
2

Isso é fácil:

  1. Remova a seção de .gitmodules
  2. Ligar: git add .gitmodules
  3. Ligar: git submodule deinit <path to submodule>
  4. Ligar: git rm <path to submodule>
  5. Confirmar e enviar

Você precisará excluir os arquivos do módulo em seu projeto manualmente.

Preto
fonte
2
Para mim, bastava ligar git submodule deinit <submodule_name>e git rm <path_to_submodule>. O último comando exclui automaticamente a entrada dentro do .gitmodules. Git 2.17
Dmytro Ovdiienko
0

Na última versão do git, são necessárias apenas 4 operações para remover o submódulo git.

  • Remova a entrada correspondente em .gitmodules
  • Mudanças de estágio git add .gitmodules
  • Remova o diretório do submódulo git rm --cached <path_to_submodule>
  • Comprometa-o git commit -m "Removed submodule xxx"
rashok
fonte
0

Caso você precise fazer isso em um comando de linha com o script bash, como abaixo:

$ cd /path/to/your/repo && /bin/bash $HOME/remove_submodule.sh /path/to/the/submodule

Crie um arquivo de script bash no $HOMEdiretório chamado ie remove_submodule.sh:

#!/bin/bash

git config -f .gitmodules --remove-section submodule.$1
git config -f .git/config --remove-section submodule.$1
git rm --cached $1
git add .gitmodules
git commit -m "Remove submodule in $1"
rm -rf $1
rm -rf .git/modules/$1
git push origin $(git rev-parse --abbrev-ref HEAD) --force --quiet

Chetabahana
fonte
0
  • Um submódulo pode ser excluído executando git rm <submodule path> && git commit. Isso pode ser desfeito usandogit revert .
    • A exclusão remove os dados de rastreamento do superprojeto, que são a entrada gitlink e a seção no .gitmodules arquivo.
    • O diretório de trabalho do submódulo é removido do sistema de arquivos, mas o diretório Git é mantido para permitir o check-out de confirmações anteriores sem a necessidade de buscar em outro repositório.
  • Para remover completamente um submódulo, exclua manualmente manualmente$GIT_DIR/modules/<name>/ .

Fonte: git help submodules

Nikhil
fonte
-1

Removendo o submódulo git

Para remover um gitsubmódulo abaixo de 4 etapas, são necessários.

  1. Remova a entrada correspondente no .gitmodulesarquivo. A entrada pode ser como mencionado abaixo
[submodule "path_to_submodule"]
    path = path_to_submodule
    url = url_path_to_submodule
  1. Mudanças de estágio git add .gitmodules
  2. Remova o diretório do submódulo git rm --cached <path_to_submodule>.
  3. Comprometa git commit -m "Removed submodule xxx"e empurre.

São necessárias mais 2 etapas adicionais mencionadas abaixo para limpar completamente o submódulo na cópia clonada local.

  1. Remova a entrada correspondente no .git/configarquivo. A entrada pode ser como mencionado abaixo
[submodule "path_to_submodule"]
    url = url_path_to_submodule
  1. Faz rm -rf .git/modules/path_to_submodule

Essas 5ª e 6ª etapas não criam alterações que precisam ser confirmadas.

rashok
fonte
Seria muito mais fácil se você usasse git submodule deinit git-scm.com/docs/git-submodule#Documentation/…
Preto