Rebase interativo: squash, fixup, reorder
1. Introdução ao Rebase Interativo
O comando git rebase -i (ou git rebase --interactive) é uma das ferramentas mais poderosas do Git para reescrever o histórico de commits. Diferente do rebase comum, que simplesmente aplica commits de uma branch sobre outra, o rebase interativo permite que você modifique, reordene, combine ou exclua commits individuais antes de aplicá-los novamente.
Utilizamos o rebase interativo principalmente em cenários onde precisamos limpar o histórico local antes de compartilhá-lo com a equipe. Por exemplo, quando você fez vários commits de "work in progress" (WIP) ou correções incrementais e deseja transformá-los em commits mais organizados e significativos.
Pré-requisito fundamental: nunca faça rebase interativo em commits que já foram enviados para um repositório remoto compartilhado com outros desenvolvedores. Reescrever o histórico público causa problemas de sincronização para todos que já puxaram esses commits.
2. Abrindo o Editor de Rebase
Para iniciar um rebase interativo, use o comando:
git rebase -i HEAD~5
Este comando abre um editor de texto com uma lista dos últimos 5 commits (do mais antigo para o mais recente). O arquivo de instruções se parece com:
pick a1b2c3d Implementa login
pick e4f5g6h Adiciona validação de email
pick i7j8k9l Corrige bug no login
pick m0n1o2p Remove debug
pick q3r4s5t Adiciona testes
Cada linha começa com uma ação (padrão: pick) seguida pelo hash e pela mensagem do commit. As ações disponíveis são:
pick– usa o commit como estáreword– altera apenas a mensagem do commitedit– para modificar o conteúdo do commitsquash– combina com o commit anterior, preservando a mensagemfixup– combina com o commit anterior, descartando a mensagemexec– executa um comando shelldrop– remove o commit
3. Squash: Unindo Múltiplos Commits em Um
O squash é ideal quando você tem commits que representam pequenos passos de desenvolvimento que deveriam ser um único commit lógico. Por exemplo, imagine que você fez:
pick a1b2c3d Adiciona formulário de cadastro
pick e4f5g6h Corrige validação de CPF
pick i7j8k9l Ajusta estilo do botão
Para combinar os dois últimos no primeiro, modifique o arquivo para:
pick a1b2c3d Adiciona formulário de cadastro
squash e4f5g6h Corrige validação de CPF
squash i7j8k9l Ajusta estilo do botão
Ao salvar e fechar o editor, o Git abrirá um novo editor para que você defina a mensagem final do commit combinado. Você pode manter a mensagem original, editá-la ou até mesmo escrever uma nova.
4. Fixup: Unindo sem Editar a Mensagem
O fixup funciona de forma similar ao squash, mas descarta automaticamente a mensagem do commit sendo fixado. É perfeito para correções rápidas onde você não quer poluir o histórico com mensagens como "corrige typo" ou "ajuste menor".
Exemplo prático: você tem um commit de funcionalidade e depois percebe um pequeno erro:
pick a1b2c3d Adiciona módulo de relatórios
pick e4f5g6h Corrige nome da variável
Altere para:
pick a1b2c3d Adiciona módulo de relatórios
fixup e4f5g6h Corrige nome da variável
O resultado será um único commit "Adiciona módulo de relatórios" com a correção incorporada, sem nenhuma menção ao commit de correção.
5. Reorder: Reorganizando a Ordem dos Commits
Reordenar commits é útil quando você deseja agrupar mudanças relacionadas ou organizar o histórico de forma mais lógica. Basta mover as linhas no editor de rebase.
Por exemplo, se você tem:
pick a1b2c3d Adiciona API de usuários
pick e4f5g6h Adiciona frontend de login
pick i7j8k9l Adiciona API de login
E deseja agrupar as mudanças de API, reordene para:
pick a1b2c3d Adiciona API de usuários
pick i7j8k9l Adiciona API de login
pick e4f5g6h Adiciona frontend de login
Cuidado: reordenar commits pode gerar conflitos se houver dependências entre eles. Por exemplo, se o commit "frontend de login" depende de funções definidas em "API de login", colocá-lo antes causará conflitos.
6. Combinando Técnicas: Squash, Fixup e Reorder Juntos
Vamos a um exemplo prático completo. Suponha que você tenha o seguinte histórico em um branch de funcionalidade:
pick a1b2c3d Inicia feature de notificações
pick e4f5g6h WIP: implementa backend
pick i7j8k9l Corrige erro no backend
pick m0n1o2p Adiciona testes backend
pick q3r4s5t Implementa frontend
pick r6s7t8u Ajuste visual no frontend
Objetivo: criar dois commits limpos – um para backend e outro para frontend.
Passo 1: Reordene para agrupar backend e frontend:
pick a1b2c3d Inicia feature de notificações
pick e4f5g6h WIP: implementa backend
pick i7j8k9l Corrige erro no backend
pick m0n1o2p Adiciona testes backend
pick q3r4s5t Implementa frontend
pick r6s7t8u Ajuste visual no frontend
Passo 2: Aplique squash e fixup:
pick a1b2c3d Inicia feature de notificações
squash e4f5g6h WIP: implementa backend
fixup i7j8k9l Corrige erro no backend
fixup m0n1o2p Adiciona testes backend
pick q3r4s5t Implementa frontend
fixup r6s7t8u Ajuste visual no frontend
Após salvar, o Git solicitará a mensagem combinada para o primeiro grupo (backend). O resultado final será:
a1b2c3d Implementa backend de notificações
q3r4s5t Implementa frontend de notificações
Verifique com:
git log --oneline
7. Resolução de Conflitos Durante o Rebase Interativo
Conflitos podem ocorrer durante o rebase interativo, especialmente ao reordenar commits. Quando isso acontece:
- O Git pausa o rebase e exibe uma mensagem indicando o conflito.
- Use
git statuspara ver quais arquivos estão em conflito. - Edite os arquivos para resolver os conflitos manualmente.
- Adicione as alterações resolvidas com
git add <arquivo>. - Continue o rebase com
git rebase --continue.
Se você se sentir perdido ou quiser desistir, use git rebase --abort para voltar ao estado anterior ao rebase.
8. Boas Práticas e Cuidados
- Nunca reescreva histórico público: rebase interativo deve ser usado apenas em commits que ainda não foram enviados para o repositório remoto compartilhado.
- Use
--force-with-leasecom cautela: se precisar forçar o push após um rebase em um branch compartilhado (e tiver certeza do que está fazendo), prefiragit push --force-with-leaseem vez de--force, pois ele verifica se ninguém mais enviou commits para o branch. - Crie um backup: antes de iniciar um rebase interativo complexo, crie um branch de backup:
git branch backup/feature-xyz
Isso permite que você volte ao estado original facilmente se algo der errado.
O rebase interativo é uma ferramenta essencial para manter um histórico limpo e compreensível. Dominar squash, fixup e reorder transforma seu workflow Git, permitindo que você apresente commits organizados e significativos para sua equipe.
Referências
- Documentação oficial do Git - Rebase Interativo — Guia completo sobre o modo interativo do rebase, incluindo todas as ações disponíveis e opções avançadas.
- Atlassian Git Tutorial - Rebase Interativo — Tutorial prático com exemplos de squash, fixup e reorder, além de boas práticas para uso em equipe.
- Git SCM - Squash e Fixup explicados — Seção do livro Pro Git que detalha o squash e fixup com exemplos passo a passo.
- GitHub Blog - Usando squash e fixup — Artigo do GitHub sobre como usar squash e fixup para manter um histórico limpo em pull requests.
- Git Tower - Rebase Interativo para iniciantes — Explicação visual e didática do rebase interativo, ideal para quem está começando.
- FreeCodeCamp - Guia completo de Git Rebase — Tutorial abrangente com exemplos de reorder, squash e fixup, incluindo resolução de conflitos.