diff - diff
Autor (es) original (is) |
Douglas McIlroy ( AT&T Bell Laboratories ) |
---|---|
Desenvolvedor (s) | Vários open-source e comerciais desenvolvedores |
lançamento inicial | Junho de 1974 |
Sistema operacional | Unix , semelhante ao Unix , V , Plan 9 , Inferno |
Plataforma | Plataforma cruzada |
Modelo | Comando |
Na computação , o utilitário diff é uma ferramenta de comparação de dados que calcula e exibe as diferenças entre o conteúdo dos arquivos. Ao contrário das noções de distância de edição usadas para outros propósitos, diff é orientado por linha em vez de por caractere, mas é como a distância de Levenshtein, pois tenta determinar o menor conjunto de exclusões e inserções para criar um arquivo a partir do outro. O utilitário exibe as alterações em um dos vários formatos padrão, de forma que humanos ou computadores possam analisar as alterações e usá-las para correção .
Normalmente, diff é usado para mostrar as mudanças entre duas versões do mesmo arquivo. Implementações modernas também oferecem suporte a arquivos binários . A saída é chamada de "diff" ou patch , já que a saída pode ser aplicada com o patch do programa Unix . A saída de utilitários de comparação de arquivos semelhantes também é chamada de "diff"; assim como o uso da palavra " grep " para descrever o ato de pesquisar, a palavra diff tornou-se um termo genérico para calcular a diferença de dados e seus resultados. O padrão POSIX especifica o comportamento dos utilitários "diff" e "patch" e seus formatos de arquivo.
História
diff foi desenvolvido no início dos anos 1970 no sistema operacional Unix, que estava surgindo no Bell Labs em Murray Hill, New Jersey. A primeira versão lançada foi enviada com a 5ª edição do Unix em 1974 e foi escrita por Douglas McIlroy e James Hunt . Esta pesquisa foi publicada em um artigo de 1976 co-escrito com James W. Hunt, que desenvolveu um protótipo inicial de diff . O algoritmo descrito neste artigo ficou conhecido como algoritmo Hunt – Szymanski .
O trabalho de McIlroy foi precedido e influenciado pelo programa de comparação de Steve Johnson no GECOS e pelo programa de prova de Mike Lesk . A prova também se originou no Unix e, como diff , produziu mudanças linha por linha e até usou colchetes angulares (">" e "<") para apresentar inserções e exclusões de linha na saída do programa. As heurísticas usadas nessas aplicações iniciais foram, no entanto, consideradas não confiáveis. A utilidade potencial de uma ferramenta diff levou McIlroy a pesquisar e projetar uma ferramenta mais robusta que pudesse ser usada em uma variedade de tarefas, mas funcionasse bem nas limitações de processamento e tamanho do hardware do PDP-11 . Sua abordagem ao problema resultou da colaboração também com indivíduos da Bell Labs, incluindo Alfred Aho , Elliot Pinson, Jeffrey Ullman e Harold S. Stone.
No contexto do Unix, o uso do editor de linha ed proporcionou ao diff a habilidade natural de criar "scripts de edição" utilizáveis por máquina. Esses scripts de edição, quando salvos em um arquivo, podem, junto com o arquivo original, ser reconstituídos por ed no arquivo modificado em sua totalidade. Isso reduziu muito o armazenamento secundário necessário para manter várias versões de um arquivo. McIlroy considerou escrever um pós-processador para diff onde uma variedade de formatos de saída poderiam ser projetados e implementados, mas ele achou mais frugal e mais simples ter diff ser responsável por gerar a sintaxe e entrada de ordem reversa aceita pelo comando ed .
No final de 1984 Larry parede criado um serviço separada, remendo , libertando o seu código de fonte nas mod.sources e net.sources grupos de notícias. Este programa generalizou e estendeu a capacidade de modificar arquivos com saída do diff .
Os modos no Emacs também permitem converter o formato dos patches e até mesmo editar os patches interativamente.
Nos primeiros anos do diff , os usos comuns incluíam a comparação de mudanças na fonte do código do software e marcação para documentos técnicos, verificação da saída de depuração do programa, comparação das listagens do sistema de arquivos e análise do código de montagem do computador. A saída direcionada para ed foi motivada a fornecer compactação para uma sequência de modificações feitas em um arquivo. O Source Code Control System (SCCS) e sua capacidade de arquivar revisões surgiram no final dos anos 1970 como consequência do armazenamento de scripts de edição do diff .
Algoritmo
A operação de diff é baseada na resolução do problema de subsequência comum mais longo .
Neste problema, dadas duas sequências de itens:
a b c d f g h j q z
a b c d e f g i j k r x y z
e queremos encontrar uma sequência de itens mais longa que esteja presente em ambas as sequências originais na mesma ordem. Ou seja, queremos encontrar uma nova sequência que pode ser obtida a partir da primeira sequência original, excluindo alguns itens, e da segunda sequência original, excluindo outros itens. Também queremos que essa sequência seja a mais longa possível. Neste caso é
a b c d f g j z
De uma subseqüência comum mais longa, é apenas um pequeno passo para obter uma saída do tipo diff : se um item está ausente na subsequência, mas presente na primeira seqüência original, ele deve ter sido excluído (conforme indicado pelas marcas '-', abaixo ) Se estiver ausente na subsequência, mas presente na segunda sequência original, deve ter sido inserido (conforme indicado pelas marcas '+').
e h i q k r x y + - + - + + + +
Uso
O diff
comando é chamado a partir da linha de comando, passando-os nomes de dois arquivos: . A saída do comando representa as alterações necessárias para transformar o arquivo original no novo arquivo.
diff original new
Se original e novo forem diretórios, então diff será executado em cada arquivo que existe em ambos os diretórios. Uma opção, -r
irá descer recursivamente quaisquer subdiretórios correspondentes para comparar os arquivos entre os diretórios.
Qualquer um dos exemplos do artigo usa os dois arquivos a seguir, original e novo :
original : This part of the
document has stayed the
same from version to
version. It shouldn't
be shown if it doesn't
change. Otherwise, that
would not be helping to
compress the size of the
changes.
This paragraph contains
text that is outdated.
It will be deleted in the
near future.
It is important to spell
check this dokument. On
the other hand, a
misspelled word isn't
the end of the world.
Nothing in the rest of
this paragraph needs to
be changed. Things can
be added after it.
|
novo : This is an important
notice! It should
therefore be located at
the beginning of this
document!
This part of the
document has stayed the
same from version to
version. It shouldn't
be shown if it doesn't
change. Otherwise, that
would not be helping to
compress the size of the
changes.
It is important to spell
check this document. On
the other hand, a
misspelled word isn't
the end of the world.
Nothing in the rest of
this paragraph needs to
be changed. Things can
be added after it.
This paragraph contains
important new additions
to this document.
|
O comando 0a1,6 > Este é um importante > observe! Deveria > portanto, esteja localizado em > o início deste > documento! > 11,15d16 <Este parágrafo contém <texto desatualizado. <Será excluído do <futuro próximo. < 17c18 <verifique este dokument. Sobre --- > verifique este documento. Sobre 24a26,29 > > Este parágrafo contém > novas adições importantes > a este documento. Nota: aqui, a saída diff é mostrada com cores para facilitar a leitura. O utilitário diff não produz saída colorida; sua saída é texto simples . No entanto, muitas ferramentas podem mostrar a saída com cores usando o realce de sintaxe . |
Neste formato de saída tradicional, umasignifica adicionado ,dpara excluído ecpara mudou . Os números de linha do arquivo original aparecem antesuma/d/ce os do novo arquivo aparecem depois. Os sinais de menor que e maior que (no início das linhas que são adicionadas, excluídas ou alteradas) indicam em qual arquivo as linhas aparecem. Linhas de adição são adicionadas ao arquivo original para aparecer no novo arquivo. As linhas de exclusão são excluídas do arquivo original para ficarem ausentes no novo arquivo.
Por padrão, as linhas comuns a ambos os arquivos não são mostradas. As linhas que foram movidas são mostradas conforme adicionadas em seu novo local e como excluídas de seu antigo local. No entanto, algumas ferramentas diff destacam as linhas movidas.
Saída variações
Editar script
Um script ed ainda pode ser gerado por versões modernas do diff com a -e
opção. O script de edição resultante para este exemplo é o seguinte:
24a This paragraph contains important new additions to this document. . 17c check this document. On . 11,15d 0a This is an important notice! It should therefore be located at the beginning of this document! .
Para transformar o conteúdo do arquivo original no conteúdo do arquivo novo usando ed , devemos acrescentar duas linhas a este arquivo diff, uma linha contendo um w
comando (escrever) e outra contendo um q
comando (sair) (por exemplo, por ). Aqui, demos ao arquivo diff o nome mydiff e a transformação acontecerá quando executarmos .
printf "w\nq\n" >> mydiff
ed -s original < mydiff
Formato de contexto
A distribuição do Unix em Berkeley fez questão de adicionar o formato de contexto ( -c
) e a capacidade de recorrer às estruturas de diretório do sistema de arquivos ( -r
), adicionando esses recursos no 2.8 BSD, lançado em julho de 1981. O formato de contexto do diff introduzido em Berkeley ajudou na distribuição patches para código-fonte que podem ter sido alterados minimamente.
No formato de contexto, todas as linhas alteradas são mostradas ao lado das linhas inalteradas antes e depois. A inclusão de qualquer número de linhas inalteradas fornece um contexto para o patch. O contexto consiste em linhas que não mudaram entre os dois arquivos e servem como uma referência para localizar o lugar das linhas em um arquivo modificado e encontrar o local pretendido para uma mudança a ser aplicada, independentemente de os números das linhas ainda corresponderem. O formato de contexto apresenta maior legibilidade para humanos e confiabilidade ao aplicar o patch, e uma saída que é aceita como entrada para o programa de patch . Este comportamento inteligente não é possível com a saída tradicional do diff.
O número de linhas inalteradas mostrado acima e abaixo de um pedaço de mudança pode ser definido pelo usuário, até mesmo zero, mas três linhas normalmente é o padrão. Se o contexto de linhas inalteradas em um pedaço se sobrepõe a um pedaço adjacente, o diff evitará duplicar as linhas inalteradas e mesclar os pedaços em um único pedaço.
Um " !
" representa uma mudança entre as linhas que correspondem nos dois arquivos. Um " +
" representa a adição de uma linha, enquanto um espaço em branco representa uma linha inalterada. No início do patch estão as informações do arquivo, incluindo o caminho completo e um carimbo de data / hora delimitado por um caractere de tabulação. No início de cada pedaço estão os números das linhas que se aplicam à alteração correspondente nos arquivos. Um intervalo de número que aparece entre conjuntos de três asteriscos se aplica ao arquivo original, enquanto conjuntos de três traços se aplicam ao novo arquivo. Os intervalos de pedaços especificam os números de linha inicial e final no respectivo arquivo.
O comando diff -c original new
produz a seguinte saída:
*** /path/to/original timestamp
--- /path/to/new timestamp
***************
*** 1,3 ****
--- 1,9 ----
+ This is an important
+ notice! It should
+ therefore be located at
+ the beginning of this
+ document!
+
This part of the
document has stayed the
same from version to
***************
*** 8,20 ****
compress the size of the
changes.
- This paragraph contains
- text that is outdated.
- It will be deleted in the
- near future.
It is important to spell
! check this dokument. On
the other hand, a
misspelled word isn't
the end of the world.
--- 14,21 ----
compress the size of the
changes.
It is important to spell
! check this document. On
the other hand, a
misspelled word isn't
the end of the world.
***************
*** 22,24 ****
--- 23,29 ----
this paragraph needs to
be changed. Things can
be added after it.
+
+ This paragraph contains
+ important new additions
+ to this document.
Nota: aqui, a saída diff é mostrada com cores para facilitar a leitura. O utilitário diff não produz saída colorida; sua saída é texto simples . No entanto, muitas ferramentas podem mostrar a saída com cores usando o realce de sintaxe .
Formato unificado
O formato unificado (ou unidiff ) herda as melhorias técnicas feitas pelo formato de contexto, mas produz um diff menor com texto antigo e novo apresentados imediatamente adjacentes. O formato unificado geralmente é chamado usando a opção de linha de comando " -u
" . Esta saída é freqüentemente usada como entrada para o programa de patch . Muitos projetos solicitam especificamente que "diffs" sejam submetidos no formato unificado, tornando o formato diff unificado o formato mais comum para troca entre desenvolvedores de software.
As diferenças de contexto unificadas foram originalmente desenvolvidas por Wayne Davison em agosto de 1990 (em unidiff que apareceu no Volume 14 de comp.sources.misc). Richard Stallman adicionou suporte a diff unificado ao utilitário diff do Projeto GNU um mês depois, e o recurso estreou no GNU diff 1.15, lançado em janeiro de 1991. Desde então, o GNU diff generalizou o formato de contexto para permitir a formatação arbitrária de diffs.
O formato começa com o mesmo cabeçalho de duas linhas do formato de contexto, exceto que o arquivo original é precedido por "---"e o novo arquivo é precedido por"+++". Em seguida, estão um ou mais blocos de alteração que contêm as diferenças de linha no arquivo. As linhas contextuais inalteradas são precedidas por um caractere de espaço, as linhas de adição são precedidas por um sinal de mais e as linhas de exclusão são precedidas por um sinal de menos .
Um pedaço começa com as informações do intervalo e é imediatamente seguido pelas adições e exclusões de linhas e qualquer número de linhas contextuais. A informação do intervalo é circundada por dois sinais de arroba e combina em uma única linha o que aparece em duas linhas no formato de contexto ( acima ). O formato da linha de informação do intervalo é o seguinte:
@@ -l,s +l,s @@ optional section heading
As informações de intervalo de trechos contêm dois intervalos de trechos. O intervalo do pedaço do arquivo original é precedido por um símbolo de menos e o intervalo do novo arquivo é precedido por um símbolo de mais. Cada intervalo de trecho tem o formato l, s, em que l é o número da linha inicial es é o número de linhas ao qual o trecho de alteração se aplica para cada arquivo respectivo. Em muitas versões do GNU diff, cada intervalo pode omitir a vírgula e o valor final s , em cujo caso o padrão é 1. Observe que o único valor realmente interessante é o número da linha l do primeiro intervalo; todos os outros valores podem ser calculados a partir do diff.
O intervalo do pedaço para o original deve ser a soma de todas as linhas contextuais e de exclusão (incluindo as alteradas). O intervalo de pedaços para o novo arquivo deve ser uma soma de todas as linhas contextuais e adicionais (incluindo as alteradas). Se as informações do tamanho do trecho não corresponderem ao número de linhas no trecho, o diff pode ser considerado inválido e rejeitado.
Opcionalmente, o intervalo do pedaço pode ser seguido pelo título da seção ou função da qual o pedaço faz parte. Isso é útil principalmente para tornar o diff mais fácil de ler. Ao criar um diff com o diff GNU, o título é identificado pela correspondência de expressão regular .
Se uma linha for modificada, ela será representada como uma exclusão e adição. Como os pedaços do arquivo original e do novo aparecem no mesmo pedaço, essas alterações apareceriam adjacentes um ao outro. Uma ocorrência disso no exemplo abaixo é:
-check this dokument. On +check this document. On
O comando diff -u original new
produz a seguinte saída:
--- /path/to/original timestamp
+++ /path/to/new timestamp
@@ -1,3 +1,9 @@
+This is an important
+notice! It should
+therefore be located at
+the beginning of this
+document!
+
This part of the
document has stayed the
same from version to
@@ -8,13 +14,8 @@
compress the size of the
changes.
-This paragraph contains
-text that is outdated.
-It will be deleted in the
-near future.
-
It is important to spell
-check this dokument. On
+check this document. On
the other hand, a
misspelled word isn't
the end of the world.
@@ -22,3 +23,7 @@
this paragraph needs to
be changed. Things can
be added after it.
+
+This paragraph contains
+important new additions
+to this document.
Nota: aqui, a saída diff é mostrada com cores para facilitar a leitura. O utilitário diff não produz saída colorida; sua saída é texto simples . No entanto, muitas ferramentas podem mostrar a saída com cores usando o realce de sintaxe .
Observe que, para separar com êxito os nomes dos arquivos dos carimbos de data / hora, o delimitador entre eles é um caractere de tabulação. Isso é invisível na tela e pode ser perdido quando os diffs são copiados / colados das telas do console / terminal.
Existem algumas modificações e extensões para os formatos diff que são usados e compreendidos por certos programas e em certos contextos. Por exemplo, alguns sistemas de controle de revisão - como o Subversion - especificam um número de versão, "cópia de trabalho" ou qualquer outro comentário ao invés de ou em adição a um timestamp na seção de cabeçalho do diff.
Algumas ferramentas permitem que diffs para vários arquivos diferentes sejam mesclados em um, usando um cabeçalho para cada arquivo modificado que pode ser semelhante a este:
Index: path/to/file.cpp
O caso especial de arquivos que não terminam em uma nova linha não é tratado. Nem o utilitário unidiff nem o padrão POSIX diff definem uma maneira de lidar com este tipo de arquivos. (Na verdade, esses arquivos não são arquivos de "texto" por definições POSIX estritas.) O programa de patch não está ciente nem mesmo de uma saída de diff específica de implementação.
As mudanças desde 1975 incluem melhorias no algoritmo principal, a adição de recursos úteis ao comando e o design de novos formatos de saída. O algoritmo básico é descrito nos artigos An O (ND) Difference Algorithm and its Variations, de Eugene W. Myers, e em A File Comparison Program, de Webb Miller e Myers. O algoritmo foi descoberto e descrito independentemente em Algorithms for Approximate String Matching , de Esko Ukkonen . As primeiras edições do programa diff foram projetadas para comparações de linhas de arquivos de texto esperando o caractere de nova linha para delimitar as linhas. Na década de 1980, o suporte para arquivos binários resultou em uma mudança no design e na implementação do aplicativo.
GNU diff e diff3 estão incluídos no pacote diffutils com outros utilitários relacionados a diff e patch . Hoje em dia também existe um pacote patchutils que pode combinar, reorganizar, comparar e corrigir diffs de contexto e diffs unificados.
Formatadores e front-ends
Os pós-processadores sdiff e diffmk renderizam listagens de diff lado a lado e marcas de alteração aplicadas a documentos impressos, respectivamente. Ambos foram desenvolvidos em outro lugar no Bell Labs em ou antes de 1981.
O Diff3 compara um arquivo com dois outros arquivos, reconciliando dois diffs. Ele foi originalmente concebido por Paul Jensen para reconciliar as alterações feitas por duas pessoas que editaram uma fonte comum. Ele também é usado por sistemas de controle de revisão, por exemplo , RCS , para fusão .
Emacs tem Ediff para mostrar as mudanças que um patch forneceria em uma interface de usuário que combina edição interativa e recursos de mesclagem para arquivos de patch.
O Vim fornece o vimdiff para comparar de dois a oito arquivos, com diferenças destacadas em cores. Embora historicamente invocando o programa diff, vim moderna usa git 's garfo de biblioteca xdiff (LibXDiff) código, proporcionando maior velocidade e funcionalidade.
GNU Wdiff é um front end para diff que mostra as palavras ou frases que mudaram em um documento de texto da linguagem escrita, mesmo na presença de quebra de linha ou larguras de coluna diferentes.
colordiff é um wrapper Perl para 'diff' e produz a mesma saída, mas com realce de 'sintaxe'.
Derivados algorítmicos
Utilitários que comparam arquivos de origem por sua estrutura sintática foram construídos principalmente como ferramentas de pesquisa para algumas linguagens de programação; alguns estão disponíveis como ferramentas comerciais. Além disso, as ferramentas gratuitas que realizam diferenças com base na sintaxe incluem:
- C ++: zograscope, baseado em AST.
- HTML: Daisydiff, html-differ.
- XML: xmldiffpatch da Microsoft e xmldiffmerge para IBM.
- JavaScript : astii (baseado em AST).
- Multi-idioma: Pretty Diff (formato de código e, em seguida, diff)
spiff é uma variante do diff que ignora as diferenças nos cálculos de ponto flutuante com erros de arredondamento e espaços em branco , ambos geralmente irrelevantes para a comparação do código-fonte. Bellcore escreveu a versão original. Uma porta HPUX é a versão pública mais recente. spiff não oferece suporte a arquivos binários. O spiff gera a saída padrão no formato diff padrão e aceita entradas nas linguagens de programação C , Bourne shell , Fortran , Modula-2 e Lisp .
LibXDiff é uma biblioteca LGPL que fornece uma interface para muitos algoritmos de 1998. Um algoritmo Myers aprimorado com impressão digital Rabin foi implementado originalmente (na versão final de 2008), mas o fork do git e libgit2 expandiu o repositório com muitos dos seu próprio. Um algoritmo chamado "histograma" é geralmente considerado muito melhor do que o algoritmo de Myers original, tanto em velocidade quanto em qualidade. Esta é a versão moderna do LibXDiff usado pelo Vim.
Veja também
- Comparação de ferramentas de comparação de arquivos
- Codificação delta
- Operador de diferença
- Editar distância
- Histórico de gerenciamento de configuração de software
- Problema de subsequência comum mais longo
- Comparação de arquivos da Microsoft
- Controle de revisão
- Gerenciamento de configuração de software
Outras ferramentas gratuitas de comparação de arquivos
Referências
Leitura adicional
- Paul Heckel (abril de 1978). "Uma técnica para isolar diferenças entre arquivos". Comunicações da ACM . 21 (4): 264–268. doi : 10.1145 / 359460.359467 . S2CID 207683976 .Uma técnica para isolar diferenças entre arquivos
- Uma implementação genérica do algoritmo Myers SES / LCS com o refinamento de espaço linear de Hirschberg (código-fonte C)
links externos
- The Single UNIX Specification , Issue 7 from The Open Group : compare dois arquivos - Commands & Utilities Reference,
- Plano 9 , Volume 1 - Manual do programador do
- Manual de comandos gerais do Inferno -
- Comparação de arquivos no Curlie
- Implementação de JavaScript