Interactive rebase para limpeza de histórico antes do PR

1. Fundamentos do Interactive Rebase

O git rebase -i (modo interativo) é uma ferramenta poderosa que permite reescrever o histórico de commits antes de enviar um Pull Request. Diferente do rebase comum, que apenas move commits para uma nova base, o interactive rebase abre um editor onde você pode modificar, unir, reordenar ou excluir commits individualmente.

Pré-requisitos essenciais:
- Commits ainda não enviados para o repositório remoto compartilhado
- Branch atualizada com a base (geralmente main ou develop)
- Certifique-se de que ninguém mais está trabalhando na sua branch

# Verificando se há commits locais não compartilhados
git log origin/main..HEAD --oneline

2. Preparação para o Rebase Interativo

Antes de iniciar, identifique o commit base. Use git log ou git merge-base:

# Identificar quantos commits você fez
git log --oneline

# Encontrar o ponto de divergência com a branch base
git merge-base HEAD origin/main

Para iniciar o rebase interativo:

# Modo 1: especificando número de commits
git rebase -i HEAD~5

# Modo 2: usando hash do commit base
git rebase -i <commit-hash>

O editor será aberto com uma lista semelhante a esta:

pick a1b2c3d Implementa funcionalidade X
pick e4f5g6h Corrige bug na funcionalidade X
pick i7j8k9l Adiciona testes para funcionalidade X
pick m0n1o2p Ajusta formatação
pick q3r4s5t Remove debug temporário

3. Comandos Essenciais para Limpeza de Histórico

pick — Mantendo commits inalterados

Use pick (ou p) para commits que devem permanecer como estão. É o comando padrão.

squash e fixup — Unificando commits relacionados

squash (ou s) combina o commit com o anterior e permite editar a mensagem final. fixup (ou f) faz o mesmo, mas descarta a mensagem do commit sendo incorporado.

Cenário prático: Você fez vários commits de correção após implementar uma funcionalidade:

pick a1b2c3d Implementa funcionalidade X
fixup e4f5g6h Corrige bug na funcionalidade X
fixup i7j8k9l Ajusta formatação
pick m0n1o2p Adiciona testes
fixup q3r4s5t Remove debug temporário

Após salvar, o histórico mostrará apenas dois commits limpos.

reword — Renomeando mensagens de commit

Use reword (ou r) para melhorar mensagens confusas:

reword a1b2c3d "wip" → "Implementa validação de entrada do usuário"
pick e4f5g6h Adiciona testes unitários

4. Removendo e Reorganizando Commits

drop — Excluindo commits desnecessários

Commits de "wip", "teste" ou "debug" podem ser removidos:

pick a1b2c3d Implementa funcionalidade X
drop e4f5g6h commit de teste
pick i7j8k9l Adiciona testes

edit — Modificando conteúdo de um commit específico

Use edit (ou e) para pausar o rebase e alterar arquivos:

edit a1b2c3d Implementa funcionalidade X
pick e4f5g6h Adiciona testes

Quando o rebase pausar, faça as alterações e continue:

# Faça alterações nos arquivos
git add .
git commit --amend
git rebase --continue

Reordenando commits

Simplesmente mova as linhas no editor para criar uma sequência lógica:

# Antes (confuso)
pick i7j8k9l Adiciona testes
pick a1b2c3d Implementa funcionalidade X
pick e4f5g6h Corrige bug

# Depois (lógico)
pick a1b2c3d Implementa funcionalidade X
pick i7j8k9l Adiciona testes
pick e4f5g6h Corrige bug

5. Resolvendo Conflitos Durante o Rebase

Conflitos podem ocorrer ao reordenar ou fazer squash de commits. O Git pausa o rebase e indica os arquivos conflitantes.

Identificando conflitos:

git status
# Mostra arquivos em conflito (both modified)

Resolvendo manualmente:

Abra os arquivos conflitantes e edite as marcações <<<<<<<, =======, >>>>>>>. Após resolver:

git add <arquivo-resolvido>
git rebase --continue

Usando ferramenta visual:

git mergetool
# Configure previamente: git config merge.tool vimdiff

Opções de emergência:

# Para desistir do rebase
git rebase --abort

# Para pular um commit problemático
git rebase --skip

6. Boas Práticas e Validação Final

Verificando o histórico limpo

git log --oneline --graph --decorate --all

Exemplo de saída desejada:

* 1234567 (HEAD -> feature/nova-funcionalidade) Adiciona testes de integração
* 2345678 Implementa funcionalidade X com validação
* 3456789 Refatora módulo de autenticação
* 4567890 (origin/main) Último commit da main

Testando antes do PR

# Verificar diferenças com a base
git diff origin/main

# Executar testes automatizados
npm test  # ou equivalente

Forçando o push com cautela

Nunca use --force em branches compartilhadas. Prefira:

git push --force-with-lease

Este comando verifica se sua branch remota não foi atualizada por outra pessoa, evitando sobrescrever trabalho alheio.

7. Cenários Comuns e Erros a Evitar

❌ Rebase em branches compartilhadas

Se outros desenvolvedores já fizeram checkout da sua branch, evite rebase. Use git revert para desfazer commits publicados.

❌ Squash excessivo

Agrupar commits muito diferentes (ex.: "implementa login" com "corrige cor do botão") dificulta revisões e bisect futuro.

Boa prática: Mantenha commits atômicos — cada commit deve representar uma mudança lógica única.

❌ Esquecer de atualizar a branch base

Sempre faça git pull origin main (ou rebase com a base) antes do rebase interativo para evitar conflitos desnecessários.

Fluxo completo recomendado:

# 1. Atualizar com a base
git checkout main
git pull origin main
git checkout feature/minha-feature
git rebase main

# 2. Limpar histórico
git rebase -i HEAD~N

# 3. Validar
git log --oneline --graph
git diff origin/main
npm test

# 4. Enviar
git push --force-with-lease

Com essas práticas, seus Pull Requests terão históricos limpos, facilitando a revisão por colegas e mantendo um registro claro das alterações no projeto.

Referências