ToolZen ToolZen
Text analyzer client

Text Diff

Compare two text blocks and highlight insertions, deletions, and unchanged lines side by side or inline.

Advertisement (Top Banner)
Added Removed Unchanged
Advertisement (Bottom)

Due testi che sembrano identici raramente lo sono, e trovare la differenza a occhio è un compito in cui gli umani sono spettacolarmente scarsi. Questo strumento confronta riga per riga e segna cosa è stato aggiunto e cosa rimosso. La parte interessante è che "cosa è cambiato" è una domanda con più di una risposta giusta.

La differenza invisibile che fa sembrare cambiato tutto

Se un diff dichiara che ogni singola riga è cambiata mentre il testo palesemente non lo è, la risposta sono quasi sempre i fine riga. Windows chiude le righe con un ritorno carrello più un avanzamento di riga; Unix, Linux e macOS usano il solo avanzamento. Entrambi non si vedono affatto sullo schermo.

L'effetto è totale. Spezza "uno\ndue\ntre" e "uno\r\ndue\r\ntre" in righe e ottieni ["uno","due","tre"] contro ["uno\r","due\r","tre\r"]: ogni riga ora porta un passeggero invisibile, e solo l'ultima, priva dell'interruzione finale, coincide. Una riga su tre. I testi sono gli stessi; i byte no.

È per questo che git ha le impostazioni autocrlf e per questo i team ci litigano. Se stai confrontando il file di un collega su Windows col tuo su un Mac, normalizza i fine riga prima di cercare un significato nel risultato.

Non esiste un diff corretto e basta

La cosa sorprende chi dà per scontato che un diff sia un fatto. Non lo è: è una risposta tra diverse ugualmente minime. Se una riga viene cancellata da una sequenza di righe identiche, niente nel testo dice quale sia sparita. L'algoritmo sceglie, e algoritmi diversi scelgono diversamente.

Aggiungi una funzione a un file sorgente e il diff può mostrare la tua nuova funzione come aggiunta, oppure può mostrare come aggiunta la tua graffa di chiusura e come rimossa quella della funzione successiva: entrambi sono minimi, uno solo è comprensibile. È esattamente il motivo per cui git offre più algoritmi: il predefinito Myers è veloce, mentre patience e histogram producono diff che si allineano meglio a come un umano vede la modifica. Nessuno è più corretto degli altri. Ottimizzano definizioni diverse di buona risposta.

Perché i confronti grandi sbattono contro un muro

L'algoritmo classico costruisce una tabella di ogni riga di A contro ogni riga di B, il che costa tempo e memoria proporzionali al prodotto delle due lunghezze. Due file da 12.000 righe chiedono una tabella da 144 milioni di celle: oltre un gigabyte di memoria e quasi due secondi di lavoro. Su un telefono è una scheda morta.

La salvezza è che i confronti veri sono raramente casuali. Due versioni di un documento condividono di solito una lunga testa e una lunga coda identiche, e quelle righe non hanno bisogno di nessuna tabella: sono uguali a colpo d'occhio. Toglierle per prime è la prima mossa di ogni implementazione diff seria, e su due file da 12.000 righe che differiscono in un punto porta la tabella da 144 milioni di celle a una manciata.

Questo copre il caso normale. Non aiuta quando due testi grandi sono genuinamente diversi ovunque, perché allora non c'è nessuna testa o coda comune da togliere. Questo strumento traccia lì una linea e te lo dice, invece di provarci e morire: se dopo il taglio il confronto è troppo grande, ricevi un messaggio. È una scelta voluta — uno strumento che ti congela il browser è peggio di uno che ammette i propri limiti.

Le righe sono la granularità sbagliata per la prosa

Questo strumento confronta righe intere, il che va bene per codice, configurazioni e qualsiasi cosa in cui una riga sia un'unità di senso. Va male per la prosa. Cambia una parola in un paragrafo che vive su una sola riga e il diff segnerà l'intero paragrafo come rimosso e riaggiunto: tecnicamente vero e praticamente inutile.

Il rimedio in quella situazione è lavorare con testo che abbia una frase per riga, oppure ricorrere a un diff a livello di parola. Vale la pena sapere quale dei due stai guardando: un diff a righe su un documento con testo a capo automatico ti dice che un paragrafo è cambiato, e niente su cosa sia cambiato dentro.

Domande frequenti

Il mio testo viene inviato a un server?

No. Questo strumento è marcato "client": entrambi i testi sono confrontati nella scheda del tuo browser e nessuno dei due lascia la macchina. Qui conta più del solito, perché confrontare due versioni di qualcosa significa che ne hai due versioni: contratti, bozze, file di configurazione con dentro le credenziali.

Perché dice che ogni riga è cambiata quando sembrano uguali?

I fine riga, quasi certamente — vedi sopra. L'altro candidato sono gli spazi in coda, altrettanto invisibili e altrettanto fatali per un confronto. Se il tuo editor sa mostrare i caratteri invisibili, attivalo e guarda la fine delle righe.

Perché c'è una riga vuota in più alla fine?

Perché il testo finisce con un'interruzione di riga. Spezzare "a\nb\n" sugli a capo produce tre pezzi: "a", "b" e una stringa vuota dopo l'ultima interruzione. Non è un bug del diff; è cosa significa un a capo finale. La convenzione Unix dice che i file di testo dovrebbero finire con uno, quindi è molto comune e di solito non vale la pena inseguirlo.

Può confrontare due file invece di testo incollato?

Non qui: questo è uno strumento da incolla. Per i file, e in particolare per qualsiasi cosa sotto controllo di versione, usa git diff: gestisce i fine riga, offre gli algoritmi migliori citati sopra, e sa mostrare le modifiche a livello di parola dentro una riga. Questo strumento è per il confronto veloce dove aprire un terminale è più fatica di quanta ne meriti la domanda.

Ignora gli spazi?

No. Ogni carattere conta, spazi in coda e indentazione inclusi. È il default giusto per uno strumento generico — a volte gli spazi sono esattamente la modifica che stai cercando — ma significa che un file reindentato risulterà completamente riscritto. Se è la tua situazione, git diff -w ignora gli spazi e ti mostra cosa si è mosso davvero.