Git: Vergleich gezippter XML-Dateien

Faluröd

Lieutenant
Registriert
März 2011
Beiträge
579
Hallo! Ich bin auf der Suche nach einer guten Möglichkeit, gezippte XML-Dateien in Git zu vergleichen. Ein Beispiel für solche Dateien sind Word-Dokumente als DOCX. Mein wichtigster Anwendungsfall wären Modelle in Matlab/Simulink. Egal ob Word- oder Simulink-Datei, in beiden Fällen handelt es sich um eine Zip-Datei, welche aus Textdateien im XML-Format besteht.

Da würde mich interessieren, ob es eine einfache Möglichkeit gibt, die in der Datei beinhalteten Texte ähnlich komfortabel in Git zu vergleichen wie normale Textdateien im txt-Format.

Ein manueller Workflow für einen solchen Vergleich wäre:
  • docx/slx-Datei unzippen
  • Alle beinhalteten Dateien als Textdatei öffnen und diese aneinanderhängen
  • Die daraus resultierende Textdatei vergleichen

Also an sich ein überschaubarer Workflow. Lässt sich sowas einem git-diff Befehl vorschalten? Und idealerweise ohne großes Zutun seitens des Nutzers?

Einige Informationen zu involvierten Programmen / Umgebungen:
  • Betriebssystem: Windows
  • Git-Server: Läuft auf GitLab
  • Git: Nutze ich derzeit über die GUI Sourcetree
Die ersten beiden Punkte sind fix, da kann ich nichts ändern. Der dritte Punkt ist bei Bedarf variabel. Wobei es natürlich schön wäre, eine Lösung zu finden, die unabhängig von der verwendeten Software funktioniert.

Hat da einer von euch einen guten Vorschlag?
 
Gezippte XML-Dateien (wie DOCX oder SLX) automatisch entpacken und die enthaltenen XML-Dateien vergleichen erreichst du mit Git's diff- und Merge-Mechanismen, indem du eine eigene Textconv-Filterregel definierst.

Erstelle ein Batch- oder PowerShell-Skript, das die Datei entpackt, XML-Dateien extrahiert und zusammenführt.
z.B. unter C:\git-tools\extract-xml.ps1 speichern

Git so konfigurieren, dass es das Skript für DOCX und SLX verwendet
also für deine deine ~/.gitconfig z.B.
[diff "zipxml"]
textconv = powershell -ExecutionPolicy Bypass -File C:/git-tools/extract-xml.ps1

Lege im Root deines Git-Repos eine Datei namens .gitattributes an
*.docx diff=zipxml
*.slx diff=zipxml

Wenn du nun git diff in deinem Repository ausführst, wird automatisch die docx- oder slx-Datei entpackt, ie enthaltenen XML-Dateien zusammengeführt, ein Git-Diff auf diese zusammengefügten XML-Inhalte durchgeführt. Aber habs jetzt nicht alles ausgeführt, da ich nicht extra die extract-xml.ps1 geschrieben hab
 
  • Gefällt mir
Reaktionen: nonick65, BeBur und Faluröd
Danke dir vielmals! Ganz läuft es noch nicht, aber 90% des Weges sollten für docx erledigt sein. Die C:\Users\<myUserID>\.gitconfig habe ich erweitert und im selben Ordner die .gitattributes abgelegt. Damit konnte ich schon erreichen, dass Git definitiv was anders macht als den standardmäßigen diff.

Außerhalb von Git habe ich in cmd folgenden Befehl gefunden, der (soweit ich das bisher beurteilen kann) das gewünschte Zusammenfassen der Dateien erledigt:
tar -O -xf myFileName.docx

Jetzt muss ich also nur noch beides verknüpfen. Da bin ich gerade noch am Tüfteln, wie ich den Dateinamen durchreiche. In den Beispielen hier übernimmt "$1" diese Rolle, habe ich allerdings noch nicht zum Laufen gebracht. Zumindest weiß ich schon mal, wonach ich suchen muss :)
 
In Bash sollte "$1" im Dateinamen enthalten sein
In PowerShell: param([string]$filename) nutzen

Teste das Skript dann manuell:

sh
./extract-docx.sh myFile.docx

Falls dakein Fehler kommt, liegt das Problem eher bei Git.
 
  • Gefällt mir
Reaktionen: Faluröd
Jetzt bin ich für docx bei einer lauffähigen Lösung. Ich wiederhole manches, damit alles auf einem Blick steht, falls sich noch jemand dafür interessiert.

Schritt 1:
C:\Users\<myUserID>\.gitattributes öffnen bzw. neu anlegen. Dann folgende Zeile ergänzen:

*.docx diff=zip

Schritt 2:
C:\Users\<myUserID>\.gitconfig öffnen / neu anlgen. Folgende Zeilen ergänzen:

[diff "zip"]
textconv = powershell -ExecutionPolicy Bypass -File C:/Users/<myUserID>/ProcessZippedXML.ps1

Schritt 3:
Das im Schritt 2 definierte PowerShell-Skript erstellen. Das Skript führt folgenden Befehl aus:

C:/Users/<myUserID>/unzip.exe -c -a

Schritt 4:
Das unzip-Tool herunterladen (gibt es hier auch als Windows-Version). Da hat es bei mir gereicht, lediglich die vom Archiv die \bin\unzip.exe dort abzulegen, wo das PowerShell-Skript danach sucht. Das Unzip funktioniert im Unterschied zum tar auch ohne Pfad. Hab's zwar nicht ganz verstanden, aber Hauptsache es läuft ;).


Anwendungsbeispiel:
Folgendes Word neu erstellt:
1742320795911.png


Wird dann so in Sourcetree angezeigt:
1742320882913.png


Ändert man das Dokument zu:
1742320939716.png


Wird das folgendermaßen angezeigt:
1742320960610.png


Textänderungen werden also erkannt, die Formattierung fällt wohl hinten runter. Nicht perfekt, aber schon mal besser als die Anzeige "sind zwei unterschiedliche binäre Dateien". Wichtig ist dann natürlich, dass man die Grenzen des Vergleichs kennt.

Aber gut, Word-Dokumente waren eher ein Seitenaspekt, um erstmal die Funktionalität zu entwickeln. Spannend wird es, wenn ich ein paar Simulink-Modelle erstelle und darauf dann die Skripten anwende. Da melde ich mich nochmal.

@wertzuiop123 : Danke dir für deine Unterstützung bei diesem Nicht-Allerwelts-Thema!
 
  • Gefällt mir
Reaktionen: Marco01_809 und wertzuiop123
Danke euch für all die Hinweise. Leider stolpere ich bei meinem Fokus Simulink-Modelle an etwas unerklärlichen Phänomenen.

Als Kommando nutze ich nun folgenden:
textconv = C:/TEMP/Git/git_local/bin/sh.exe -c 'C:/TEMP/Git/git_local/usr/bin/unzip -p "$0" -x "/.png"'

Wenn ich das Kommando im Bash ausführe (mit echtem Dateinamen anstelle "$0"), dann schreibt es schön den Textinhalt der Datei. Zudem habe ich diese Ausgabe manuell via ">"-Operator auf eine Textdatei umgeleitet, da sieht ein Vergleich dann z.B. so aus:
1743626220766.png


Der erste "Gain" 2 bzw. 3 wäre eine relevante Änderung, die weiteren wie Zeile 101 "Revision" und die UUID (also ID-Nummer) in Z. 134 etwas Beiprodukt. Daraus könnte man also schon einen ersten Eindruck erhalten, was geändert wurde, v.a. wenn man die Vergleiche öfters sieht.

Führe ich den textconv allerdings via Git durch, dann erkennt er das immer noch als Binärdatei. Ich habe mir als Test auch erlaubt, die slx-Datei zu docx umzubenennen, und darauf denselben textconv-Befehl anzuwenden. Dann funktioniert es in Auszügen:
1743627330851.png


Ja, an einigen Stellen wird die XML richtig interpretiert. Aber es mogeln sich immer wieder binäre Passagen rein, welche das Diff erschweren. Testweise habe ich die Simulinkdateien auch im normalen Texteditor geöffnet: Da wird viel Text angezeigt, aber eben auch immer wieder eine Zeile PK, gefolgt von einigen Binärdaten. Was für mich etwas nach den Meta-Informationen innerhalb des Archivs aussieht. Genau diese Infos sieht man auch im Git Diff (und im Unterschied dazu beim manuellen Ausführen nicht). Im Screenshot ist es z.B. die 2. Zeile:
1743627370357.png




Lange Rede kurzer Sinn: Inzwischen habe ich schon viel ausprobiert, aber bisher leider keine stabil funktionierende Lösung gebunden. Da die Skripte für sich gestellt funktionieren, und ich in den Git-Workflow leider keinen Debug-Punkt reinsetzen kann, weiß ich auch nicht, wo ich weitersuchen müsste. Deswegen würde ich das Thema leider unvollendet abbrechen.

Als weiterer Grund kommt dazu, das Simulink ja für sich ein Git-Diff-Tool bereitstellt. Es ist zwar ein bisschen mehr Klickerei als automatisch den Vergleich in Sourcetree zu sehen. Aber ich hab leider keine zündende Idee mehr, und das Netz ist auch nicht allzu ergiebig zu dem Thema.

Danke dennoch an alle, die mich mit ihren Anregungen unterstützt haben. Einiges dabei gelernt habe ich dennoch. Wer weiß, wozu das mal einiges Tages nützlich sein kann.
 
Zuletzt bearbeitet:
Git entscheidet anhand der ersten paar Tausend Bytes, ob eine Datei als Text oder Binär interpretiert wird. Selbst wenn dein textconv sinnvollen Text ausgibt, führt die kleinste Binärspur in der Ausgabe dazu, dass Git auf „binary“ schaltet. Wenn du unzip -p verwendest, bekommst du beim Entpacken immer den gesamten Dateiinhalt – also auch etwaige eingebettete Medien, .png, .jpg, Vorschaugrafiken oder Metainfos. Diese „vermüllen“ deinen Output mit Binärdaten. Du könntest versuchen, nur gezielt die .xml-Dateien aus dem Archiv zu extrahieren, wenn du da weiter dran bleiben willst... unzip -p "$0" '*/blockdiagram.xml' oder unzip -p "$0" | strings

Falls du mit unzip -l vorher die Pfade im SLX-Archiv anzeigen lässt, kannst du das -p gezielter einsetzen.
 
Jetzt hab ich mich doch nochmal hingesetzt. Und jetzt hab ich es hinbekommen :). Der Fehler lag allerdings nicht am textconv-Kommando, sondern in den gitattributes. Da ich Sourcetree bzw. die dort mit installierte git.exe genutzt habe, musste ich folgende Datei öffnen:
C:\Users\<myWindowsUser>\AppData\Local\Atlassian\SourceTree\git_local\etc\gitattributes

Im Unterschied dazu habe ich bisher C:\Users\<myWindowsUser>\.gittatributes bearbeitet, diese wurde nicht gelesen (oder vielleicht nur vereinzelnd, denn einiges hat zwischenzeitlich funktioniert)

Gleichzeitig erklärt das auch, warum die DOCX verarbeitet wurden: Denn da steht "*.DOCX diff=astextplain" drin. Deswegen wurden die also verarbeitet, aber eben mit all den "Sonderzeichen" bei binären Inhalten. Also genau das, was rauskommt, wenn man die SLX mit dem Texteditor öffnet.

Gut, nun fix "*.slx diff=slx" als neue Zeile ergänzt, und schon lief es. Als Kommando fürs Diff der SLX bin ich nun auf folgenden gewechselt (das dann in C:\Users\<myWindowsUser>\.gitconfig):
Code:
textconv = C:/Users/<myWindowsUser>/AppData/Local/Atlassian/SourceTree/git_local/bin/sh.exe -c 'C:/Users/<myWindowsUser>/AppData/Local/Atlassian/SourceTree/git_local/usr/bin/unzip -p "$0" "*/*.xml" "*/*.rels"'

Mit *.xml und *.rels greife ich die beiden Textdateitypen innerhalb der Datei raus. Das sollte die wichtigsten Anwendungsfälle abdecken. Wie gesagt, mir geht es nur um die erste Idee, was geändert wurde. Und wenn ich es genauer wissen will, bietet Matlab ja selbst eine diff-Funktion.


Also zum Schluss doch noch gute Nachrichten. Jetzt bleibt "nur" noch übrig, das alles an einem anderen Rechner zum Laufen zu bekommen. Was ein Test ist, dass es wirklich exakt die beiden Kommandos in den genannten Dateien sind.
 
Zuletzt bearbeitet: (Fehler im Kommando korrigiert)
Supi :) Vielleicht ein kleines Wrapper-Skript schreiben, das SLX-Files prüft und nur die relevanten Textteile an Git weiterreicht... dann musst du nicht an jedem Gerät händisch alles nachbauen.
 
Zurück
Oben