Comparando os mesmos dois arquivos, o resultado pode variar conforme o algoritmo de diff. Todos são diffs "corretos", mas mudam as linhas que cada um decide parear como iguais, e com isso muda a facilidade de leitura. O git oferece quatro opções pelo parâmetro --diff-algorithm.
| Valor | Descrição na documentação do git | Característica |
|---|---|---|
myers (default) | Algoritmo guloso (greedy) básico, o padrão atual | Rápido e geralmente próximo do mínimo |
minimal | Gasta mais tempo para produzir o menor diff possível | Sempre mínimo, pode ser lento com entradas grandes |
patience | Algoritmo patience diff | Usa linhas únicas como pontos de ancoragem |
histogram | Estende o patience para suportar elementos comuns de baixa ocorrência | Usa linhas raras como pontos de ancoragem |
Também há as formas curtas, como git diff --patience e git diff --histogram, e é possível mudar o padrão com git config diff.algorithm histogram.
Myers: o padrão que busca a edição mínima
O algoritmo de Myers procura o caminho que minimiza o número de remoções e inserções (o princípio está em Como o diff funciona). O problema aparece quando há várias opções de quais linhas considerar iguais. Código tem muitas linhas extremamente comuns, como }, {, linhas em branco e return, e o algoritmo pode parear linhas sem relação de sentido mantendo o mesmo número mínimo de edições.
A mesma mudança, dois resultados
Suponha que uma nova função h foi inserida entre as funções f e g, como abaixo. Os dois diffs a seguir têm o mesmo número de edições: 4 linhas adicionadas.
@@ -1,6 +1,10 @@ int f() { return 1; }++int h() {+ return 3;+} int g() { return 2;
@@ -1,5 +1,9 @@ int f() { return 1;+}++int h() {+ return 3; } int g() {
No primeiro, a nova função aparece inteira; no segundo, a chave de fechamento da função existente f foi tratada como a chave da nova função, e o trecho adicionado ficou cortado de um jeito estranho. Esse formato surge da ordem de busca, e as versões recentes do git corrigem boa parte dos casos com uma heurística que desloca as fronteiras do trecho alterado olhando a indentação (--indent-heuristic, ativa por padrão).
Patience: primeiro alinhar as linhas únicas
O patience diff, proposto por Bram Cohen, começa procurando as linhas que aparecem exatamente uma vez em cada um dos dois arquivos. Uma linha única, como a declaração de função int h() {, tem um par inequívoco. Dessas linhas únicas, escolhe a maior lista em ordem compatível (a maior subsequência crescente) como pontos de ancoragem e compara de novo apenas os pequenos trechos entre eles.
- Vantagem: não se deixa levar por linhas comuns como
}ou linhas em branco, então mudanças em funções ou parágrafos aparecem como blocos. - Desvantagem: em entradas quase sem linhas únicas (dados com linhas repetidas, logs), não encontra pontos de ancoragem e fica igual a um diff comum, ou pode até agrupar tudo em blocos grandes.
Histogram: prioridade às linhas raras
O algoritmo histogram foi desenvolvido no JGit (uma implementação do git em Java) e depois incorporado ao git. Enquanto o patience só considera "linhas que aparecem exatamente uma vez", o histogram conta quantas vezes cada linha aparece e escolhe as menos frequentes como pontos de ancoragem. Assim, mesmo sem linhas únicas, pode usar como referência as linhas relativamente raras. A documentação do git descreve isso como "estende o algoritmo patience para suportar elementos comuns de baixa ocorrência". Na prática, costuma produzir resultados que preservam bem a estrutura do código, parecidos com os do patience.
Qual usar
- Revisão de código do dia a dia: o padrão basta. Se o resultado parecer cortado de forma estranha, veja de novo com
--histogram. - Grandes refatorações, com funções movidas ou várias funções adicionadas:
--histogramou--patiencemantêm melhor os blocos. - Quando é preciso contar exatamente o mínimo de linhas alteradas:
--minimal. - Arquivos de dados com muita repetição: ordenar e normalizar pode importar mais que o algoritmo. Para JSON, veja Como comparar JSON.
Seja qual for o algoritmo, o arquivo resultante é reconstruído da mesma forma. O que muda é apenas a aparência para quem lê.
Nesta ferramenta
Este site compara as linhas com um algoritmo da família Myers, depois avalia a semelhança de conteúdo entre as linhas alteradas para parear as "modificadas" e compara de novo o interior delas. Por isso, mesmo que o resultado por linha fique cortado de forma um pouco estranha, dá para ver na hora qual palavra mudou. Cole o exemplo acima no comparador de textos e compare como ele aparece nas visualizações unificada e lado a lado. A forma de ler o resultado está em Como ler um unified diff.