Text Diff

Vergleiche zwei Texte nebeneinander und markiere Unterschiede zeilenweise

Beispiel ausprobieren

Text A

Text B

Läuft lokal · Sicher zum Einfügen von Secrets
Läuft lokal · Sicher zum Einfügen von Secrets

Was ist Text Diff?

Ein Text Diff (kurz für „Difference”, Unterschied) ist das Ergebnis des Vergleichs zweier Textblöcke, bei dem ermittelt wird, welche Zeilen hinzugefügt, entfernt oder unverändert geblieben sind. Das Konzept stammt vom Unix-diff-Dienstprogramm, das 1974 erstmals als Teil von Version 5 Unix veröffentlicht wurde. Heute ist Text Diff das Rückgrat von Versionskontrollsystemen wie Git, bei dem jeder Commit einen Diff speichert anstatt eine vollständige Kopie jeder Datei.

Ein Diff-Algorithmus findet die Longest Common Subsequence (LCS) zwischen zwei Zeilenfolgen. Zeilen, die in der LCS vorhanden sind, werden als unverändert markiert. Zeilen im Originaltext, die nicht in der LCS enthalten sind, werden als entfernt markiert. Zeilen im geänderten Text, die nicht in der LCS enthalten sind, werden als hinzugefügt markiert. Das Ergebnis ist ein minimaler Satz von Änderungen, der notwendig ist, um einen Text in den anderen umzuwandeln.

Diff-Ausgaben gibt es in verschiedenen Formaten. Unified diff (Standard für git diff) kennzeichnet entfernte Zeilen mit einem Minuszeichen und hinzugefügte Zeilen mit einem Pluszeichen. Side-by-side diff ordnet beide Texte in parallelen Spalten an. Dieses Tool verwendet einen zeilenweisen Vergleich mit farbcodierter Ausgabe: Grün für Ergänzungen, Rot für Entfernungen und Neutral für unveränderte Zeilen. Unveränderte Zeilen werden standardmäßig ohne Präfix angezeigt, können aber ausgeblendet werden, um sich nur auf das Geänderte zu konzentrieren.

Warum ein Online-Text-Diff-Tool verwenden?

Texte im Terminal zu vergleichen erfordert die Installation von diff-Dienstprogrammen und den Umgang mit Kommandozeilenoptionen. Ein browserbasiertes Diff-Tool beseitigt diese Hürden vollständig.

Sofortiger Vergleich
Zwei Textblöcke einfügen und Unterschiede sofort markiert sehen. Keine Datei-Erstellung, keine Befehle zu merken, keine Ausgabe zu parsen.
🔒
Datenschutz-zuerst
Der gesamte Vergleich findet im Browser mit JavaScript statt. Der Text verlässt das Gerät nie — wichtig beim Vergleich von Konfigurationsdateien, Zugangsdaten oder proprietärem Code.
📋
Kopierfertige Ausgabe
Die Diff-Ausgabe verwendet standardmäßige + / - Präfixe, die dem unified diff Format entsprechen. Das Ergebnis kann direkt in Commit-Nachrichten, Code-Review-Kommentare oder Fehlerberichte kopiert werden.
🌐
Keine Anmeldung oder Installation erforderlich
Funktioniert auf jedem Gerät mit einem Browser. Keine Kontoerstellung, keine Erweiterung, keine Desktop-App. Seite öffnen und sofort vergleichen.

Anwendungsfälle für Text Diff

Frontend-Entwicklung
Minifizierten CSS- oder HTML-Output vor und nach einem Build-Schritt vergleichen, um unbeabsichtigte Änderungen im generierten Markup oder den Styles zu erkennen.
Backend-Engineering
API-Antworten über Umgebungen hinweg vergleichen (Staging vs. Produktion), um zu überprüfen, ob ein Deployment unerwartete Datenänderungen eingeführt hat.
DevOps & Infrastruktur
Kubernetes-Manifeste, Terraform-Pläne oder Nginx-Konfigurationen vor der Anwendung auf einen Live-Cluster oder Server vergleichen.
QA & Testing
Test-Ausgaben mit erwarteten Baselines abgleichen, indem das tatsächliche Ergebnis mit einer gespeicherten Snapshot-Datei verglichen wird.
Data Engineering
CSV-Header oder SQL-Schemadefinitionen über Datenbank-Migrationen hinweg vergleichen, um zu bestätigen, dass Spalten korrekt hinzugefügt oder umbenannt wurden.
Lernen & Studium
Die eigene Lösung zeilenweise mit einer Referenzimplementierung vergleichen, um herauszufinden, wo die eigene Logik vom erwarteten Ansatz abweicht.

Diff-Ausgabeformate im Vergleich

Diff-Tools erzeugen Ausgaben in verschiedenen Formaten. Die folgende Tabelle fasst die gängigsten zusammen, was sie erzeugt und wann jedes Format nützlich ist.

FormatTool / QuelleBeschreibung
Unified diffdiff -u / git diffPrefixes lines with + / - / space; includes @@ hunk headers
Side-by-sidediff -y / sdiffTwo columns, changed lines aligned horizontally
Context diffdiff -cShows changed lines with surrounding context, marked with ! / + / -
HTML diffPython difflibColor-coded HTML table with inline change highlights
JSON PatchRFC 6902Array of add/remove/replace operations on a JSON document

Wie Zeilen-Diff funktioniert: Der LCS-Algorithmus

Die meisten Zeilen-Diff-Tools, einschließlich dieses, verwenden den Longest Common Subsequence (LCS) Algorithmus. LCS findet die größte Menge von Zeilen, die in beiden Texten in derselben relativen Reihenfolge vorkommen, ohne dass sie aufeinanderfolgend sein müssen. Die Zeilen, die nicht in der LCS enthalten sind, stellen die tatsächlichen Unterschiede dar.

Der Standard-LCS-Algorithmus verwendet dynamische Programmierung und läuft in O(m x n) Zeit, wobei m und n die Zeilenanzahlen der beiden Texte sind. Bei großen Dateien reduzieren optimierte Varianten wie Myers' Diff-Algorithmus (von Git verwendet) dies auf O(n + d^2), wobei d die Anzahl der Unterschiede ist — was ihn schnell macht, wenn die meisten Zeilen übereinstimmen.

1. DP-Tabelle aufbauen
Eine (m+1) x (n+1) Matrix erstellen. Für jedes Zeilenpaar die Länge der bisher längsten gemeinsamen Teilfolge speichern. Gleiche Zeilen erhöhen den Diagonalwert um 1.
2. Rückverfolgung
Von der unteren rechten Ecke der Matrix zurück zu (0,0) gehen. Diagonale Schritte bei gleichen Zeilen erzeugen Einträge „unverändert”. Horizontale oder vertikale Schritte erzeugen Einträge „hinzugefügt” oder „entfernt”.
3. Ausgabe rendern
Jeden Eintrag einer Anzeigezeile zuordnen: unveränderte Zeilen erhalten kein Präfix, hinzugefügte Zeilen erhalten +, entfernte Zeilen erhalten -. Farbcodierung für visuelle Übersichtlichkeit anwenden.

Code-Beispiele

Implementierungen des zeilenweisen Textvergleichs in JavaScript, Python, Go und der Kommandozeile. Jedes Beispiel erzeugt eine Ausgabe im unified-diff-Stil.

JavaScript
// Line-by-line diff using the LCS algorithm
function diffLines(a, b) {
  const linesA = a.split('\n')
  const linesB = b.split('\n')

  // Build LCS table
  const m = linesA.length, n = linesB.length
  const dp = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0))
  for (let i = 1; i <= m; i++)
    for (let j = 1; j <= n; j++)
      dp[i][j] = linesA[i-1] === linesB[j-1]
        ? dp[i-1][j-1] + 1
        : Math.max(dp[i-1][j], dp[i][j-1])

  // Backtrack to produce diff
  const result = []
  let i = m, j = n
  while (i > 0 || j > 0) {
    if (i > 0 && j > 0 && linesA[i-1] === linesB[j-1]) {
      result.unshift({ type: 'equal', text: linesA[i-1] }); i--; j--
    } else if (j > 0 && (i === 0 || dp[i][j-1] >= dp[i-1][j])) {
      result.unshift({ type: 'add', text: linesB[j-1] }); j--
    } else {
      result.unshift({ type: 'remove', text: linesA[i-1] }); i--
    }
  }
  return result
}

const diff = diffLines("alpha\nbeta\ngamma", "alpha\nbeta changed\ngamma\ndelta")
// → [
//   { type: 'equal',  text: 'alpha' },
//   { type: 'remove', text: 'beta' },
//   { type: 'add',    text: 'beta changed' },
//   { type: 'equal',  text: 'gamma' },
//   { type: 'add',    text: 'delta' }
// ]
Python
import difflib

text_a = """alpha
beta
gamma""".splitlines()

text_b = """alpha
beta changed
gamma
delta""".splitlines()

# Unified diff (same format as git diff)
for line in difflib.unified_diff(text_a, text_b, fromfile='a.txt', tofile='b.txt', lineterm=''):
    print(line)
# --- a.txt
# +++ b.txt
# @@ -1,3 +1,4 @@
#  alpha
# -beta
# +beta changed
#  gamma
# +delta

# HTML side-by-side diff
d = difflib.HtmlDiff()
html = d.make_file(text_a, text_b, fromdesc='Original', todesc='Modified')
Go
package main

import (
	"fmt"
	"strings"
)

// Minimal LCS-based line diff
func diffLines(a, b string) {
	la := strings.Split(a, "\n")
	lb := strings.Split(b, "\n")
	m, n := len(la), len(lb)

	dp := make([][]int, m+1)
	for i := range dp {
		dp[i] = make([]int, n+1)
	}
	for i := 1; i <= m; i++ {
		for j := 1; j <= n; j++ {
			if la[i-1] == lb[j-1] {
				dp[i][j] = dp[i-1][j-1] + 1
			} else if dp[i-1][j] >= dp[i][j-1] {
				dp[i][j] = dp[i-1][j]
			} else {
				dp[i][j] = dp[i][j-1]
			}
		}
	}

	var result []string
	i, j := m, n
	for i > 0 || j > 0 {
		if i > 0 && j > 0 && la[i-1] == lb[j-1] {
			result = append([]string{" " + la[i-1]}, result...)
			i--; j--
		} else if j > 0 && (i == 0 || dp[i][j-1] >= dp[i-1][j]) {
			result = append([]string{"+" + lb[j-1]}, result...)
			j--
		} else {
			result = append([]string{"-" + la[i-1]}, result...)
			i--
		}
	}

	for _, line := range result {
		fmt.Println(line)
	}
}

// Output:
//  alpha
// -beta
// +beta changed
//  gamma
// +delta
CLI (diff / git)
# Compare two files with unified diff (3 lines of context)
diff -u original.txt modified.txt

# Git diff between working tree and last commit
git diff HEAD -- file.txt

# Git diff between two branches
git diff main..feature -- src/

# Side-by-side diff in the terminal
diff -y --width=120 original.txt modified.txt

# Color-coded diff (requires colordiff)
diff -u original.txt modified.txt | colordiff

Häufig gestellte Fragen

Was ist der Unterschied zwischen einem Zeilen-Diff und einem Zeichen-Diff?
Ein Zeilen-Diff vergleicht Text zeilenweise: Wenn sich ein beliebiges Zeichen einer Zeile ändert, wird die gesamte Zeile als entfernt markiert und die neue Version als hinzugefügt. Ein Zeichen-Diff (oder Wort-Diff) arbeitet auf einer feineren Granularitätsebene und markiert die spezifischen Zeichen oder Wörter, die sich innerhalb einer Zeile geändert haben. Zeilen-Diff ist Standard für Code-Reviews; Zeichen-Diff ist nützlicher für die Bearbeitung von Fließtext.
Wie funktioniert git diff intern?
Git verwendet standardmäßig Myers' Diff-Algorithmus, der das kürzeste Bearbeitungsskript (die minimale Anzahl von Einfügungen und Löschungen) zwischen zwei Dateien findet. Git speichert das Ergebnis im unified diff Format mit @@ Hunk-Headern, die Zeilennummern angeben. Wenn git diff ausgeführt wird, vergleicht Git den Arbeitsbereich mit dem Index (Staging Area), nicht dem letzten Commit, außer HEAD wird explizit übergeben.
Kann ich Binärdateien mit einem Text-Diff-Tool vergleichen?
Nein. Text-Diff-Tools teilen die Eingabe an Zeilenumbruchzeichen auf und vergleichen Strings. Binärdateien enthalten beliebige Byte-Sequenzen, die bedeutungslose Zeilenaufteilungen erzeugen. Für binäre Vergleiche sollte ein Hex-Diff-Tool oder ein Prüfsummenvergleich auf Dateiebene verwendet werden (sha256sum auf beiden Dateien).
Werden meine Daten an einen Server gesendet, wenn ich dieses Tool verwende?
Nein. Dieses Tool läuft vollständig im Browser. Die Diff-Berechnung verwendet eine JavaScript-LCS-Implementierung, die clientseitig ausgeführt wird. Es werden keine Netzwerkanfragen mit dem Textinhalt durchgeführt. Dies kann durch Öffnen des Netzwerk-Tabs im Browser während der Nutzung des Tools überprüft werden.
Was ist das unified diff Format?
Unified diff ist das Ausgabeformat von diff -u und git diff. Es zeigt geänderte Zeilen mit den Präfixen - (entfernt) und + (hinzugefügt), preceded von @@ Headern, die die Zeilennummerbereiche in beiden Dateien angeben. Kontextzeilen (unverändert) haben ein Leerzeichen als Präfix. Unified diff ist das gebräuchlichste Format für Patches, Pull Requests und Code-Review-Tools.
Wie vergleiche ich große Dateien mit vielen Unterschieden?
Bei Dateien mit Tausenden von Zeilen funktioniert ein browserbasiertes Tool, kann aber langsamer werden, da der LCS-Algorithmus quadratisch skaliert. Bei sehr großen Diffs sind Kommandozeilen-Tools wie diff oder git diff schneller, da sie optimierte C-Implementierungen verwenden und Ausgaben streamen können. Unveränderte Zeilen können auch herausgefiltert werden (Option „Unveränderte Zeilen zeigen” deaktivieren), um sich nur auf Änderungen zu konzentrieren.
Was ist ein Three-Way-Merge-Diff?
Ein Three-Way-Merge vergleicht zwei geänderte Versionen einer Datei mit ihrem gemeinsamen Vorgänger (der Basis). Git verwendet dies während git merge und git rebase. Es identifiziert Änderungen, die in jedem Branch relativ zur Basis vorgenommen wurden, und kombiniert sie. Wenn beide Branches dieselbe Zeile ändern, meldet Git einen Merge-Konflikt. Three-Way-Merge benötigt drei Eingaben, während ein Standard-Diff nur zwei benötigt.