Git range-diff: comparando séries de commits entre branches
1. Introdução ao git range-diff
O git range-diff é um comando Git introduzido na versão 2.19 que permite comparar duas séries de commits entre si, identificando correspondências e diferenças entre elas. Diferentemente do git diff (que compara o conteúdo de arquivos) e do git log (que exibe o histórico de commits), o range-diff opera em um nível mais alto: ele compara conjuntos de commits como sequências, detectando quais commits foram mantidos, modificados, reordenados ou removidos.
Os cenários típicos de uso incluem:
- Revisão de rebase: verificar o que mudou após um
git rebase -i - Validação de cherry-pick: comparar commits originais com os cherry-pickados
- Análise de squash: entender como commits foram combinados
- Revisão de merge: comparar a série de commits de uma feature branch antes e depois de um merge
2. Sintaxe básica e modos de operação
O formato fundamental do comando é:
git range-diff <range1> <range2>
Onde cada range pode ser especificado de duas formas:
Comparação direta entre séries:
git range-diff main~5..main topic~5..topic
Isso compara os últimos 5 commits de main com os últimos 5 commits de topic.
Uso com ranges simétricos:
git range-diff A...B C...D
O operador ... (três pontos) cria um range simétrico, incluindo commits que estão em A mas não em B, e vice-versa. Isso é útil para comparar branches que divergiram.
Exemplo prático:
# Comparar os últimos 3 commits de develop com os de feature
git range-diff develop~3..develop feature~3..feature
3. Entendendo a saída do range-diff
A saída do range-diff é estruturada em seções que mostram:
- Commits correspondentes: identificados por números de sequência
- Commits não correspondentes: exibidos com indicadores especiais
- Diferenças no patch: mostradas linha a linha
Os indicadores de mudança incluem:
-: linha removida no commit correspondente+: linha adicionada no commit correspondente: linha inalterada!: indica que o commit não tem correspondente (aparece apenas em um dos ranges)
Exemplo de saída:
1: 123abcd ! 2: 456efgh
@@ -12,6 +12,7 @@
função antiga() {
+ nova funcionalidade
}
2: 789ijkl ! 3: 012mnop
@@ -5,3 +5,5 @@
- linha removida
+ linha adicionada
A primeira linha 1: 123abcd ! 2: 456efgh indica que o commit 123abcd (primeiro range) corresponde ao commit 456efgh (segundo range), mas com diferenças. O patch abaixo mostra exatamente o que mudou.
4. Aplicações práticas: revisão de rebase interativo
O uso mais comum do range-diff é verificar o resultado de um git rebase -i. Suponha que você tenha:
# Antes do rebase (branch feature)
git log --oneline feature
a1b2c3d Commit 3
d4e5f6g Commit 2
h7i8j9k Commit 1
# Após rebase interativo com squash e reword
git rebase -i main
# Resultado:
l0m1n2o Commit 3 (modificado)
p3q4r5s Commit 1+2 (squash)
Para verificar o que mudou:
git range-diff main~3..main feature~3..feature
A saída mostrará:
- O commit
h7i8j9k(Commit 1) foi combinado comd4e5f6g(Commit 2) no novo commitp3q4r5s - O commit
a1b2c3d(Commit 3) foi modificado paral0m1n2o - As diferenças específicas de cada commit são exibidas
Isso permite identificar rapidamente:
- Commits removidos: aparecem sem correspondente
- Commits reordenados: a numeração muda
- Commits modificados: mostram o patch diff
- Squashes: múltiplos commits antigos mapeiam para um novo
5. Aplicações práticas: validação de cherry-pick e merge
Cherry-pick de múltiplos commits:
# Branch origem: feature
git checkout main
git cherry-pick feature~3..feature
# Verificar se o cherry-pick foi fiel
git range-diff feature~3..feature main~3..main
Se houver conflitos resolvidos manualmente, o range-diff mostrará exatamente quais linhas foram alteradas durante a resolução, permitindo verificar se a resolução foi correta.
Revisão de merge de feature branches:
# Antes do merge
git checkout main
git merge feature
# Comparar commits da feature antes e depois
git range-diff feature~5..feature main~5..main
Isso é particularmente útil quando o merge gera um commit de merge com conflitos resolvidos. O range-diff mostrará se algum commit da feature foi alterado durante o processo.
Detectando alterações acidentais:
# Após um rebase, verificar se apenas o esperado mudou
git range-diff ORIG_HEAD..HEAD@{1} HEAD~3..HEAD
6. Dicas avançadas e flags úteis
--creation-factor: Controla a sensibilidade na correspondência entre commits. O valor padrão é 60 (percentual). Valores mais baixos (ex: 30) permitem corresponder commits mais diferentes; valores mais altos (ex: 90) exigem maior similaridade.
# Permitir correspondência mesmo com mudanças significativas
git range-diff --creation-factor=30 A..B C..D
--no-color e --no-stat: Úteis para scripts e automação:
# Saída limpa para processamento em script
git range-diff --no-color --no-stat A..B C..D
Combinando com git log:
# Ver apenas os hashes dos commits correspondentes
git range-diff A..B C..D | grep "^[0-9]:" | cut -d' ' -f2
Com git format-patch:
# Gerar patches e comparar
git format-patch -o patches_old A~3..A
git format-patch -o patches_new B~3..B
git range-diff patches_old/* patches_new/*
Isso permite comparar séries de commits mesmo que os ranges não estejam mais disponíveis no repositório atual.
7. Limitações e boas práticas
Quando range-diff não é adequado:
- Grandes reescritas: se um rebase reescreve completamente a lógica, o algoritmo de correspondência pode falhar
- Squash total: quando múltiplos commits são combinados em um único, a correspondência individual se perde
- Histórias lineares muito longas: a comparação pode se tornar lenta
Impacto em performance:
O range-diff compara cada commit de um range com cada commit do outro range, calculando similaridade. Para ranges com mais de 50 commits, o comando pode demorar significativamente. Estratégias para mitigar:
- Limitar o range com
~N(ex:main~10..main) - Usar
--creation-factormais alto para reduzir comparações
Boas práticas para code review:
- Sempre use
range-diffapós rebase interativo para verificar se nenhuma alteração foi perdida - Documente o comando usado em mensagens de commit ou PRs
- Combine com
git log --onelinepara ter contexto visual antes/depois - Em pipelines CI, use
--no-colore capture a saída para análise automatizada
Exemplo de workflow completo:
# 1. Antes do rebase, salve a referência
git branch backup_feature
# 2. Execute o rebase
git rebase -i main
# 3. Verifique o resultado
git range-diff backup_feature~5..backup_feature feature~5..feature
# 4. Se tudo correto, remova o backup
git branch -D backup_feature
O git range-diff é uma ferramenta essencial para qualquer desenvolvedor que trabalhe com Git em projetos colaborativos, especialmente quando operações de reescrita de histórico estão envolvidas. Dominá-lo significa ter controle total sobre a integridade do histórico de commits.
Referências
- Documentação oficial do Git - git-range-diff — Documentação completa com todas as opções e exemplos de uso do comando.
- Git range-diff: what is it and why you should use it — Artigo técnico explicando casos de uso práticos com exemplos detalhados.
- Comparing commits with git range-diff — Tutorial da Atlassian com exemplos visuais e cenários de code review.
- Git range-diff - A practical guide — Guia prático do GitButler com dicas avançadas e comparação com outras ferramentas de diff.
- How to use git range-diff effectively — Discussão no Stack Overflow com exemplos reais e soluções para problemas comuns.
- Git range-diff for rebase verification — Tutorial do freeCodeCamp focado em validação de rebase interativo com exemplos passo a passo.