diff vergleicht zwei Files zeilenweise und meldet, welche Zeilen sich unterscheiden, hinzugekommen oder entfernt sind. Die Ausgabe lässt sich in mehreren Formaten erzeugen — vom kompakten Normal-Format bis zum Unified-Format, das als De-facto-Standard für Patches gilt und sich direkt mit patch einspielen lässt. diff -r arbeitet rekursiv über ganze Verzeichnisbäume, was es zum unverzichtbaren Werkzeug für Code-Reviews, Backups und Konfigurationsabgleiche macht.
Was diff macht
diff liest zwei Eingaben — zwei Files, ein File und stdin (-), oder zwei Verzeichnisse — und berechnet die minimalen Änderungen, mit denen sich die erste Eingabe in die zweite überführen lässt. Die Ausgabe ist deterministisch, maschinenlesbar und in mehreren Formaten verfügbar.
Typische Einsatzgebiete:
- Code-Reviews ohne Versionskontrolle — schnell prüfen, was sich zwischen zwei Files geändert hat
- Patch-Erzeugung —
diff -u alt neu > fix.patchproduziert einen Patch, denpatcheinspielen kann - Konfigurationsabgleich — z. B.
/etc/nginx/nginx.confvor und nach einem Update vergleichen - Verzeichnisse synchronisieren —
diff -r dir1 dir2 --briefzeigt Unterschiede auf Datei-Ebene - Skript-Logik — Exit-Code 0/1/2 lässt sich in
if-Bedingungen direkt nutzen
Default-Output (Normal-Format)
Ohne weitere Optionen liefert diff das Normal-Format. Zeilen aus dem ersten File werden mit < markiert, Zeilen aus dem zweiten File mit >. Davor steht ein Hunk-Header, der die betroffenen Zeilennummern und die Art der Änderung beschreibt: c für change, a für append, d für delete.
diff alt.txt neu.txt1c1
< Hallo Welt
---
> Hallo Linux
3a4
> Neue Zeile am EndeLesart: In Zeile 1 wurde der Inhalt geändert (1c1), nach Zeile 3 wurde an Position 4 etwas angehängt (3a4). Ein Block wie 4d3 würde bedeuten, dass Zeile 4 aus dem ersten File gelöscht wurde und im zweiten File hinter Position 3 fehlt.
Wichtige Optionen
| Option | Wirkung |
|---|---|
-u, --unified | Unified-Format mit Kontext — Standard für Patches |
-c, --context | Klassisches Context-Format mit drei Zeilen Kontext |
-y, --side-by-side | Zweispaltige Darstellung nebeneinander |
-r, --recursive | Rekursiver Vergleich zweier Verzeichnisse |
-q, --brief | Nur melden, dass sich Files unterscheiden, nicht wie |
-i, --ignore-case | Groß-/Kleinschreibung ignorieren |
-w, --ignore-all-space | Sämtliche Whitespace-Unterschiede ignorieren |
-B, --ignore-blank-lines | Reine Leerzeilen-Unterschiede ausblenden |
--color=auto | Farbige Ausgabe im Terminal |
-N, --new-file | Fehlende Files wie leere Files behandeln (wichtig für Patches) |
-x PATTERN | Files/Pfade mit Muster vom Vergleich ausschließen |
-s | Auch melden, wenn Files identisch sind |
Unified-Format -u
Das Unified-Format ist der De-facto-Standard für Patches und das Format, das git diff, GitHub und patch lesen. Jeder Hunk beginnt mit einem Header der Form @@ -L,N +L,N @@: links die Zeilen aus dem alten File (Start L, Anzahl N), rechts die aus dem neuen.
diff -u alt.txt neu.txt--- alt.txt 2026-05-04 10:00:00.000000000 +0200
+++ neu.txt 2026-05-04 10:05:00.000000000 +0200
@@ -1,3 +1,4 @@
-Hallo Welt
+Hallo Linux
Zweite Zeile
Dritte Zeile
+Neue Zeile am EndeZeilen mit - stammen aus dem alten File, Zeilen mit + aus dem neuen, Zeilen ohne Präfix sind Kontext (per Default drei Zeilen vor und nach jeder Änderung). Der gesamte Output lässt sich in eine Datei umlenken und mit patch < fix.patch wieder einspielen.
Verzeichnisse vergleichen
Mit -r arbeitet diff rekursiv durch zwei Verzeichnisbäume. Kombiniert mit --brief bekommst du eine reine Übersicht, welche Files sich unterscheiden, ohne jeden Hunk zu sehen.
diff -r --brief --exclude='.git' projektA projektBFiles projektA/README.md and projektB/README.md differ
Only in projektB: CHANGELOG.md
Files projektA/src/main.go and projektB/src/main.go differ-x PATTERN (oder das ausführliche --exclude=PATTERN) blendet Pfade aus — typisch sind .git, node_modules, dist oder *.log. Mehrere -x-Flags sind erlaubt. Mit -N werden Files, die nur in einem Baum existieren, behandelt, als wären sie auf der anderen Seite leer — das ergibt sauberere Patches über ganze Projekte.
Praxis-Patterns
Patch erzeugen und einspielen. Der klassische Workflow für Patches ohne Git:
diff -u alt.conf neu.conf > fix.patch
patch alt.conf < fix.patchSchnell prüfen, ob zwei Files identisch sind. Mit -q wird nur eine kurze Meldung erzeugt, der Exit-Code reicht für Skripte:
diff -q a.txt b.txt && echo "identisch" || echo "unterschiedlich"Side-by-Side ohne Rauschen. -y --suppress-common-lines zeigt nur die Zeilen, die sich tatsächlich unterscheiden — viel übersichtlicher bei langen Files:
diff -y --suppress-common-lines alt.txt neu.txtFarbiger Diff. Mit --color=auto wird die Ausgabe im Terminal eingefärbt. Für noch hübschere Ausgabe gibt es colordiff als Wrapper:
diff --color=auto -u alt.txt neu.txt
colordiff -u alt.txt neu.txtdiff vs. git diff vs. cmp
| Werkzeug | Granularität | Typischer Use-Case | Format |
|---|---|---|---|
diff | Zeilenweise, Text | Beliebige zwei Files/Verzeichnisse vergleichen | Normal, Unified, Context, Side-by-Side |
git diff | Zeilenweise, Text | Änderungen im Git-Repo (Working Tree, Index, Commits) | Unified mit Git-Erweiterungen |
cmp | Byte für Byte, binär | Binär-Files, Backups, Image-Vergleich | Erste Abweichung oder alle Bytes |
Für reine Text-Files reicht diff fast immer. Sobald du ein Git-Repo verwaltest, ist git diff ergonomischer (Index, Stash, Branches). Für Binär-Files ist cmp das richtige Werkzeug — diff quittiert sie mit Binary files ... differ und liefert keine Details.
Besonderheiten
Exit-Code als Skript-Signal: 0, 1, 2
diff setzt drei klar definierte Exit-Codes: 0 wenn die Eingaben gleich sind, 1 wenn sie sich unterscheiden, 2 bei einem echten Fehler (Datei nicht lesbar, Pfad existiert nicht). Diese Trennung ist gold wert für Skripte: if diff -q a b; then ... reagiert nur auf Identität, [ $? -eq 2 ] lässt sich für Fehlerbehandlung nutzen. Viele Tools vermischen Exit-Code 1 und 2 — diff nicht.
Unified-Format hat per Default drei Kontextzeilen
Mit -u bekommst du -u3 — drei Zeilen Kontext vor und nach jedem Hunk. Für engere oder breitere Patches lässt sich der Wert anpassen, etwa diff -u5 oder diff -U0 (überhaupt kein Kontext). Bei sehr kleinen Änderungen in großen Files kann -U0 die Patch-Datei drastisch verkürzen — überlappende Hunks werden dann allerdings nicht zusammengefasst und Patches sind sensibler gegenüber Verschiebungen.
Speicherhungrig bei sehr großen Files
diff lädt seine Eingaben in den Speicher und berechnet einen optimalen Diff über einen Algorithmus auf Basis der längsten gemeinsamen Teilfolge. Bei mehreren Hundert MB pro File kann das den RAM sprengen. Für Logfiles oder Datenbank-Dumps lohnt es sich, vorher mit head/tail/split einzugrenzen oder direkt auf zeilensortierte Vergleiche mit comm zu wechseln.
Binär-Files werden abgelehnt
Sobald diff ein NUL-Byte in einer Eingabe findet, schaltet es um auf Binary files A and B differ und gibt keinen Inhalt aus. Mit --text lässt sich der Vergleich erzwingen, das Ergebnis ist aber selten lesbar. Für Binär-Files ist cmp (Byte-Vergleich) oder die Kombination xxd a | diff - <(xxd b) der bessere Weg — letzterer liefert einen Hex-Dump-Diff, in dem du die Abweichungen tatsächlich sehen kannst.
Whitespace-Optionen unterscheiden sich von git diff
diff -w ignoriert alle Whitespace-Unterschiede, -b nur Mengenunterschiede, -B nur Leerzeilen, --ignore-trailing-space nur Trailing Spaces. git diff kennt mit -w, -b, --ignore-blank-lines ähnliche, aber nicht 1:1 deckungsgleiche Schalter. Wenn du Diffs zwischen Tools austauschst, lohnt es sich, die exakten Whitespace-Regeln zu prüfen — sonst wundert man sich, warum derselbe Patch in einem Werkzeug sauber ist und im anderen Konflikte erzeugt.
Reihenfolgewechsel sehen oft chaotisch aus
Wenn du in einem File nur zwei Blöcke vertauschst, produziert diff häufig einen riesigen Hunk: Es markiert den ersten Block als gelöscht und denselben Block weiter unten als hinzugefügt — plus die Zwischenzeilen als Kontext. Das ist algorithmisch korrekt, optisch aber irreführend. Tools wie git diff --color-moved oder dedizierte Move-Detector erkennen Verschiebungen explizit; diff kann das nicht.
Weiterführende Ressourcen
Externe Quellen
- diff(1) – Linux manual page (man7.org) — offizielle Dokumentation aller diff-Optionen
- GNU diffutils Manual — ausführliches Handbuch zu diff, cmp, sdiff, diff3
- GNU patch Manual — wie sich diff-Output mit patch einspielen lässt
Verwandte Artikel
- cmp – Byte-genauer Binär-Vergleich — Wenn diff bei Binär-Files passt
- sort – Zeilen sortieren — Vorbereitung für saubere Diffs unsortierter Listen
- grep – Muster in Text suchen — Punktuelle Suche statt vollständigem Vergleich
- sed – Textströme bearbeiten — Patches programmatisch erzeugen und anwenden
- find – Files im Verzeichnisbaum finden — Vorfilterung, bevor diff -r alles vergleicht