Confrontatore di testo (Diff)
Confronta due testi e trova le differenze all'istante.
Informazioni sul confronto di testi
Questo strumento di diff usa l'algoritmo della più lunga sottosequenza comune (LCS) per confrontare due testi riga per riga. Le aggiunte sono evidenziate in verde e le eliminazioni in rosso. Scegli la vista «In linea» per vedere tutte le modifiche su una singola colonna, o «Fianco a fianco» per confrontare i testi originale e modificato in parallelo.
Usi comuni
- Confrontare modifiche di codice prima di fare un commit
- Rivedere documenti o contratti modificati
- Verificare differenze di traduzione
- Validare modifiche di file di configurazione
- Confrontare risposte di API
Domande frequenti
Confronta carattere per carattere?
Questo strumento confronta riga per riga. Se una riga ha la minima modifica (anche un singolo carattere), l'intera riga viene marcata come modificata. È lo stesso approccio usato da Git e dalla maggior parte degli strumenti di diff.
C'è un limite di dimensione?
Non c'è un limite rigido, ma testi molto grandi (più di 10.000 righe) possono richiedere un momento per essere elaborati, perché il confronto viene eseguito interamente nel tuo browser.
Cosa significa davvero «diff»
Un diff descrive come trasformare un testo in un altro usando il più piccolo insieme di inserimenti e cancellazioni. Ci sono infiniti modi per farlo, quello banale è «cancella ogni carattere di A e poi inserisci ogni carattere di B.» Un diff utile è lo script di modifica più corto, che è il duale del problema della più lunga sottosequenza comune: trovare la più lunga sequenza di righe che appare (nell'ordine) in entrambi i testi, e tutto il resto è un'aggiunta o una cancellazione. La maggior parte degli algoritmi di diff sono algoritmi LCS travestiti.
Un punto sottile: la più lunga sottosequenza comune non è la più lunga sottostringa comune. Una sottosequenza preserva l'ordine ma non l'adiacenza, quindi «ABCDE» e «AXBYCZD» condividono la sottosequenza «ABCD» anche se nessuna sequenza contigua di tre caratteri appare in entrambe.
Una breve storia degli algoritmi di diff
Il primo programma di confronto file ampiamente usato fu il diff di Unix scritto da Douglas McIlroy ai Bell Labs, con l'algoritmo sottostante pubblicato da James W. Hunt e McIlroy come Bell Labs Computing Science Technical Report #41 nel giugno 1976. McIlroy stesso descrisse i quattro mesi di sviluppo come «uno sforzo disperato.» L'approccio Hunt-McIlroy calcolava l'hash di ogni riga del file B, indicizzava dove compariva ogni riga unica, e cercava la più lunga catena di corrispondenze monotonicamente crescente. Fu distribuito in Version 6 Unix e rimase essenzialmente lo stesso algoritmo in /usr/bin/diff sulla maggior parte dei sistemi Unix per decenni.
Eugene W. Myers pubblicò lo standard industriale moderno nel 1986, «An O(ND) Difference Algorithm and Its Variations» in Algorithmica Vol. 1, No. 2. Myers riformulò LCS come un problema di cammino minimo attraverso un grafo di modifica: disponi A lungo l'asse superiore e B lungo il lato, traccia una diagonale ogni volta che due righe corrispondono, e cerca il cammino dall'angolo in alto a sinistra a quello in basso a destra con il minor numero di archi non diagonali. Ogni arco non diagonale è un inserimento o una cancellazione; ogni diagonale è gratuita. Fondamentale, l'algoritmo viene eseguito in tempo O((N+M)·D) dove D è la dimensione dello script di modifica, ovvero, diventa più veloce quanto più simili sono i file. Per i tipici diff del controllo di versione D è minuscolo rispetto a N+M, quindi Myers è enormemente più veloce del caso peggiore O(N·M) nella pratica. Il suo articolo include anche un perfezionamento a spazio lineare che usa un trucco divide-et-impera del «middle snake». L'algoritmo di Myers è quello predefinito alla base di GNU diff, git diff, Mercurial, Subversion, jsdiff, il difflib di Python, e la maggior parte dei visualizzatori di diff con interfaccia grafica.
Bram Cohen (poi più noto come l'inventore di BitTorrent) progettò il patience diff per il sistema di controllo di versione Bazaar intorno al 2002. Il problema motivante: il diff di Myers allinea qualsiasi riga corrispondente, comprese quelle molto comuni, quindi spostare una funzione in C può produrre un diff rumoroso in cui la parentesi graffa di chiusura della funzione spostata si allinea con la parentesi graffa di chiusura di una funzione non correlata. Il patience diff àncora il diff sulle righe che compaiono esattamente una volta in ciascun file (tipicamente firme di funzione, intestazioni di commento, messaggi di log distintivi), calcola l'LCS di solo quelle àncore usando il patience sort, e ricorre sugli spazi vuoti. Il risultato si allinea su righe significative e si legge meglio per il codice sorgente. Git lo supporta tramite git diff --patience. L'histogram diff è un perfezionamento aggiunto a git intorno al 2010 che costruisce un istogramma delle occorrenze delle righe e preferisce àncore a bassa frequenza anziché quelle strettamente uniche; da git 2.45 in poi è quello predefinito per molte configurazioni.
Levenshtein contro LCS
Un concetto correlato che vale la pena distinguere. La distanza di Levenshtein (Vladimir Levenshtein, 1965) conta il numero minimo di inserimenti, cancellazioni e sostituzioni di singoli caratteri per trasformare una stringa in un'altra. Il diff basato su LCS è strettamente correlato ma leggermente diverso: il diff classico tratta una «modifica» come una coppia cancella-poi-inserisci anziché una singola sostituzione, perché ciò si adatta meglio ai file orientati alle righe. Levenshtein risponde a «quanto sono diverse queste stringhe?» e ti dà un numero; LCS risponde a «cosa è cambiato di preciso?» e ti dà un effettivo script di modifica. I correttori ortografici e le funzioni «forse cercavi?» vogliono il primo; gli strumenti di diff vogliono il secondo. La variante Damerau-Levenshtein (1964) estende Levenshtein con un operatore di trasposizione per il rilevamento di errori di battitura.
Granularità: riga, parola e carattere
Il diff può essere calcolato a diverse granularità, ciascuna con i suoi compromessi:
- A livello di riga: ogni riga è un token; due righe o corrispondono esattamente o no. Veloce, si adatta in modo pulito al modo in cui i programmatori modificano il codice, produce patch concise che
patch(1)può applicare. Costo: riformattare un carattere in una riga di 200 caratteri segna l'intera riga come modificata. L'impostazione predefinita perdiff, git, SVN e questo strumento. - A livello di parola: ogni token delimitato da spazi è un'unità, quindi una riga che ha cambiato una parola mostra evidenziata solo quella parola. Eccellente per la prosa, i contratti, le bozze dei blog. Usato da
git diff --word-diff, la modalità «Suggesting» di Google Docs, «Track Changes» di Microsoft Word, la modalità confronto-parole di Diffchecker. - A livello di carattere: ogni code point Unicode è un'unità. Cattura gli errori di battitura di un singolo carattere, ideale per la revisione legale dove una sola parola può ribaltare il significato. Lento su input di grandi dimensioni e talvolta illeggibile per modifiche lunghe.
Uno schema comune nelle moderne interfacce di diff è calcolare prima il diff a livello di riga, poi per ogni coppia di «vicini rimossi/aggiunti» eseguire un diff secondario a livello di parola su solo quelle due righe ed evidenziare le modifiche all'interno della riga. È esattamente così che funzionano sia la vista PR di GitHub sia la libreria diff-match-patch.
Tre modalità di visualizzazione del diff che vedrai
- Unified diff (il formato di ogni file
.patch), blocchi introdotti da@@ -oldStart,oldLen +newStart,newLen @@con tre righe di contesto sopra e sotto per impostazione predefinita. Ebbe origine con il flag-udel GNU diff di Wayne Davison intorno al 1990. Compatto e leggibile dalla macchina tramitepatch(1), motivo per cui git, le patch via e-mail in stile kernel e SVN lo usano tutti. - Affiancato: originale a sinistra, modificato a destra, allineati riga per riga.
diff -yproduce una versione ASCII primitiva; Beyond Compare, Meld, WinMerge e la vista «Side by Side» qui sopra usano tutti questo formato. Ideale per la revisione visiva e la correzione di bozze di prosa. - In linea (impilato): una singola colonna dove le righe cancellate e aggiunte sono alternate. La vista PR di GitHub usa questa per impostazione predefinita. Il formato più efficiente in termini di spazio per schermi stretti e modifiche piccole.
Varianti utili di git diff
git diff: index rispetto al working tree.git diff --staged: HEAD rispetto all'index.git diff main..feature: le punte dei branch.main...featureconfronta rispetto alla base di merge, ciò che la PR andrà a integrare.git diff --word-diffe--color-words: diff a livello di parola adatto al markup e colorato.git diff --no-index a.txt b.txt: funziona su file al di fuori di qualsiasi repo git. Comodo come diff autonomo dei poveri con gli algoritmi patience o histogram.git diff -w: ignora tutti gli spazi bianchi (corrisponde alla casella «Ignore whitespace» qui sopra).git diff --histogram: cambia algoritmo per singolo comando.
Quando ricorreresti a un diff nel browser
- Revisione del codice. Incolla due versioni di un file, scorri per vedere cosa è cambiato, decidi se la modifica ha senso.
- Revisione di codice modificato dall'IA. Confronta il tuo originale con la versione rifattorizzata da un LLM per individuare deviazioni o allucinazioni.
- Revisione di contratti legali. Conferma che solo le clausole concordate siano cambiate tra la versione 3 e la versione 4.
- Controllo qualità delle traduzioni. Confronta due traduzioni francesi dello stesso paragrafo, o confronta i file di localizzazione precedenti e aggiornati quando solo una manciata di stringhe avrebbe dovuto cambiare.
- Deriva della configurazione. Confronta
nginx.confdi produzione con quello di staging. - Confronto di schemi SQL. Esporta le istruzioni
CREATE TABLEda due database e confrontale per trovare indici mancanti o derive del tipo di colonna. - Deriva delle specifiche. Confronta due versioni di uno YAML OpenAPI / Swagger per verificare che le modifiche che rompono la compatibilità siano documentate.
- Bozze di blog in Markdown. Individua cosa ha modificato un coautore.
- Audit di conformità. Confronta un'informativa sulla privacy mese dopo mese per i regolatori.
- Analisi forense dei lock-file. Confronta
package-lock.jsonoyarn.lockper capire un aggiornamento di dipendenza.
Limitazioni oneste
- Il diff di testo semplice non ha consapevolezza semantica. Rinominare
fooinbarin tutto un file sembra avere lo stesso costo di una riscrittura del tutto non correlata. Strumenti come difftastic analizzano l'AST del linguaggio e producono diff strutturali («funzione aggiunta,» «argomento riordinato»). Questa pagina no, è un semplice diff di righe basato su LCS. - Spazi bianchi e fine riga causano diff spuri. CRLF rispetto a LF, spazi bianchi finali, tab rispetto a spazi. L'interruttore «Ignore whitespace» qui sopra corrisponde al
-wdi git. - I file binari non si adattano. Il diff è un concetto testuale. Per il diff binario ci sono strumenti come
bsdiff,xdeltao VBinDiff. - Sensibilità all'ordine. Il diff di righe presuppone che i documenti siano stati modificati riga per riga. Per CSV non ordinati o riordinamenti delle chiavi di oggetti JSON, conviene prima ordinare o canonicalizzare.
- Rilevamento degli spostamenti. Il diff LCS classico non riconosce che una funzione è stata spostata all'interno di un file, mostra lo spostamento come una cancellazione più un inserimento. Beyond Compare, Meld e difftastic tentano il rilevamento degli spostamenti; questa pagina no.
Altre domande
Perché questa pagina non mostra evidenziazioni a livello di carattere all'interno delle righe modificate?
Perché il passaggio a livello di riga è sufficiente per la maggior parte dei casi d'uso e viene eseguito molto più velocemente su input lunghi. Per l'evidenziazione parola per parola all'interno della riga, il perfezionamento in due passaggi è prassi standard ma aggiunge latenza. Se l'intera differenza di riga è importante per te (revisione legale, correzione di bozze di prosa), uno strumento dedicato a livello di parola (incluso git diff --word-diff da riga di comando) è più adatto.
Qual è la differenza tra unified diff e affiancato?
Unified diff è il formato compatto e leggibile dalla macchina che ogni file .patch usa, tre righe di contesto, blocchi contrassegnati con @@. L'affiancato mostra le due versioni in colonne parallele, il che è più riposante per l'occhio nella revisione visiva ma occupa più spazio orizzontale. Unified è ciò che invieresti via e-mail o committeresti; l'affiancato è ciò che leggeresti su un monitor largo.
Esistono algoritmi migliori di Myers per il codice sorgente?
Per il codice sorgente con funzioni spostate o grandi riarrangiamenti, sì, il patience diff (Bram Cohen, 2002) e l'histogram diff (git, intorno al 2010) sono progettati per allinearsi su righe uniche significative anziché su quelle comuni, producendo un output più leggibile. Entrambi sono disponibili tramite git diff --patience e git diff --histogram. Gli strumenti consapevoli dell'AST come difftastic vanno oltre e analizzano l'effettiva struttura del linguaggio.
È sicuro incollare testo riservato qui?
Sì, il diff viene eseguito interamente nel tuo browser usando un'implementazione LCS in JavaScript. Nulla viene caricato, nessuna analisi sull'input, nessun log lato server del testo. Questa è l'unica categoria di strumento di diff sicura per gli NDA, il codice sorgente interno o le clausole contrattuali non rilasciate; i servizi di diff basati su cloud vedono qualunque cosa incolli.