
Git hardcore: hooks, submodules, monorepos e sobrevivência em códigos gigantes
Técnicas avançadas de Git para códigos grandes: hooks, submodules, monorepos, performance e plano de desastre.
✨TL;DR / Sumário Executivo
Técnicas avançadas de Git para códigos grandes: hooks, submodules, monorepos, performance e plano de desastre.
💡 TL;DR (Resumo)
Repositórios grandes pedem ferramentas avançadas.
git hooksautomatiza checagens locais.git submodulesé mais problema que solução (evite). Monorepos funcionam se bem estruturados. Performance melhora com.gitignore, Git LFS e clones shallow. Trate o repo como infra crítica: backups, branch protegida, plano de desastre. A verdade: no final, a maioria dos problemas "de Git" é na verdade problema de organização.
Até aqui a gente falou de Git no dia a dia. Agora é hora de encarar as partes que a galera finge que não existe porque dá trabalho:
- Hooks de Git para automatizar checagens
- Submodules (sim, aquele bicho estranho)
- Monorepos e estratégias para repositórios gigantes
- Performance: quando o Git come sua RAM e CPU
- Plano de desastre para não virar refém de um único repositório
Esse é o artigo para quando você já sabe usar Git, mas o tamanho do código começou a doer.
1. Hooks de Git: automatizando boas práticas
Hooks são scripts que o Git executa automaticamente em certos momentos:
- Antes de um commit (
pre-commit) - Depois de um commit (
post-commit) - Antes de um push (
pre-push) - Etc.
Eles moram em .git/hooks/.
1.1. Habilitando um pre-commit simples
Exemplo: impedir commit se existirem console.log perdidos.
Crie o arquivo .git/hooks/pre-commit:
#!/usr/bin/env bash
if git diff --cached | grep -q "console.log"; then
echo "
[pre-commit] Encontrado 'console.log' no diff. Remova antes de commitar." >&2
exit 1
fiDê permissão de execução:
chmod +x .git/hooks/pre-commitAgora, se você tentar commitar com console.log, o commit falha.
1.2. Rodando linter/testes automaticamente
#!/usr/bin/env bash
npm test
STATUS=$?
if [ $STATUS -ne 0 ]; then
echo "
[pre-commit] Testes falharam. Arrume antes de commitar." >&2
exit $STATUS
fiControvérsia: hook só local vira gambiarra se o time todo não usar. Para times grandes, vale padronizar via ferramentas tipo Husky (JS), pre-commit (Python) ou via CI.
2. Submodules: quando (quase nunca) usar
Submodule é basicamente um repositório Git dentro de outro.
Uso clássico:
- Você tem uma lib compartilhada entre vários projetos
- Quer manter o histórico dessa lib separado, mas versionado junto
2.1. Adicionando um submodule
git submodule add https://github.com/org/lib-compartilhada.git libs/lib-compartilhada
git commit -m "Adiciona submodule da lib compartilhada"Isso cria uma entrada no .gitmodules e trata libs/lib-compartilhada como submodule.
2.2. Clonando repo com submodules
git clone https://github.com/org/projeto-com-submodules.git
cd projeto-com-submodules
git submodule update --init --recursiveSem isso, os diretórios de submodule ficam vazios.
2.3. Por que muita gente odeia submodules
- Fluxo de uso é mais chato
- Fácil quebrar se o time não souber mexer
- CI precisa ser configurado com carinho
Alternativas modernas:
- Repos separados com gestão de versão (npm, pip, maven, etc.)
- Monorepo com gerenciador de workspaces (Nx, Turborepo, pnpm, Bazel, etc.)
Opinião polêmica: submodule não é "errado". Errado é enfiar submodule em time que mal sabe fazer merge.
3. Monorepos: um repo para governar todos
Monorepo é quando você coloca vários projetos (serviços, libs, apps) no mesmo repositório Git.
3.1. Vantagens
- Mais fácil manter versões compatíveis
- Refactors entre serviços ficam mais controlados
- CI pode ser otimizado por paths
- Menos "onde vive esse código?" na sua vida
3.2. Desvantagens
- Repo pode ficar gigante
- Clone inicial demorado
- Histórico muito ruidoso se não organizar bem
3.3. Estrutura típica de monorepo
.
├── apps
│ ├── web
│ ├── mobile
│ └── admin
├── services
│ ├── users
│ ├── billing
│ └── notifications
├── libs
│ ├── ui
│ ├── core
│ └── utils
└── tools
└── ci-scripts3.4. Comandos Git úteis em monorepo
Histórico de um subdiretório apenas:
# ver histórico só do serviço de billing
git log --oneline -- services/billingDiferença entre branches apenas para um diretório:
git diff main..minha-branch -- services/billingBlame focado numa parte do repo:
git blame services/billing/src/invoice_service.ts3.5. Filtrando histórico por path
Útil para gerar um histórico "por projeto" dentro do monorepo:
git log --oneline -- services/usersOu mesmo extrair um subdiretório para outro repositório mantendo histórico (com git filter-repo ou filter-branch).
4. Performance: quando o Git come sua máquina
Repositórios gigantes podem deixar o Git lento:
- Muitos arquivos binários
- Histórico gigantesco de merges
- Diretórios
node_modulesoudistcommitados sem querer
4.1. Use .gitignore direito
Não tem conversa: se você está commitando build, dependências e lixo, vai sofrer.
Exemplo básico para projetos JS:
node_modules/
dist/
coverage/
.env
*.log4.2. Git LFS para arquivos grandes
Arquivos binários gigantes (imagens pesadas, vídeos, modelos de ML) não se dão bem com Git puro.
Use Git LFS (Large File Storage):
git lfs track "*.psd"
echo "*.psd filter=lfs diff=lfs merge=lfs -text" >> .gitattributes4.3. Clones rasos (--depth)
Em CI ou ambientes onde você não precisa do histórico inteiro:
git clone --depth=50 https://github.com/org/projeto-gigante.gitIsso baixa só os últimos 50 commits.
4.4. Limpeza periódica
Com o tempo, repositórios podem acumular refs, tags antigas e branches mortas.
# remove refs remotas deletadas
git fetch --prune
# limpa objetos soltos (local)
git gc --prune=now --aggressiveDica: não rode
git gc --aggressivetodo dia, mas de vez em quando em repositórios grandes pode ajudar.
5. Plano de desastre para repositórios críticos
Se o seu repositório é o coração do produto, trate ele como tal.
5.1. Backups e remotos múltiplos
Você pode ter mais de um remoto configurado:
git remote add backup git@backup-server:org/projeto.git
git push --all backup
git push --tags backupSe o GitHub/GitLab da vida tiver um dia ruim, você tem cópia.
5.2. Proteção de branch
Em provedores tipo GitHub/GitLab/Bitbucket:
- Proteja
main/mastercontrapush --force - Exija PR + review para merges
- Exija status de CI verde
Isso não é burocracia: é o que impede git push --force errado sexta às 18h.
5.3. Recuperação após desastre
Se alguém fizer besteira muito grande:
- Pare tudo (nada de push até entender a situação)
- Use
git reflognos clones locais que ainda estão saudáveis - Crie uma nova branch a partir de um commit bom
- Combine com o time como migrar para esse ponto seguro
Ter clones atualizados em máquinas diferentes já é uma forma de backup implícito.
6. Resumo hardcore
Quando o repositório fica grande e a bagunça cresce:
- Use hooks para automatizar checks locais
- Evite submodules a não ser que o time saiba muito bem o que está fazendo
- Considere monorepo se você tem muitos serviços interligados
- Cuide de performance:
.gitignore, Git LFS,--depth,git gc - Trate o repo como infra crítica: backup, branch protegida, plano de desastre
Se esse artigo fez sentido, provavelmente você já tomou umas pancadas de Git na vida.
Manda praquele amigo que ainda acha que git é só "salvar código no GitHub".
Me encontra no X/Twitter: @gss_62
#git #gittips