Git submodule: como adicionar, atualizar e remover submódulos
Um git submodule é outro repositório aninhado no seu e fixado em um commit específico. O submódulo é adicionado com git submodule add <url> <caminho>, baixado no clone com git clone --recurse-submodules, atualizado com git submodule update --remote e removido com git submodule deinit e git rm.
Um git submodule (submódulo) é um repositório Git separado, aninhado em uma pasta do seu projeto. Sua principal característica: o repositório pai não guarda os arquivos do submódulo, e sim uma referência a um commit específico dele. Por isso, todos que clonarem o projeto terão o submódulo na mesma versão — até que você a mude explicitamente.
Submódulos são usados quando é preciso incluir uma biblioteca de terceiros sem gerenciador de pacotes, compartilhar código comum entre vários projetos ou separar um tema visual ou um firmware em um repositório próprio, com histórico independente.
Como os git submodules funcionam
Um submódulo tem três partes, e entender como elas se ligam elimina a maioria dos problemas:
- O arquivo
.gitmodulesna raiz do projeto — é commitado e descreve qual caminho vem de qual URL. - A entrada gitlink na árvore do commit — um elemento especial com modo
160000, que guarda o hash do commit do submódulo em vez de conteúdo. - O próprio repositório do submódulo — seus dados ficam em
.git/modules/<nome>do pai, e na pasta do submódulo há um arquivo.gitapontando para lá.
cat .gitmodules
[submodule "libs/ui-kit"]
path = libs/ui-kit
url = https://github.com/example/ui-kit.git
git ls-tree HEAD libs/
160000 commit 8d7c6b5a4f3e2d1c0b9a8f7e6d5c4b3a2f1e0d9c libs/ui-kit
Repare: o pai registra um commit, não uma branch. Essa é a diferença fundamental entre um submódulo Git e uma dependência do tipo "última versão da main".
Como adicionar um submódulo
git submodule add https://github.com/example/ui-kit.git libs/ui-kit
Cloning into '/home/dev/shop/libs/ui-kit'...
done.
git status
new file: .gitmodules
new file: libs/ui-kit
git commit -m "Adicionar ui-kit como submódulo"
O comando clona o repositório, cria ou completa o .gitmodules e adiciona o gitlink ao índice. Só falta commitar. Se o caminho não for informado, a pasta recebe o nome do repositório.
Para que o submódulo acompanhe uma branch específica nas atualizações, informe-a logo de cara: git submodule add -b develop <url> <caminho>. A branch é gravada no .gitmodules como branch = develop.
URL relativa
Se o submódulo estiver no mesmo servidor, dá para usar um caminho relativo: git submodule add ../ui-kit.git libs/ui-kit. Ele é resolvido em relação à URL do repositório remoto do pai, então funciona tanto por SSH quanto por HTTPS — dependendo de como o projeto foi clonado.
Como clonar um projeto com submódulos
A reclamação mais comum: "clonei e a pasta do submódulo está vazia". Por padrão, o git clone não baixa submódulos. O certo é:
git clone --recurse-submodules https://github.com/example/shop.git
Se o projeto já foi clonado sem os submódulos:
git submodule update --init --recursive
--init registra os submódulos do .gitmodules no .git/config local, update os baixa e muda para o commit fixado, e --recursive faz o mesmo para submódulos dentro de submódulos.
Como atualizar um submódulo
Aqui é importante separar duas tarefas: "pegar a versão que os colegas commitaram" e "passar para uma nova versão da biblioteca".
Pegar a versão fixada no projeto
Depois de um git pull no pai, o gitlink pode ter mudado, mas os arquivos do submódulo não se atualizam sozinhos — o git status mostra modified: libs/ui-kit (new commits). Sincronize:
git pull
git submodule update --init --recursive
Para não fazer isso à mão, ative a automação: git config submodule.recurse true. Assim pull, checkout e switch passam a atualizar os submódulos sozinhos. Para uma chamada pontual, a alternativa é git pull --recurse-submodules.
Passar para uma nova versão da biblioteca
# Opção 1: trazer o último commit da branch acompanhada
git submodule update --remote libs/ui-kit
# Opção 2: escolher a versão manualmente
cd libs/ui-kit
git fetch
git checkout v3.2.0
cd ../..
# Nos dois casos — registrar a nova versão no pai
git add libs/ui-kit
git commit -m "Atualizar ui-kit para v3.2.0"
O --remote usa a branch do parâmetro branch no .gitmodules e, se ele não existir, a branch para a qual aponta o HEAD do repositório remoto do submódulo (normalmente main). Sem o último commit no pai, os colegas não recebem a nova versão: atualizar um submódulo é sempre uma alteração do gitlink que precisa ser commitada.
Para ver o que mudou nos submódulos:
git diff --submodule=log
git config diff.submodule log # tornar esse formato o padrão
git submodule status
8d7c6b5a4f3e2d1c0b9a8f7e6d5c4b3a2f1e0d9c libs/ui-kit (v3.1.0)
+1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b libs/charts (v1.4.0-3-g1a2b3c4)
O prefixo no git submodule status: - — submódulo não inicializado, + — o commit atual difere do fixado no pai, U — conflito de merge.
Como fazer alterações em um submódulo
Depois de git submodule update, o submódulo fica em detached HEAD — em um commit específico, não em uma branch. Se você começar a commitar assim, é fácil perder os commits no próximo update. A ordem de trabalho:
cd libs/ui-kit
git switch main # ir para uma branch
# ... alterações ...
git commit -am "Corrigir espaçamento do botão"
git push # primeiro o push do submódulo!
cd ../..
git add libs/ui-kit
git commit -m "ui-kit: espaçamento do botão corrigido"
git push
A ordem dos pushes é crítica. Se você enviar o pai antes do submódulo, no servidor o projeto vai apontar para um commit que ninguém além de você consegue baixar, e nos colegas o git submodule update falha com fatal: remote error: upload-pack: not our ref ou did not contain. Para se proteger, use git push --recurse-submodules=check (recusa o push se o submódulo não foi enviado) ou =on-demand (envia os submódulos primeiro automaticamente).
Como remover um submódulo
Antigamente, remover exigia editar vários arquivos à mão. Nas versões atuais do Git, bastam três passos:
git submodule deinit -f libs/ui-kit # tirar do .git/config e limpar a pasta
git rm -f libs/ui-kit # remover o gitlink e a entrada do .gitmodules
rm -rf .git/modules/libs/ui-kit # apagar os dados guardados do submódulo
git commit -m "Remover submódulo ui-kit"
O último passo não é obrigatório para a correção, mas sem ele, ao adicionar de novo um submódulo no mesmo caminho, o Git pode reclamar que a pasta local já existe (A git directory for 'libs/ui-kit' is found locally).
Se a URL do submódulo mudou
O repositório mudou de lugar? Corrija o .gitmodules e sincronize a configuração local:
git submodule set-url libs/ui-kit https://gitlab.com/example/ui-kit.git
git submodule sync --recursive
git commit -am "Novo endereço do ui-kit"
Os colegas também precisam rodar git submodule sync depois do pull: a URL do .gitmodules só é copiada para o .git/config deles no init ou no sync.
Comandos úteis para vários submódulos
| Tarefa | Comando |
|---|---|
| Lista e estado | git submodule status --recursive |
| Executar um comando em cada um | git submodule foreach 'git switch main && git pull' |
| Acelerar o download | git submodule update --init --jobs 4 |
| Baixar sem histórico | git submodule update --init --depth 1 |
| Resumo no status | git config status.submoduleSummary true |
Problemas comuns com submódulos
- Pasta vazia depois do clone — o init não foi feito. Solução:
git submodule update --init --recursive. - "modified: (new commits)" logo depois do pull — o pai aponta para outro commit, mas os arquivos são antigos. Solução:
git submodule update. - Submódulo revertido sem querer — rodou
git add .com o submódulo em um commit antigo e commitou o retrocesso de versão. Sempre confiragit diff --submoduleantes de commitar. - Conflito de gitlink no merge — em duas branches o submódulo foi atualizado para commits diferentes. Entre no submódulo, escolha o commit certo (muitas vezes o mais novo, que inclui as duas alterações), depois
git add caminhoe conclua o merge. - Submódulo privado no CI — o build não consegue baixar o submódulo sem acesso. É preciso dar ao CI uma chave ou token para o repositório do submódulo; URLs relativas simplificam a configuração.
Submódulos em equipe: combinados
A maior parte dos problemas com submódulos não vem do Git, e sim de cada pessoa agir de um jeito. Algumas regras que vale registrar no README do projeto:
- Clonar sempre com
--recurse-submodulese ativarsubmodule.recurse truepara todos. - Atualizar o submódulo em um commit separado, com mensagem clara: qual versão e por quê.
- Não editar o código do submódulo no projeto pai sem um commit e push separados no próprio submódulo.
- No CI, rodar explicitamente
git submodule update --init --recursivee verificar que o build não depende de alterações locais.
Para verificar no CI que todos os commits fixados dos submódulos estão realmente acessíveis, basta um clone limpo: se alguém esqueceu de enviar o submódulo, o build falha na etapa de update, e não na máquina de um colega uma semana depois.
git clone --recurse-submodules --jobs 4 "$REPO_URL" build
cd build
git submodule status --recursive
Submodule ou alternativas
Submódulos dão controle exato da versão e históricos separados, mas acrescentam passos manuais para cada participante. Se o código é uma biblioteca comum, um gerenciador de pacotes é mais simples (npm, pip, Composer, Go modules). Se o importante é que o código de terceiros simplesmente fique dentro do projeto e seja clonado sem comandos extras, considere o git subtree: ele copia o histórico para o repositório principal, e os colegas não precisam saber de nada. Para muitos serviços relacionados, as equipes costumam escolher um monorepo. O submódulo se justifica quando o código aninhado tem vida própria, releases próprios e equipe própria.
Resumo
Um git submodule é uma referência a um commit específico de outro repositório. Adicionar — git submodule add; baixar — --recurse-submodules ou update --init; atualizar para nova versão — update --remote mais um commit no pai; remover — deinit, git rm e limpeza de .git/modules. Lembre do detached HEAD dentro do submódulo e da ordem dos pushes. As ferramentas avançadas do Git são praticadas no curso de Git.
Perguntas frequentes
Por que o submódulo está sempre em detached HEAD?
O pai guarda o hash de um commit, não uma branch, e o git submodule update muda o submódulo exatamente para esse commit. Para editar, mude para uma branch manualmente ou use git submodule update --remote --merge.
Dá para fixar um submódulo em uma tag?
Diretamente não, mas você pode fazer checkout da tag dentro do submódulo e commitar no pai o commit resultante; no git submodule status a tag aparece entre parênteses.
O GitHub inclui os submódulos no arquivo ZIP?
Não, os arquivos de código-fonte do GitHub não incluem o conteúdo dos submódulos, as pastas ficam vazias. Use git clone --recurse-submodules.
Qual a diferença entre git submodule e git subtree?
O submodule guarda uma referência a um commit de um repositório externo e exige comandos separados para baixar o código, enquanto o subtree copia os arquivos e o histórico direto para o repositório principal.
Dá para mover um submódulo para outra pasta?
Sim, com git mv caminho/antigo caminho/novo: o Git atualiza sozinho o .gitmodules e as referências internas, só falta commitar.
Este tema é abordado em profundidade, com prática, no curso “Git do zero ao desenvolvedor confiante”.
Ir para o curso