2 Punkte von GN⁺ 2025-06-05 | 1 Kommentare | Auf WhatsApp teilen
  • Das bestehende Unified-Diff-Format hat Grenzen und bildet die Anforderungen moderner Entwicklungsumgebungen nicht vollständig ab
  • DiffX ist mit dem bestehenden Format vollständig kompatibel und bietet eine zukunftsorientierte Struktur sowie erweiterbare Metadaten
  • Mehrere Commit-Informationen und Binärdateien sowie Zeichenkodierung und Metadaten lassen sich strukturiert speichern
  • Durch standardisierte Parsing-Regeln können verschiedene Werkzeuge (Patches, Code-Review usw.) leicht angebunden werden
  • In bestehenden Tools und Workflows lässt sich das Format problemlos verwenden; nur für neue Funktionen ist Unterstützung durch die jeweiligen Tools nötig

Entwickler und Diff-Dateien

  • Softwareentwickler prüfen Codeänderungen in der Regel über Diff-Dateien aus Git, Subversion, CVS usw.
  • Diff-Dateien enthalten Texteinfügungen (+) und -löschungen (-) sowie Dateinamen, Pfade, Zeitstempel und einige Metadaten
  • Die meisten Werkzeuge und Nutzer verwenden das Format Unified Diff, das Unterschiede vergleichsweise einfach visualisiert

Grenzen von Unified Diff

  • Unified Diff standardisiert nur Dateiidentifikation, Änderungsbereiche sowie eingefügte und gelöschte Zeilen, nicht aber Kodierung, Revisionen oder erweiterte Metadaten
  • Dadurch sind die Unterstützung verschiedener Versionsverwaltungssysteme, zuverlässiges Parsing und die Extraktion umfangreicher Informationen schwierig
  • Immer wieder treten unter anderem folgende Probleme auf
    • Mehrere Commits können nicht auf einmal dargestellt werden
    • Es fehlt ein eigener Standard für Binärdateien
    • Ohne Kenntnis der Zeichenkodierung kommt es zu Informationsverlust und Verwirrung
    • Für beliebige Metadaten fehlt eine Standardisierung, weshalb jedes Tool eigene Formen nutzt

Richtung der Verbesserung

  • Das bestehende Unified Diff verfügt zwar über wenig Struktur und Standardisierung, ist aber flexibel und in vielen Umgebungen bereits weit verbreitet
  • Git Diff fungiert faktisch als Standard, dennoch fehlt es dem Format weiterhin an einer offiziellen Spezifikation und allgemeiner Erweiterbarkeit
  • Daher wächst der Bedarf an einem neuen Format, das die Stärken von Unified Diff beibehält und zugleich Erweiterbarkeit sowie eine standardisierte Struktur bietet

Was ist DiffX?

  • DiffX ist ein erweiterbares Diff-Format, das mit bestehenden Werkzeugen vollständig kompatibel ist, die Lesbarkeit für Menschen bewahrt und gleichzeitig Metadaten und Struktur geordnet aufnehmen kann
  • Syntaxbeispiele:
    • Für Dateien, Commits und den gesamten Diff lassen sich Metadaten und Inhalte mithilfe einer strukturierten, erweiterbaren Methode speichern
    • In der Beispielausgabe erscheinen Syntaxelemente wie #diffx: sowie Sections, Metadaten (JSON), Dateipfade und Commit-Informationen

Zentrale Merkmale von DiffX

  • Bietet standardisierte Parsing-Regeln, damit Tools Informationen zuverlässig lesen und schreiben können
  • Offizielle Unterstützung für das Speichern und Verwalten von Metadaten: auf Ebene des gesamten Diff, von Commits und von Dateien
  • Kompatibel mit bestehenden Tools wie Parsern, Patchern und Code-Review-Werkzeugen (neue Funktionen benötigen Unterstützung, bestehende Funktionen bleiben kompatibel)
  • In einer Datei lassen sich mehrere Commits, binäre Diffs, Informationen zur Textkodierung und weitere Inhalte in einer effizienten Struktur darstellen
  • Unterstützt Mutability: Tools können einen Diff öffnen, benötigte Informationen eintragen oder ändern und ihn anschließend wieder speichern

Zielsetzung und Nicht-Zielsetzung von DiffX

  • Es zwingt nicht allen Tools Unterstützung für das Format auf und verursacht keine Kompatibilitätsprobleme
  • Es führt nicht zu Vendor Lock-in und zerstört keine bestehenden Workflows
  • Es behebt die Probleme bestehender Diff-Dateien und bietet in Entwicklungs-, Review- und Analyse-Tools eine konsistente und verlässliche Nutzungserfahrung

1 Kommentare

 
GN⁺ 2025-06-05
Hacker-News-Kommentare
  • Mir gefallen hierarchisch komplexe Formate wie „..meta“ und „...meta“ nicht. Für die Klarheit des Ausdrucks wäre es meiner Meinung nach übersichtlicher, nur drei Ebenen zu unterscheiden — den gesamten Diff, die Datei und den Chunk — und jeder einen eigenen Namen zu geben. Dann könnte man das Ziel auch ohne Metablock auf einen Blick erkennen, was Fehler und Versehen reduzieren würde. Dass die Metadaten für den gesamten Diff und die Metadaten auf Dateiebene aus denselben Feldern bestehen, wirkt ebenfalls unlogisch. Und ich verstehe nicht, warum sowohl JSON als auch ein key=value-Format nötig sind; wenn es nur wenig zu verwalten gibt, ist ein einziges Format für die Implementierung und die Integration in bestehende Tools deutlich vorteilhafter (grep, sed oder jq allein würde genügen). Außerdem wäre es schön, wenn in Listen ein trailing comma erlaubt wäre. Diff ist ursprünglich so aufgebaut, dass es sich teilweise anwenden lässt, und ich frage mich, wie sich dieses Format darauf auswirkt (zum Beispiel erscheint es umständlich, wenn man zum Anwenden nur eines Teils eines Diffs das Präambel kopieren und Blöcke separat kopieren muss). Ich frage mich auch, ob revision eine Dateieigenschaft oder eine Commit-Prüfsumme ist.

    • Wir haben verschiedene Ansätze für die Struktur ausprobiert und uns am Ende aus Parser-Sicht für die Einfachheit von #<section_level><section_type> entschieden. Bei jedem Metablock muss nur vertikal die Ebene geprüft werden, und durch das Zählen der Punkte lässt sich natürlich erkennen, zu welcher Ebene die Metadaten gehören. Das Key/Value-Header-Format sollte nur einfache Eigenschaften enthalten, die der Parser im Voraus kennt; freie Metadaten sollten dagegen in einem separaten Meta-Block stehen. Der Header kann das Format angeben, damit es nicht nur mit bestehendem JSON funktioniert, sondern auch künftig erweiterbar bleibt, falls andere Serialisierungsformen nötig werden. Das ist das Ergebnis des Versuchs, ein Gleichgewicht zwischen Einfachheit und Flexibilität zu finden. Ein trailing comma würde ich persönlich gern aufnehmen, aber wegen der Kompatibilitätsprobleme mit JSON auf Basisebene ist es schwer, einen JSON5-Parser zur Pflicht zu machen. Diff bleibt weiterhin teilbar, und weil die Informationen in Bereiche eingefügt wurden, die Unified Diff ignoriert, werden sie von GNU patch usw. ignoriert, sodass kein Problem entsteht. Wenn man eine DiffX-Datei allerdings in zwei Dateien aufteilt, muss der Header neu hinzugefügt werden, was etwas komplexer werden kann. Bei manchen SCM-Diffs gehen beim Aufteilen bestimmte Metadaten verloren (zum Beispiel Informationen über den Parent-Commit), oder es kommt je nach Anwendungsziel zu Informationsverlust. revision ist je nach SCM unterschiedlich; es kann sich um eine Commit-ID, eine dateibezogene ID oder eine Kombination daraus mit zusätzlichen Informationen handeln. Die Struktur wurde mit Blick auf die unterschiedlichen Anforderungen verschiedener SCMs entworfen.
  • Von den vier unten genannten Kritikpunkten scheint mir nur einer als Verallgemeinerung von Diff-Dateien tatsächlich sinnvoll zu sein: eine Notation für Binär-Patches. Alles andere sind Daten oder Protokollprobleme innerhalb bestimmter Versionsverwaltungssysteme (SCM), die nur in deren jeweiligen Clients, Servern oder Backup-Systemen relevant sind. Alles andere wirkt auf mich unnötig.

    • Ein einzelner Diff kann nicht mehrere Commits auflisten

    • Es gibt keinen Standard für Binär-Patches

    • Die Textkodierung kann nicht erkannt werden (das ist überraschend oft ein Problem)

    • Es gibt kein Standardformat für beliebige Metadaten

    • Wir entwickeln seit 20 Jahren ein Code-Review-Produkt, das mehr als 12 SCMs integriert, und sind dabei auf unzählige Diff-Formate und SCM-spezifische Probleme gestoßen, die man sich kaum vorstellen kann. Das sind zwar keine Themen, mit denen sich Endnutzer direkt befassen müssen, aber aus Sicht von Tool-Entwicklern sind es Pain Points, die unbedingt gelöst werden müssen. Manche SCMs haben kein eigenes Diff-Format oder es fehlen viele Informationen (zum Beispiel kann eine gelöschte Datei nicht markiert werden), sodass andere Tools Dateien nicht korrekt identifizieren können. Deshalb fanden wir solche Verbesserungen notwendig.

    • Heute ist das zwar seltener, aber ich benutze immer noch gelegentlich Werkzeuge ähnlich wie patch(1). Wenn Entwickler auf mehreren Plattformen zusammenarbeiten, treten wegen Groß-/Kleinschreibung in Dateinamen, Zeichencodierungen usw. weiterhin verschiedene Probleme auf.

  • Wenn JSON in einem selbstabgrenzenden Format mit Längenangabe eingebettet wird, kann schon das Ändern eines einzigen Leerzeichens im JSON dazu führen, dass das JSON zwar weiterhin gültig ist, DiffX insgesamt aber kaputtgeht. Strukturell wirkt diese Kombination klobig und unordentlich (Mischung aus eigenem Header und JSON-Payload, Unterscheidung verschiedener Meta-Blöcke nur durch Zählen der Punkte, Bedarf an zwei Parsern usw.). Die Idee, einen erweiterbaren Diff-Standard für Metadaten zu schaffen, ist gut, aber diese konkrete Umsetzung wirkt wie ein Versuch-und-Irrtum-Ergebnis.

  • Ich denke, das Patch-Format löst all diese Probleme bereits. Link zur Erklärung von git format-patch

    • Ich habe heute zum ersten Mal erfahren, dass es so ein Format gibt, und nehme das als Referenz mit (ich bin nur ein normaler Internetnutzer, nicht der Autor).

    • Mit Git lässt sich das lösen, aber bei einem Produkt wie Review Board muss man mit mehreren VCS wie SVN, CVS oder Perforce integrieren, und daraus scheint der Hintergrund für dieses Format zu entstehen. Ich habe ebenfalls mit Review Board und SVN gearbeitet, und wenn mehrere Entwickler git-svn und svn gemischt verwenden, gab es beim Hochladen von Diffs für Reviews häufig Probleme. Ein Standard-Diff-Format, das beide Seiten unterstützen, hätte bei der Nutzung des Tools sehr geholfen.

  • Ich habe nicht wirklich das Gefühl, dass die genannten Probleme tatsächlich existieren (abgesehen von Binärdateien).

    • Selbst bei unterschiedlicher Kodierung bleibt der Patch-Algorithmus derselbe, also muss man sich darum nicht kümmern (die Zeichen müssen nicht einmal gültiges UTF-8 sein).

    • Es gibt keinen wirklichen Grund, mehrere Commits in einen Diff zu packen; mehrere Diffs sind intuitiver.

    • Metadaten gelten doch vermutlich nur innerhalb des jeweiligen Systems.

    • Auch bei der Kodierung sollte Patch-Datenmaterial ohnehin wie ASCII-basierte Binärdaten behandelt werden; weil man Dateien mit gemischter Kodierung bearbeiten kann, bringt eine feste Kodierung nicht viel.

    • Ich halte das überhaupt nicht für ein Problem. Es wäre besser, auf reale Erfahrungen von Nutzern zu hören, die Diff tatsächlich häufig verwenden, statt ein bestehendes, gut funktionierendes Format unnötig zu overengineeren.

    • Das Problem mit Binärdaten existiert meiner Meinung nach definitiv.

    • In der Praxis stößt man auf diese Probleme meist nur dann, wenn man selbst Tools baut oder mit bestimmten SCMs interagieren muss.

      1. Kodierungsprobleme betreffen sowohl Dateinamen als auch Inhalte. Git achtet auf die Dateinamenkodierung, die meisten SCMs aber nicht, sodass automatisch erzeugte Diffs aus einer Umgebung in einer anderen manchmal die Dateinamen nicht finden (das habe ich bei Perforce, Subversion usw. gesehen). Auch im Inhalt kann ein Diff je nach lokaler Kodierung des SCM kaputtgehen. Beim Wechsel zwischen Windows- und Linux-Umgebungen haben gemischte Zeilenenden schon dazu geführt, dass sich Patches nicht anwenden ließen, oder GNU patch ist wegen BOM-Problemen kaputtgegangen.
      2. Wenn man mehrere Commits auf einmal verarbeitet oder an ein Tool übergibt, können Probleme wie fehlende Dateien oder Inkonsistenzen auftreten, und es ist mühsam, Diffs einzeln auf Plausibilität zu prüfen. Außerdem unterstützen verschiedene Tools unterschiedliche Formate, was unpraktisch ist.
      3. Um Dateien im Repository zu finden, benötigt man je nach System allerlei Identifikatoren wie commitbezogene IDs, dateibezogene IDs, Kombinationen davon oder Beziehungsinformationen. Auch Daten wie symbolische Links, Dateimodi oder SCM-spezifische Eigenschaften, die nicht in Unified Diff enthalten sind, sind essenziell.
  • Das gesamte Dokument ist schwer zu lesen. Für mich bedeutet „diff“ den Unterschied zwischen zwei Objekten (Dateien, Verzeichnissen usw.), aber das, was TFA hier mit diff meint, ist das, was ich als „patch“ kenne. Hier geht es nicht um Diff, sondern um die Verwaltung von Patch-Metadaten. Wenn man Metadaten in einem verpflichtenden Format wie JSON standardisieren würde, wäre das okay, aber diese vage selbstbeschreibende, längenbegrenzte Struktur wirkt, als würde sie das Problem eher verstecken. Die Standardisierung an sich ist gut, aber ich habe den Eindruck, dass eine deutlich klarer formulierte Lösung nötig wäre. Interessant finde ich auch, dass für mich der Git-Diff-Stil dem faktischen Standard näherkommt.

    • Dem letzten Satz stimme ich vollkommen zu: Man kann Diffs einfach in mehrere Teile aufteilen.
  • Ich frage mich, welches Problem dieses Format eigentlich lösen soll. Es heißt, bestehende Patch-/Diff-Formate seien nicht gut genug, aber es müsste klarer erklärt werden, für wen diese Verbesserung gedacht ist, ob sich in der GNU-Patch-Community Beschwerden häufen oder was genau der Anlass ist. Ich frage mich weiterhin, warum ein besseres Patch-Format wirklich notwendig sein soll.

    • Ich habe dazu einen längeren Text, den ich hier wegen der Länge nicht posten kann. Kurz gesagt geht es um Überlegungen für Leute, die selbst SCMs bauen oder Tools entwickeln, die mit SCMs integriert werden. Normale Nutzer müssen sich darum nicht kümmern. Auch die Diff-Formate unterscheiden sich je nach SCM stark; manche sind wirklich gut gemacht, andere gravierend unzureichend oder es gibt gar kein Format. Für ein Produkt wie Review Board, das viele SCMs abdecken muss, ist so ein Integrationsstandard in der Praxis unbedingt nötig. Es ist ein Verbesserungsversuch, in den Feedback aus der Zusammenarbeit mit SCM-Anbietern eingeflossen ist.

    • Es wirkt wie ein Format, das vor allem für Review Board verwendet wird; da dieses Produkt viele VCS unterstützt und Diff für Code-Reviews zentral ist, wurde es wohl deshalb eingeführt.

  • Die allgemeinste und klarste Art, einen Diff auszudrücken, besteht darin, einfach die beiden Dateien mitzuliefern. Heutzutage ist Datenvolumen kein Problem mehr, also könnte man statt diff a b | patch c etwas wie apply a b c verwenden; dann wäre die interne Darstellung egal. Diff ist für Menschen schwer zu lesen, und eine farbige Side-by-Side-Ansicht ist viel besser. Deshalb erscheint es intuitiver, von vornherein beide Dateien zu übertragen und zu verarbeiten. Ich glaube nicht, dass man unbedingt nicht standardisierte Diffs verschicken muss.

    • Es gibt nicht nur genau einen Diff aus zwei Dateien; je nach Zweck können verschiedene Varianten entstehen. Wenn es ein Diff-Format gibt, lassen sich die Logik für die Erzeugung und die Logik für die Anwendung von Diffs trennen, wodurch sich das n*m-Problem auf ein n+m-Problem reduzieren lässt.

    • Bei Programm-Updates wäre es zwar ärgerlich, jedes Mal die gesamten 130 GB neu herunterzuladen, aber fast identische Dateien lassen sich ohnehin gut komprimieren, sodass es praktisch sinnvoll bleibt, nur die Unterschiede zwischen zwei Versionen zu übertragen. Man könnte sich auch effizientere Methoden vorstellen, etwa nur den Hash der Originaldatei zu senden und den komprimierten Dateiinhalt selbst zu übertragen.

    • Das Übertragen und Verwalten von zwei Dateipaaren ist ohne einen speziellen Container schwierig, und wenn man mehrere Änderungen (Änderungen an 10 Dateien plus Löschungen und Ergänzungen usw.) per E-Mail austauschen will, würde das eher wie ein Rückschritt in die Zeit vor VCS wirken, als man auf komplexe Strukturen wie tar oder zip angewiesen war.

    • Auch wenn das Versenden ganzer Dateien intuitiver wirkt als Diff, bleibt Diff je nach Anwendungsfall und Umgebung weiterhin wichtig. Gerade heute, wo LLMs Dinge wie Code-Edits erzeugen, spart eine Diff-basierte Anfrage massiv Tokens und kann die Antwortlatenz um das 5- bis 10-Fache senken, was die Effizienz deutlich steigert. Beide Dateiversionen zu senden verschwendet Tokens und verursacht höhere Kosten. Wenn man Änderungen schnell in einer Code-Sandbox oder auf einer entfernten Maschine anwenden will, bietet Diff große Optimierungsvorteile. Wenn man Datei A, Datei A2 und den Diff A×A2 hat, lässt sich A2 leicht rekonstruieren, und auch die Speicherung kann optimiert werden. Falls es beim Mergen Konflikte gibt, muss man nur dann direkt eingreifen. Kurz gesagt: Diff ist großartig.

  • Mich stört weiterhin, dass Diff-Werkzeuge so stark von Zeilenumbrüchen abhängen. Wenn eine Zeile sehr lang ist (zum Beispiel JSON oder lange Arrays), wird das Review schwierig.

    • Stimme ich zu. Bei strukturierten Daten (zum Beispiel AST-Diffs) gibt es noch viel Raum, bessere Darstellungsformen für Diffs zu erforschen. Dieses Format (DiffX) legt den Schwerpunkt darauf, den bestehenden Unified-Diff-Stil zu erweitern. Falls sich speziellere Formate wie AST-Diffs breit durchsetzen, ist es so entworfen, dass sie ebenfalls leicht eingebettet und unterstützt werden können.

    • Die gebräuchliche Form ist ein Kompromiss zwischen menschlicher Lesbarkeit und maschinellem Parsen und bleibt dadurch etwas halbgar. Diesmal scheint man versucht zu haben, einen Teil des Problems durch Metadatenerweiterungen zu lösen, aber eine wirklich gute Lösung wäre vermutlich ein neues Format, das nicht bloß Klartext ist, sondern zugleich gut lesbar und gut parsbar. Für lange Zeilen oder strukturierte Daten bessere Diff-Algorithmen als die bisherigen zu entwickeln, ist schwierig, aber durchaus lösbar.

    • Git unterstützt neben Zeilen-Diffs auch feinere Word-Diffs, wobei standardmäßig Leerraum als Trenner dient.

  • Ich frage mich, warum JSON das einzige unterstützte Metadatenformat ist. Für einen Metadatenstandard mit allgemeinem Zweck erscheint mir JSON eher unnötig komplex.

    • Ich würde gern genauer hören, warum du JSON für übermäßig komplex hältst.