git filter-branch: Wie entfernt man Dateien aus der git Historie?

By Jason Long (http://git-scm.com/downloads/logos) [CC-BY-3.0 (http://creativecommons.org/licenses/by/3.0)], via Wikimedia CommonsEs kommt immer wieder mal vor, dass unachtsame Kollegen die Videos von der letzten Netways Feier in das git-Repository der Puppet Konfiguration pushen. Wie man sofort merkt, funktioniert der git-hook zur Erkennung und Verhinderung von push Befehlen unter Restalkohol noch nicht so ganz…
Spaß bei Seite… wie kann man ungewollte (große) Dateien wieder aus git entfernen, welche das Repository nur aufblähen aber eigentlich nicht benötigt werden? Ein einfaches git revert entfernt zwar die Datei wieder aus der aktuellen Revision, aber in der History findet man ja Gott sei Dank trotzdem noch immer alles. Auch die Größe des Repositories bleibt gleich und mit jedem neuem Klon werden die unnützen Daten auch kopiert.
Um Dateien wirklich komplett aus dem git-Repository zu entfernen wird git filter-branch benötigt. Hiermit kann man die Historie neu schreiben, aber Achtung, dies bedeutet auch, dass bereits geklonte Repositories nicht mehr fast-forward fähig sind.
filter-branch läuft über jede Revision des aktuellen Branch und kann Kommandos auf die einzelnen Revisionen ausführen, z.B. ein git rm um Dateien zu löschen. Man kann die verschiedenen Elemente der Historie einzeln bearbeiten, in unserem Fall wollen wir den Index bearbeiten. Mit anderen Optionen könnte man z.B. die Commit-Message bearbeiten.
Mit folgendem Befehl wird das Video TWUndDieWeihnachtsmaenner.mpg aus allen Zweigen des Repository entfernt:
git filter-branch --prune-empty --index-filter "git rm --cached -f \
--ignore-unmatch TWUndDieWeihnachtsmaenner.mpg" -- --all

Was machen die Optionen im einzelnen?

  • –index-filter <command>: Mit diesem Filter schreibt man den Index neu.
  • –prune-empty: Durch das Filtern kann es passieren, dass leere Commits entstehen. Dank diesem Parameter werden solche Commits entfernt.
  • –all: Es werden alle Zweige es Repositories bearbeitet.
  • <command>: Im unserem Fall ist das <command> ein git rm.
    • –ignore-unmatch sorgt einfach nur dafür, dass 0 zurück gegeben wird, auch wenn es keine Datei zum löschen gibt.
    • –cache sorgt dafür, dass der aktuelle Working Tree nicht angefasst wird.
    • -f steht natürlich für force.

Als Ergebnis bekommt man ein bereinigtes Repositorie mit einer neuen Historie. Von diesem kann jetzt wiederrum geklont werden.
Wie man sieht ist es relativ viel Arbeit ein git Repository zu bereinigen. Zudem muss man das ursprüngliche Repository ersetzen und die Kollegen müssen dieses auch neu klonen.

Achim Ledermüller
Achim Ledermüller
Lead Senior Systems Engineer

Der Exil Regensburger kam 2012 zu NETWAYS, nachdem er dort sein Wirtschaftsinformatik Studium beendet hatte. In der Managed Services Abteilung ist unter anderem für die Automatisierung des RZ-Betriebs und der Evaluierung und Einführung neuer Technologien zuständig.