Comparar dois arquivos

Ilimitado arquivos. Comparações em tempo real. Gratuitamente, para sempre.
Original
Alterado

Privado e seguro

Tudo acontece no seu navegador. Seus arquivos nunca tocam nossos servidores.

Incrivelmente rápido

Sem upload, sem espera. Converta no momento em que você solta um arquivo.

Realmente grátis

Nenhuma conta necessária. Sem custos ocultos. Sem truques de tamanho de arquivo.

“Diffs” são a língua franca da mudança. São as narrativas compactas que lhe dizem o que se moveu entre duas versões de uma coisa — código-fonte, prosa, um conjunto de dados — sem forçá-lo a reler tudo. Por trás desses poucos símbolos (+, -, @@) vive uma pilha profunda de algoritmos, heurísticas e formatos que equilibram otimalidade, velocidade e compreensão humana. Este artigo é um tour prático, de algoritmos a fluxos de trabalho, de diffs: como são computados, como são formatados, como as ferramentas de fusão os usam e como ajustá-los para melhores revisões. Ao longo do caminho, fundamentaremos as alegações em fontes primárias e documentos oficiais — porque pequenos detalhes (como se o espaço em branco conta) realmente importam.

O que um “diff” realmente é

Formalmente, um diff descreve um script de edição mais curto (SES) para transformar uma sequência “antiga” em uma “nova” usando inserções e exclusões (e às vezes substituições, que podem ser modeladas como excluir+inserir). Na prática, a maioria dos diffs voltados para programadores sãoorientados por linha e, em seguida, opcionalmente refinados para palavras ou caracteres para legibilidade. As saídas canônicas são os formatos contexto e unificado ; este último — o que você geralmente vê na revisão de código — comprime a saída com um cabeçalho conciso e “hunks”, cada um mostrando uma vizinhança de contexto em torno das mudanças. O formato unificado é selecionado via -u/--unified и является стандартом де-факто para aplicar patches; patch geralmente se beneficia de linhas de contexto para aplicar mudanças de forma robusta.

O manual do GNU diff cataloga os interruptores que você procura quando quer menos ruído e mais sinal — ignorando espaços em branco, expandindo tabulações para alinhamento ou pedindo um script de edição “mínimo”, mesmo que seja mais lento (referência de opções). Essas opções não mudam o que significa para dois arquivos diferirem; elas mudam o quão agressivamente o algoritmo busca por scripts menores e como o resultado éapresentado aos humanos.

Do LCS ao Myers: como os diffs são computados

A maioria dos diffs de texto é construída sobre a abstração da Subsequência Comum Mais Longa (LCS) . A programação dinâmica clássica resolve o LCS em tempo e espaço O(mn), mas isso é muito lento e consome muita memória para arquivos grandes. O algoritmo de Hirschberg mostrou como calcular alinhamentos ótimos em espaço linear (ainda tempo O(mn)) usando dividir e conquistar, uma técnica fundamental de economia de espaço que influenciou as implementações práticas de diff.

Para velocidade e qualidade, o avanço foi o algoritmo de Eugene W. Myers de 1986, que encontra um SES em tempo O(ND) (N ≈ linhas totais, D ≈ distância de edição) e espaço quase linear. Myers modela edições em um “gráfico de edição” e avança ao longo das fronteiras de maior alcance, produzindo resultados que são rápidos e próximos do mínimo no cenário de diff de linha. É por isso que “Myers” permanece o padrão em muitas ferramentas.

Há também a família Hunt–Szymanski , que acelera o LCS quando poucas posições correspondem (pré-indexando correspondências e perseguindo subsequências crescentes), e está historicamente ligada às primeiras variantes do diff. Esses algoritmos iluminam as compensações: em entradas com correspondências esparsas, eles podem ser executados de forma subquadrática. Para uma visão geral do praticante que une teoria e implementação, veja as notas de Neil Fraser.

Quando o “ótimo” não é legível: estratégias de paciência e histograma

Myers visa scripts de edição mínimos, mas “mínimo” ≠ “mais legível”. Blocos grandes reordenados ou duplicados podem enganar um algoritmo SES puro em alinhamentos desajeitados. Entre patience diff, atribuído a Bram Cohen: ele se ancora em linhas únicas e de baixa frequência para estabilizar os alinhamentos, muitas vezes produzindo diffs que os humanos acham mais limpos — especialmente em código com funções movidas ou blocos reorganizados. Muitas ferramentas expõem isso por meio de uma opção de “paciência” (por exemplo,diff.algorithm).

Histogram diff estende a paciência com um histograma de frequência para lidar melhor com elementos de baixa ocorrência, mantendo-se rápido (popularizado em JGit). Se você já descobriu que --histogram produz hunks mais claros para arquivos ruidosos, isso é por design. No Git moderno, você pode escolher o algoritmo globalmente ou por invocação:git config diff.algorithm myers|patience|histogram ou git diff --patience.

Clareza no nível da palavra, controle de espaço em branco e destaque de código movido

Diffs de linha são concisos, mas podem obscurecer pequenas edições. Diffs no nível da palavra (--word-diff) colorem as alterações dentro da linha sem inundar a revisão com inserções/exclusões de linha inteira — ótimo para prosa, strings longas ou de uma linha.

O espaço em branco pode inundar os diffs após a reformatação. Tanto o Git quanto o GNU diff permitem que você ignore as alterações de espaço em diferentes graus e as opções de espaço em branco do GNU diff (-b, -w, -B) ajudam quando um formatador é executado; você verá edições lógicas em vez de ruído de alinhamento.

Quando o código se move por atacado, o Git pode destacar blocos movidos com --color-moved, separando visualmente “movido” de “modificado”, o que ajuda os revisores a auditar que um movimento não escondeu edições não intencionais. Persista-o via diff.colorMoved.

Diffs a serviço de fusões: bidirecional vs. tridirecional e diff3

Um diff bidirecional compara exatamente duas versões; ele não pode dizer se ambos os lados editaram a mesma linha de base, então muitas vezes entra em conflito excessivo. A fusão tridirecional (usada por VCSs modernos) calcula diffs de um ancestral comumpara cada lado e, em seguida, reconcilia os dois conjuntos de alterações. Isso reduz drasticamente conflitos espúrios e fornece um contexto melhor. O núcleo algorítmico clássico aqui é diff3, que mescla alterações de “O” (base) para “A” e “B” e marca conflitos quando necessário.

O trabalho acadêmico e industrial continua a formalizar e melhorar a correção da fusão; por exemplo, fusões tridirecionais verificadas propõem noções semânticas de ausência de conflito. No dia a dia do Git, a moderna estratégia de fusão ort se baseia em diffing e detecção de renomeação para produzir fusões com menos surpresas. Para os usuários, as dicas principais são: mostrar linhas de base em conflitos com merge.conflictStyle=diff3, e integrar com frequência para que os diffs permaneçam pequenos.

Detecção de renomeação e seus limites

Diffs tradicionais не podem “ver” renomeações porque o endereçamento de conteúdo trata os arquivos como blobs; eles só veem uma exclusão e uma adição. As heurísticas de detecção de renomeação preenchem essa lacuna comparando a similaridade entre os pares adicionados/removidos. No Git, ative ou ajuste via -M/--find-renames[=<n>] (o padrão é ~50% de similaridade). Diminua-o para movimentos mais ruidosos. Você pode limitar as comparações de candidatos com diff.renameLimit (e merge.renameLimit durante as fusões). Para seguir o histórico através de renomeações, use git log --follow -- <path>. O Git recente também executa a detecção de renomeação de diretório para propagar movimentos de pasta durante as fusões.

Diffs binários e delta: rsync, VCDIFF/xdelta, bsdiff

O texto não é a única coisa que muda. Para binários, você normalmente quer codificação delta — emita instruções de cópia/adição para reconstruir um alvo a partir de uma fonte. O algoritmo rsync foi pioneiro na diferenciação remota eficiente usando somas de verificação rolantes para alinhar blocos em uma rede, minimizando a largura de banda.

O IETF padronizou um formato delta genérico, VCDIFF (RFC 3284), descrevendo um bytecode de ADD, COPY e RUN, com implementações como xdelta3 usando-o para patches binários. Para patches compactos em executáveis, bsdiff muitas vezes produz deltas muito pequenos por meio de matrizes de sufixos e compressão; escolha-o quando o tamanho do patch domina e a geração pode ocorrer offline.

Diffs de texto além do código-fonte: correspondência difusa e aplicação de patches

Quando você precisa de patches robustos em face de edições simultâneas ou contextos ligeiramente desalinhados — pense em editores ou sistemas colaborativos — considere diff-match-patch. Ele une a diferenciação no estilo Myers com Bitap correspondência difusa para encontrar correspondências próximas e aplicar patches “da melhor maneira possível”, além de acelerações pré-diff e limpezas pós-diff que trocam um pouco de minimalismo por uma saída humana mais agradável. Para saber como combinar diff e patch difuso em loops de sincronização contínua, consulte a Sincronização Diferencialde Fraser.

Diffs de dados estruturados: tabelas e árvores

Diffs de linha em CSV/TSV são frágeis porque uma alteração de uma célula pode parecer uma edição de linha inteira. Ferramentas de diff com reconhecimento de tabela (daff) tratam os dados como linhas/colunas, emitindo patches que visam células específicas e renderizando visualizações que tornam adições, exclusões e modificações óbvias (veja a vinheta R). Para verificações rápidas, diferenciadores de CSV especializados podem destacar alterações célula por célula e mudanças de tipo; eles não são algoritmicamente exóticos, mas aumentam o sinal de revisãocomparando a estrutura que você realmente se importa.

Ajuste prático do Git diff: uma lista de verificação do revisor

Como as fusões realmente consomem diffs (e o que fazer quando não o fazem)

Uma fusão calcula dois diffs (BASE→NOSSO, BASE→DELES) e tenta aplicar ambos ao BASE. Estratégias como ort orquestram isso em escala, incorporando detecção de renomeação (incluindo movimentos em escala de diretório) e heurísticas para minimizar conflitos. Quando ocorrem conflitos, --conflict=diff3 enriquece os marcadores com o contexto base, que é inestimável para entender a intenção. O capítulo do Pro Git sobre Fusão Avançada percorre os padrões de resolução, e os documentos do Git listam botões como -X ours e -X theirs. Para economizar tempo em conflitos recorrentes, ative rerere para gravar и reproduzir suas resoluções.

Além dos arquivos: cenários remotos e incrementais

Se você está sincronizando grandes ativos por uma rede, está mais perto do rsync mundo do que do diff local. O Rsync calcula somas de verificação rolantes para descobrir blocos correspondentes remotamente, e então transfere apenas o que é necessário. Para deltas empacotados, VCDIFF/xdelta lhe dá um bytecode padrão e ferramentas maduras; escolha-o quando você controla tanto o codificador quanto o decodificador. E se o tamanho do patch for primordial (por exemplo, firmware over-the-air), bsdiff troca CPU/memória no momento da construção por patches muito pequenos.

Uma palavra rápida sobre “difuso” e “amigável”

Bibliotecas como diff-match-patch aceitam que, no mundo real, o arquivo que você está aplicando o patch pode ter se desviado. Ao combinar um diff sólido (geralmente Myers) com correspondência difusa (Bitap) e regras de limpeza configuráveis, eles podem encontrar o lugar certo para aplicar um patch e tornar o diff mais legível — crítico para edição colaborativa e sincronização.

As “apostas da mesa” que você deve internalizar

  1. Conheça seus formatos. Diffs unificados (-u/-U<n>) são compactos e amigáveis para patches; são o que a revisão de código e a CI esperam (referência).
  2. Conheça seus algoritmos. Myers para edições mínimas rápidas (artigo); paciência/histograma para legibilidade em reordenações ou blocos ruidosos (paciência, histograma); Hirschberg para o truque do espaço linear (artigo); Hunt–Szymanski para aceleração de correspondência esparsa (artigo).
  3. Conheça seus interruptores. Controles de espaço em branco, word-diff e color-moved são multiplicadores de revisão (documentos do git diff; opções de espaço em branco do GNU).
  4. Conheça suas fusões. Tridirecional com diff3 -estilo é menos confuso; ort mais detecção de renomeação reduz a rotatividade; rerere economiza tempo.
  5. Escolha a ferramenta certa para os dados. Para CSV/tabelas, use daff; para binários, use VCDIFF/xdelta ou bsdiff.

Apêndice: pequeno livro de receitas de comandos

Porque a memória muscular importa:

# Mostrar um diff unificado padrão com contexto extra
  git diff -U5
  diff -u -U5 a b
  
  # Obter clareza no nível da palavra para linhas longas ou prosa
  git diff --word-diff
  
  # Ignorar ruído de espaço em branco após a reformatação
  git diff -b -w --ignore-blank-lines
  diff -b -w -B a b
  
  # Destacar código movido durante a revisão
  git diff --color-moved
  git config --global diff.colorMoved default
  
  # Domar refatorações com detecção de renomeação e seguir o histórico através de renomeações
  git diff -M
  git log --follow -- <file>
  
  # Preferir algoritmo para legibilidade
  git diff --patience
  git diff --histogram
  git config --global diff.algorithm patience
  
  # Ver linhas de base em marcadores de conflito
  git config --global merge.conflictStyle diff3

Pensamento final

Grandes diffs são menos sobre provar a minimalidade e mais sobre maximizar a compreensão do revisor com o mínimo de custo cognitivo. É por isso que o ecossistema evoluiu vários algoritmos (Myers, paciência, histograma), várias apresentações (unificado, word-diff, color-moved) e ferramentas com reconhecimento de domínio (daff para tabelas, xdelta/bsdiff para binários). Aprenda as compensações, ajuste os botões e você passará mais tempo raciocinando sobre a intenção e menos tempo remontando o contexto a partir de linhas vermelhas e verdes.


Referências selecionadas e leitura adicional

Perguntas Frequentes

O que é um diff?

Um diff é uma ferramenta ou funcionalidade utilizada em sistemas de controle de versão para destacar as diferenças entre duas versões ou instâncias de um arquivo. É normalmente usado para rastrear alterações ou atualizações feitas ao arquivo ao longo do tempo.

Como um diff compara dois arquivos?

Um diff compara dois arquivos linha por linha. Ele examina e corresponde cada linha no primeiro arquivo com sua contraparte no segundo arquivo, notando todas as diferenças significativas, como adições, exclusões ou alterações.

O que é um patch no contexto dos diffs?

Um patch é um arquivo que contém as diferenças entre dois arquivos, produzido pela ferramenta diff. Ele pode ser aplicado a uma versão de um arquivo com o comando 'patch' para atualizá-lo para uma versão mais recente.

O que são diffs unificados?

Os diffs unificados são um tipo de formato de arquivo diff que apresenta mudanças em um formato de arquivo adequado para arquivos de texto. Ele mostra exclusões do arquivo original com um prefixo '-', e adições ao original são prefixadas com um '+'.

Por que diffs são cruciais nos sistemas de controle de versão?

Os diffs são cruciais nos sistemas de controle de versão porque permitem às equipes rastrear as mudanças feitas em um arquivo ao longo do tempo. Este rastreamento facilita a manutenção da consistência, evita a duplicação de trabalho, identifica erros ou discrepâncias e gerencia várias versões de arquivos de maneira eficiente.

O que é o algoritmo LCS em ferramentas diff?

O algoritmo Longest Common Subsequence (LCS) é um método comum usado nas ferramentas diff para encontrar a sequência mais longa de caracteres que aparece da esquerda para a direita em ambos os arquivos originais e modificados. Este algoritmo auxilia na identificação das principais semelhanças e diferenças entre dois arquivos.

As ferramentas diff podem comparar arquivos binários?

A maioria das ferramentas diff básicas só pode comparar arquivos de texto. No entanto, ferramentas diff especializadas são projetadas para comparar arquivos binários, exibindo as diferenças em um formato legível.

Quais são algumas ferramentas diff comuns em uso hoje?

Algumas das ferramentas diff mais populares incluem GNU diff, DiffMerge, KDiff3, WinMerge (Windows) e FileMerge (Mac). Muitos Ambientes de Desenvolvimento Integrado (IDEs) também incluem utilitários diff embutidos.

Como posso criar um diff no Git?

No Git, você pode criar um diff usando o comando `git diff` seguido pelas duas versões dos arquivos que deseja comparar. A saída mostrará as diferenças entre os dois arquivos.

Posso usar ferramentas diff com diretórios, não apenas arquivos?

Sim, muitas ferramentas diff têm a capacidade de comparar diretórios, além de arquivos individuais. Esta funcionalidade pode ser particularmente útil ao comparar versões de um grande projeto com vários arquivos.