Pull Requests: boas práticas de revisão
1. Fundamentos de um Pull Request Eficiente
1.1. O que é um Pull Request e seu ciclo de vida no Git
Um Pull Request (PR) é um mecanismo de colaboração que permite solicitar que alterações de um branch sejam integradas a outro branch (geralmente o branch principal). No Git, o ciclo de vida de um PR envolve: criação do branch de feature, desenvolvimento com commits, abertura do PR, revisão, ajustes e, finalmente, o merge.
1.2. Tamanho ideal do PR: como dividir mudanças complexas
PRs muito grandes são difíceis de revisar e aumentam a chance de bugs passarem despercebidos. O ideal é que cada PR contenha uma única mudança lógica e coesa.
Exemplo de divisão inadequada:
PR #42: "Implementar sistema de login completo"
- 40 arquivos alterados
- 2000 linhas adicionadas
- Mistura de frontend, backend e banco de dados
Exemplo de divisão adequada:
PR #42: "Adicionar modelo de usuário no banco de dados"
- 3 arquivos alterados
- 50 linhas adicionadas
PR #43: "Criar endpoint de registro de usuário"
- 5 arquivos alterados
- 120 linhas adicionadas
PR #44: "Implementar tela de login no frontend"
- 8 arquivos alterados
- 200 linhas adicionadas
1.3. Relação entre commits, branches e o PR
Cada commit deve representar uma unidade lógica de mudança. O branch do PR deve ser criado a partir de um ponto estável do branch base.
# Criando branch para nova feature
git checkout -b feature/autenticacao-jwt main
# Commits atômicos
git commit -m "feat: adicionar dependência jsonwebtoken"
git commit -m "feat: criar middleware de verificação JWT"
git commit -m "feat: proteger rotas de usuário com JWT"
2. Preparação do PR para Revisão
2.1. Escrevendo títulos e descrições claras e objetivas
O título deve resumir a mudança em poucas palavras. A descrição deve explicar o "porquê" e "como" da mudança.
Exemplo de descrição eficiente:
## Título: "Corrigir vazamento de memória no processamento de imagens"
## Descrição:
### Problema
O processamento de imagens de alta resolução estava causando
vazamento de memória, levando ao crash do servidor após
aproximadamente 100 requisições.
### Causa
O buffer de imagem não estava sendo liberado após o
redimensionamento, acumulando memória a cada requisição.
### Solução
Adicionar chamada explícita para `buffer.free()` após o
processamento. Testado com imagens de até 50MB.
### Testes
- Teste unitário para liberação de buffer
- Teste de carga com 500 requisições simultâneas
2.2. Como referenciar issues e tarefas no corpo do PR
Plataformas como GitHub e GitLab permitem referenciar issues automaticamente.
Closes #123
Related to #456
## Checklist
- [x] Código segue o guia de estilo
- [x] Testes unitários adicionados
- [x] Documentação atualizada
- [x] Sem warnings do linter
2.3. Checklist de auto-revisão antes de abrir o PR
## Auto-revisão
- [ ] O código compila sem erros?
- [ ] Testes passam localmente?
- [ ] Não há código comentado ou debug statements?
- [ ] Variáveis e funções têm nomes significativos?
- [ ] O histórico de commits está limpo?
- [ ] A branch está atualizada com o branch base?
3. Boas Práticas de Commits Dentro do PR
3.1. Commits atômicos e mensagens descritivas
Cada commit deve representar uma única mudança lógica, facilitando o entendimento e possível reversão.
# Mensagens descritivas seguindo Conventional Commits
git commit -m "feat(api): adicionar endpoint GET /users/:id"
git commit -m "fix(auth): corrigir validação de token expirado"
git commit -m "refactor(database): extrair conexão para módulo separado"
3.2. Uso de git rebase -i para limpar o histórico antes do merge
Antes do merge, reorganize os commits para manter um histórico limpo.
# Interativamente reorganizar últimos 5 commits
git rebase -i HEAD~5
# Comandos comuns no rebase interativo:
# pick - manter o commit
# squash - combinar com o commit anterior
# reword - alterar mensagem do commit
# fixup - combinar com anterior descartando mensagem
3.3. Evitando commits de "merge" e "fixup" desnecessários
Commits de merge poluem o histórico. Prefira rebase para atualizar o branch.
# Em vez de:
git merge main # cria commit de merge desnecessário
# Faça:
git rebase main # mantém histórico linear
4. O Papel do Revisor: O que Analisar
4.1. Lógica e corretude do código vs. estilo e formatação
Priorize a revisão da lógica de negócio. Use ferramentas automáticas (linters, formatters) para estilo.
# O que revisar manualmente:
- Lógica de validação está correta?
- Tratamento de erros é adequado?
- Casos de borda foram considerados?
# O que automatizar:
- Formatação (Prettier, Black)
- Estilo (ESLint, Pylint)
- Tipos (TypeScript, mypy)
4.2. Verificação de segurança, performance e testes
# Checklist de segurança
- [ ] Dados de entrada são sanitizados?
- [ ] Autenticação e autorização estão corretas?
- [ ] Não há exposição de informações sensíveis?
# Checklist de performance
- [ ] Consultas ao banco estão otimizadas?
- [ ] Há N+1 queries?
- [ ] Recursos são liberados corretamente?
# Checklist de testes
- [ ] Testes cobrem o cenário feliz?
- [ ] Testes cobram casos de erro?
- [ ] Testes de integração foram adicionados?
4.3. Como usar git diff e git log para entender o PR
# Ver alterações completas do PR
git diff main...feature-branch
# Ver apenas arquivos alterados
git diff --stat main...feature-branch
# Ver histórico de commits do PR
git log main..feature-branch --oneline
# Ver alterações de um commit específico
git show <commit-hash>
5. Comunicação e Feedback na Revisão
5.1. Como dar feedback construtivo e específico
# Feedback construtivo
"Na linha 42, a validação de email pode ser simplificada
usando a biblioteca `email-validator`. Isso reduziria o
código e melhoraria a cobertura de casos de borda."
# Feedback vago (evitar)
"Isso está errado."
5.2. Diferença entre "must fix", "nice to have" e "suggestion"
# Must fix (bloqueante)
"**Must fix**: A função `deleteUser` não verifica se o
usuário existe antes de tentar deletar. Isso pode causar
um erro 500. Adicione verificação de existência."
# Nice to have (não bloqueante)
"**Nice to have**: Considere adicionar logging para
facilitar debug em produção."
# Suggestion (apenas sugestão)
"**Suggestion**: Poderíamos extrair a lógica de
validação para um módulo separado no futuro."
5.3. Lidando com discordâncias e revisões iterativas
Quando houver discordância, foque em dados e evidências, não em opiniões pessoais. Ciclos de revisão são normais e esperados.
# Abordagem produtiva
"Entendo seu ponto sobre performance, mas os benchmarks
mostram que a versão atual é 30% mais lenta. Podemos
discutir alternativas na daily de hoje?"
6. Ferramentas e Fluxos de Revisão com Git
6.1. Uso de git request-pull e patches em projetos sem plataforma
Para projetos sem GitHub/GitLab, é possível usar patches.
# Gerar patch das alterações
git format-patch main --stdout > feature.patch
# Aplicar patch
git am feature.patch
# Ou usar request-pull para notificar mantenedores
git request-pull main origin feature-branch
6.2. Integração com CI/CD: testes automáticos no PR
Configure CI para executar automaticamente ao abrir/atualizar PR.
# Exemplo de workflow GitHub Actions
name: PR Checks
on: [pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: npm install
- run: npm test
- run: npm run lint
6.3. Estratégias de merge: squash, rebase ou merge commit
# Squash - combina todos os commits em um
# Ideal para: features pequenas, histórico limpo
git merge --squash feature-branch
# Rebase - mantém commits individuais sem merge commit
# Ideal para: features com commits atômicos significativos
git rebase main feature-branch
git checkout main
git merge feature-branch
# Merge commit - preserva histórico completo
# Ideal para: colaboração em equipe, features complexas
git checkout main
git merge --no-ff feature-branch
7. Finalização e Merge do PR
7.1. Critérios para aprovação: quantos revisores?
Projetos críticos geralmente exigem 2 revisores. Projetos menores podem exigir 1.
# Critérios de aprovação
- [ ] Pelo menos 1 revisor aprovou (projetos pequenos)
- [ ] Pelo menos 2 revisores aprovaram (projetos críticos)
- [ ] Todos os "must fix" foram resolvidos
- [ ] CI/CD passou com sucesso
- [ ] Branch está atualizada com o branch base
7.2. Boas práticas ao fazer merge (evitar conflitos futuros)
# Antes do merge, atualizar branch
git checkout feature-branch
git rebase main
# Verificar se não há conflitos
git diff --check
# Fazer merge apenas quando todos os checks passarem
git checkout main
git merge --no-ff feature-branch
7.3. Atualização do branch base e limpeza pós-merge
# Após merge, deletar branch remoto e local
git push origin --delete feature-branch
git branch -d feature-branch
# Atualizar branch base
git checkout main
git pull origin main
Referências
- GitHub - About pull requests — Documentação oficial do GitHub sobre PRs, incluindo ciclo de vida e boas práticas
- Atlassian - Pull Request Best Practices — Tutorial completo da Atlassian com dicas para criar e revisar PRs eficientes
- GitLab - Merge requests best practices — Guia oficial do GitLab sobre revisão de código e merge requests
- Conventional Commits — Especificação para mensagens de commit padronizadas, amplamente usada em PRs
- Google - Code Review Developer Guide — Guia de revisão de código do Google, com foco em feedback construtivo e eficiência
- Git SCM - Rebasing — Documentação oficial do Git sobre rebase, essencial para limpar histórico de PRs
- ThoughtWorks - Code Review — Artigo da ThoughtWorks sobre como fazer code review de forma eficaz