Monorepos com Git: estratégias e ferramentas
1. Introdução aos Monorepos no Contexto do Git
Um monorepo é um repositório Git único que armazena múltiplos projetos relacionados, enquanto um multirepo mantém cada projeto em seu próprio repositório. No ecossistema Git, monorepos oferecem vantagens significativas: visibilidade completa do código, refatorações atômicas entre projetos e compartilhamento simplificado de dependências. Os desafios incluem aumento no tempo de clone, histórico de commits misturado e necessidade de ferramentas especializadas. Um monorepo é ideal quando os projetos compartilham bibliotecas, padrões de código ou precisam de coordenação frequente — como em microsserviços fortemente acoplados ou SDKs multiplataforma.
2. Estruturação de Diretórios e Nomes de Branches
A organização do diretório é crucial para a manutenção de um monorepo. Um padrão comum:
monorepo/
├── apps/
│ ├── web-app/
│ └── mobile-app/
├── libs/
│ ├── shared-utils/
│ └── ui-components/
├── packages/
│ ├── sdk-core/
│ └── cli-tool/
├── .gitignore
└── README.md
Convenções de branches ajudam a identificar o escopo das alterações:
feature/web-app/user-auth
fix/mobile-app/crash-on-load
release/v2.1.0
hotfix/shared-utils/security-patch
Para .gitignore modulares, coloque arquivos específicos em cada subdiretório:
# apps/web-app/.gitignore
node_modules/
dist/
.env
# libs/shared-utils/.gitignore
*.log
__pycache__/
3. Estratégias de Merge e Histórico de Commits
Em monorepos, a escolha da estratégia de merge impacta diretamente a clareza do histórico. O squash merge é preferível para branches de feature, pois condensa múltiplos commits em um único commit atômico:
git checkout main
git merge --squash feature/web-app/login
git commit -m "feat(web-app): implementa fluxo de login com OAuth2"
O rebase interativo mantém um histórico linear, útil para revisão de código:
git checkout feature/mobile-app/push-notifications
git rebase -i main
Políticas de commit atômico exigem que cada commit represente uma mudança completa e funcional. Mensagens descritivas seguem o formato tipo(escopo): descrição. Para conflitos entre projetos, use git log com filtros de caminho:
git log --oneline -- apps/web-app/ libs/shared-utils/
4. Submodules e Subtrees: Alternativas Nativas do Git
Os submodules permitem incluir outros repositórios Git dentro do monorepo:
git submodule add https://github.com/exemplo/external-lib.git libs/external-lib
git submodule update --init --recursive
Vantagens: versionamento independente e isolamento de dependências externas. Desvantagens: comandos adicionais para sincronização e riscos de referências órfãs.
O subtree incorpora o histórico de outro repositório diretamente:
git subtree add --prefix=packages/vendor-lib https://github.com/exemplo/vendor-lib.git main --squash
git subtree pull --prefix=packages/vendor-lib https://github.com/exemplo/vendor-lib.git main
Vantagens: histórico unificado e sem necessidade de comandos extras para contribuidores. Desvantagens: aumento do tamanho do repositório e conflitos em merges complexos. Para monorepos internos, subtrees são geralmente mais práticas que submodules.
5. Ferramentas Complementares para Monorepos
O git worktree permite trabalhar em múltiplos branches simultaneamente sem trocar de diretório:
git worktree add ../monorepo-hotfix hotfix/shared-utils/security
git worktree list
git worktree remove ../monorepo-hotfix
Ferramentas como Lerna, Nx e Turborepo gerenciam dependências entre pacotes e otimizam builds:
# Exemplo com Nx
nx affected:test --base=main
nx build web-app
Hooks personalizados validam alterações em escopos específicos:
# .git/hooks/pre-commit (exemplo parcial)
#!/bin/sh
CHANGED=$(git diff --cached --name-only)
if echo "$CHANGED" | grep -q "^apps/web-app/"; then
cd apps/web-app && npm run lint
fi
6. Otimização de Performance em Monorepos Grandes
Shallow clone limita o histórico baixado:
git clone --depth 1 https://github.com/empresa/monorepo.git
Sparse checkout restringe os diretórios visíveis no working tree:
git sparse-checkout init --cone
git sparse-checkout set apps/web-app libs/shared-utils
Para reduzir o tamanho do repositório, execute periodicamente:
git gc --aggressive --prune=now
git repack -a -d --depth=250 --window=250
O git maintenance automatiza a otimização:
git maintenance start
git maintenance run --task=gc
7. CI/CD e Automação em Monorepos
Triggers seletivos por caminho evitam builds desnecessários:
# GitHub Actions (exemplo)
on:
push:
paths:
- 'apps/web-app/**'
- 'libs/shared-utils/**'
Build incremental baseado em mudanças detecta dependências afetadas:
# Comando hipotético para ferramenta de monorepo
affected-projects --base=main --target=build
Versionamento semântico usa tags no formato pacote@versão:
git tag web-app/v2.1.0
git tag libs/shared-utils/v1.3.2
git push --tags
8. Boas Práticas e Anti-Padrões
Evite commits gigantes — prefira alterações pequenas e focadas. Dependências circulares entre pacotes devem ser eliminadas com refatoração. Para revisão de código, configure CODEOWNERS por diretório:
# .github/CODEOWNERS
/apps/web-app/ @time-web
/libs/shared-utils/ @time-core
Documente a estrutura e crie scripts de inicialização:
#!/bin/bash
# setup.sh
git clone --depth 1 https://github.com/empresa/monorepo.git
cd monorepo
git sparse-checkout set apps/web-app libs/shared-utils
npm install
Anti-padrões comuns incluem misturar lógicas não relacionadas no mesmo commit, ignorar a limpeza de branches obsoletos e não estabelecer limites claros entre projetos.
Referências
- Git SCM Documentation: Submodules — Guia oficial sobre uso de submodules no Git, incluindo comandos e fluxos de trabalho.
- Atlassian: Monorepo vs Multirepo — Artigo técnico comparando abordagens de repositórios únicos e múltiplos com exemplos práticos.
- Nx Documentation: Monorepos — Guia completo sobre gerenciamento de monorepos com a ferramenta Nx, incluindo build incremental e dependências.
- Git SCM: git-worktree — Documentação oficial do comando worktree para gerenciar múltiplos branches simultaneamente.
- Turborepo: Monorepo Handbook — Manual prático sobre estratégias de monorepo usando Turborepo, com foco em performance e cache.
- Git SCM: git-sparse-checkout — Documentação oficial sobre sparse checkout para otimização de repositórios grandes.
- GitHub: CODEOWNERS — Guia sobre configuração de revisores automáticos por escopo de diretório.