Gelegentlich habe ich einen DVD-Rip in ein Website-Projekt gelegt, dann nachlässig git commit -a -m ...
, und zap, das Repo wurde durch 2,2 Gigs aufgebläht. Das nächste Mal habe ich einige Änderungen vorgenommen, die Videodatei gelöscht und alles festgeschrieben, aber die komprimierte Datei befindet sich noch im Repository im Verlauf.
Ich weiß, dass ich aus diesen Commits Zweige starten und einen Zweig auf einen anderen umstellen kann. Aber was soll ich tun, um die beiden Commits zusammenzuführen, damit die große Datei nicht im Verlauf angezeigt wird und bei der Speicherbereinigung bereinigt wird?
git filter-branch
, aber ich fand das Gegenteil wahr.Antworten:
Verwenden Sie den BFG Repo-Cleaner , eine einfachere und schnellere Alternative zum
git-filter-branch
Entfernen unerwünschter Dateien aus dem Git-Verlauf.Befolgen Sie sorgfältig die Gebrauchsanweisung , der Kern ist genau dies:
Alle Dateien mit einer Größe von mehr als 100 MB (die nicht in Ihrem letzten Commit enthalten sind) werden aus dem Verlauf Ihres Git-Repositorys entfernt. Sie können dann
git gc
die toten Daten entfernen:Das BFG ist in der Regel mindestens 10-50-mal schneller als das Laufen
git-filter-branch
und im Allgemeinen einfacher zu verwenden.Vollständige Offenlegung: Ich bin der Autor des BFG Repo-Cleaner.
quelle
git push --force
nach Ihren Schritten tun , sonst wird das Remote-Repo immer noch nicht geändert.git push --force
. Ebenfalls erwähnenswert: Force-Pushs werden von der Fernbedienung möglicherweise nicht zugelassen (gitlab.com standardmäßig nicht. Der Zweig musste "ungeschützt" werden).Was Sie tun möchten, ist äußerst störend, wenn Sie den Verlauf für andere Entwickler veröffentlicht haben. Siehe „Wiederherstellen von Upstream Rebase“ in der
git rebase
Dokumentation für die notwendigen Schritte nach der Geschichte zu reparieren.Sie haben mindestens zwei Optionen:
git filter-branch
und eine interaktive Rebase, die beide unten erläutert werden.Verwenden von
git filter-branch
Ich hatte ein ähnliches Problem mit umfangreichen binären Testdaten aus einem Subversion-Import und schrieb über das Entfernen von Daten aus einem Git-Repository .
Sagen Sie, Ihre Git-Geschichte ist:
Beachten Sie, dass dies
git lola
ein nicht standardmäßiger, aber äußerst nützlicher Alias ist. Mit dem--name-status
Schalter können wir Baumänderungen sehen, die mit jedem Commit verbunden sind.Beim Commit "Careless" (dessen SHA1-Objektname ce36c98 lautet) ist die Datei
oops.iso
der DVD-Rip, der versehentlich hinzugefügt und beim nächsten Commit, cb14efd, entfernt wurde. Unter Verwendung der im oben genannten Blog-Beitrag beschriebenen Technik lautet der auszuführende Befehl:Optionen:
--prune-empty
Entfernt Commits, die aufgrund der Filteroperation leer werden ( dh den Baum nicht ändern). Im typischen Fall erzeugt diese Option einen saubereren Verlauf.-d
Benennt ein temporäres Verzeichnis, das noch nicht zum Erstellen des gefilterten Verlaufs verwendet werden kann. Wenn Sie auf einer modernen Linux-Distribution arbeiten, führt die Angabe eines Baums in/dev/shm
zu einer schnelleren Ausführung .--index-filter
ist das Hauptereignis und wird bei jedem Schritt im Verlauf gegen den Index ausgeführt. Sie möchten entfernen,oops.iso
wo immer es gefunden wird, aber es ist nicht in allen Commits vorhanden. Der Befehlgit rm --cached -f --ignore-unmatch oops.iso
löscht den DVD-Rip, wenn er vorhanden ist, und schlägt ansonsten nicht fehl.--tag-name-filter
beschreibt, wie Tag-Namen umgeschrieben werden. Ein Filter voncat
ist die Identitätsoperation. Ihr Repository hat wie das obige Beispiel möglicherweise keine Tags, aber ich habe diese Option aus Gründen der allgemeinen Allgemeinheit eingefügt.--
Gibt das Ende der Optionen angit filter-branch
--all
Das Folgende--
ist eine Abkürzung für alle Refs. Ihr Repository hat wie das obige Beispiel möglicherweise nur eine Referenz (Master), aber ich habe diese Option aus Gründen der allgemeinen Allgemeinheit aufgenommen.Nach einigem Hin und Her ist die Geschichte nun:
Beachten Sie, dass das neue Commit "Unvorsichtig" nur
other.html
hinzugefügt wird und dass sich das Commit "DVD-Rip entfernen" nicht mehr im Hauptzweig befindet. Der gekennzeichnete Zweigrefs/original/refs/heads/master
enthält Ihre ursprünglichen Commits, falls Sie einen Fehler gemacht haben. Befolgen Sie zum Entfernen die Schritte unter „Checkliste zum Verkleinern eines Repositorys“.Für eine einfachere Alternative klonen Sie das Repository, um die unerwünschten Bits zu verwerfen.
Durch die Verwendung einer
file:///...
Klon-URL werden Objekte kopiert, anstatt nur Hardlinks zu erstellen.Jetzt ist Ihre Geschichte:
Die SHA1-Objektnamen für die ersten beiden Commits ("Index" und "Admin-Seite") blieben unverändert, da die Filteroperation diese Commits nicht geändert hat. „Careless“ verloren
oops.iso
und „Login - Seite“ haben ein neu Eltern, so dass ihre SHA1s tat ändern.Interaktive Rebase
Mit einer Geschichte von:
Sie möchten
oops.iso
aus "Unvorsichtig" entfernen, als hätten Sie es nie hinzugefügt, und dann ist "DVD-Rip entfernen" für Sie nutzlos. Daher ist unser Plan für eine interaktive Rebase, die "Admin-Seite" beizubehalten, "Nachlässig" zu bearbeiten und "DVD-Rip entfernen" zu verwerfen.Durch Ausführen wird
$ git rebase -i 5af4522
ein Editor mit den folgenden Inhalten gestartet.Wir führen unseren Plan aus und ändern ihn in
Das heißt, wir löschen die Zeile mit "DVD-Rip entfernen" und ändern den Vorgang auf "Unvorsichtig" so, dass er
edit
nichtpick
.Wenn Sie das Speichern des Editors beenden, wird uns an einer Eingabeaufforderung die folgende Meldung angezeigt.
Wie aus der Nachricht hervorgeht, befinden wir uns im Commit "Unvorsichtig", das wir bearbeiten möchten, und führen daher zwei Befehle aus.
Der erste entfernt die fehlerhafte Datei aus dem Index. Der zweite ändert oder ändert "Careless" als aktualisierten Index und
-C HEAD
weist git an, die alte Festschreibungsnachricht wiederzuverwenden. Schließlich wirdgit rebase --continue
mit dem Rest der Rebase-Operation fortgefahren.Dies gibt eine Geschichte von:
Welches ist, was Sie wollen.
quelle
-f
(oder--force
) hinzugit push
: „Normalerweise weigert sich der Befehl, eine Remote-Referenz zu aktualisieren, die kein Vorfahr der lokalen Referenz ist, die zum Überschreiben verwendet wurde. Dieses Flag deaktiviert die Prüfung. Dies kann dazu führen, dass das Remote-Repository Commits verliert. benutze es mit Vorsicht. "... "git rm --cached -rf --ignore-unmatch path/to/dir"...
Warum nicht diesen einfachen, aber leistungsstarken Befehl verwenden?
Die
--tree-filter
Option führt den angegebenen Befehl nach jedem Auschecken des Projekts aus und schreibt die Ergebnisse erneut fest. In diesem Fall entfernen Sie eine Datei namens DVD-Rip aus jedem Snapshot, unabhängig davon, ob sie vorhanden ist oder nicht.Wenn Sie wissen, durch welches Commit die große Datei eingeführt wurde (z. B. 35dsa2), können Sie HEAD durch 35dsa2..HEAD ersetzen, um zu vermeiden, dass zu viel Verlauf neu geschrieben wird, und um divergierende Commits zu vermeiden, wenn Sie noch kein Push durchgeführt haben. Dieser Kommentar mit freundlicher Genehmigung von @ alpha_989 scheint zu wichtig, um ihn hier wegzulassen.
Siehe diesen Link .
quelle
fatal: bad revision 'rm'
, was ich mit"
statt behoben habe'
. Gesamtbefehl:git filter-branch --force --index-filter "git rm --cached -r --ignore-unmatch oops.iso" --prune-empty --tag-name-filter cat -- --all
commit
wo Sie die Datei in (sagen wir setzen35dsa2
) können Sie ersetzenHEAD
mit35dsa2..HEAD
.tree-filter
ist viel langsamer als aufindex-filter
diese Weise. Es wird nicht versucht, alle Commits auszuchecken und neu zu schreiben. Wenn Sie HEAD verwenden, wird dies versucht.(Die beste Antwort, die ich auf dieses Problem gesehen habe, ist: https://stackoverflow.com/a/42544963/714112 , hier kopiert, da dieser Thread in den Google-Suchrankings hoch erscheint, der andere jedoch nicht.)
🚀 Ein blitzschneller Shell-Einzeiler 🚀
Dieses Shell-Skript zeigt alle Blob-Objekte im Repository an, sortiert vom kleinsten zum größten.
Für mein Beispiel-Repo lief es ungefähr 100-mal schneller als die anderen hier gefundenen.
Auf meinem vertrauenswürdigen Athlon II X4-System verwaltet es das Linux-Kernel-Repository mit seinen 5.622.155 Objekten in etwas mehr als einer Minute .
Das Basisskript
Wenn Sie den obigen Code ausführen, erhalten Sie eine schöne, für Menschen lesbare Ausgabe wie folgt :
🚀 Schnelle Dateientfernung 🚀
Angenommen, Sie möchten dann die Dateien entfernen
a
undb
von jedem Commit, von dem ausHEAD
Sie erreichbar sind , können Sie diesen Befehl verwenden:quelle
--tag-name-filter cat
neuen entsprechenden Commits neu zu markieren, wenn sie neu geschrieben werden, dhgit filter-branch --index-filter 'git rm --cached --ignore-unmatch a b' --tag-name-filter cat HEAD
(siehe diese verwandte Antwort )git filter-branch --index-filter 'git rm --cached --ignore-unmatch <filename>' HEAD
Arbeitsauftrag rechts von der Fledermausgit rev-list --objects --all \ | git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' \ | awk '/^blob/ {print substr($0,6)}' \ | sort --numeric-sort --key=2 \ | gnumfmt --field=2 --to=iec-i --suffix=B --padding=7 --round=nearest
Nachdem ich praktisch jede Antwort in SO ausprobiert hatte, fand ich endlich dieses Juwel, das die großen Dateien in meinem Repository schnell entfernte und löschte und es mir ermöglichte, erneut zu synchronisieren: http://www.zyxware.com/articles/4027/how-to-delete -Dateien-permanent-von-Ihren-lokalen-und-Remote-Git-Repositorys
CD in Ihren lokalen Arbeitsordner und führen Sie den folgenden Befehl aus:
Ersetzen Sie FOLDERNAME durch die Datei oder den Ordner, den Sie aus dem angegebenen Git-Repository entfernen möchten.
Führen Sie anschließend die folgenden Befehle aus, um das lokale Repository zu bereinigen:
Übertragen Sie nun alle Änderungen in das Remote-Repository:
Dadurch wird das Remote-Repository bereinigt.
quelle
Diese Befehle funktionierten in meinem Fall:
Es unterscheidet sich kaum von den oben genannten Versionen.
Für diejenigen, die dies auf Github / Bitbucket schieben müssen (ich habe dies nur mit Bitbucket getestet):
quelle
git rm --cached files
. Der Vorschlag von Greg Bacon ist vollständiger und entspricht dem meiner Mine, aber er hat den --force-Index für Fälle verpasst, in denen Sie Filter-Branch mehrmals verwenden, und er hat so viele Informationen geschrieben, dass meine Version wie ein Lebenslauf ist davon.-f
Option nicht nur-rf
hier verwenden,git rm --cached -rf --ignore-unmatch oops.iso
sonderngit rm --cached -r --ignore-unmatch oops.iso
gemäß @ lfender6445 untenBeachten Sie nur, dass diese Befehle sehr zerstörerisch sein können. Wenn mehr Leute am Repo arbeiten, müssen sie alle den neuen Baum ziehen. Die drei mittleren Befehle sind nicht erforderlich, wenn Sie die Größe NICHT reduzieren möchten. Weil der Filterzweig eine Sicherungskopie der entfernten Datei erstellt und dort lange bleiben kann.
quelle
git filter-branch --force --index-filter 'git rm --cached -r --ignore-unmatch oops.iso' --prune-empty --tag-name-filter cat -- --all
anstelle des ersten aus Ihrem Codegit filter-branch --tree-filter 'rm -f path/to/file' HEAD
hat für mich ziemlich gut funktioniert, obwohl ich auf das gleiche Problem wie hier beschrieben gestoßen bin, das ich gelöst habe, indem ich diesem Vorschlag gefolgt bin .Das Pro-Git-Buch enthält ein ganzes Kapitel zum Umschreiben des Verlaufs. Schauen Sie sich den Abschnitt
filter-branch
/ Entfernen einer Datei aus jedem Commit an .quelle
Wenn Sie wissen, dass Ihr Commit kürzlich ausgeführt wurde, anstatt den gesamten Baum zu durchlaufen, gehen Sie wie folgt vor:
git filter-branch --tree-filter 'rm LARGE_FILE.zip' HEAD~10..HEAD
quelle
Ich bin darauf mit einem Bitbucket-Konto gestoßen, in dem ich versehentlich gigantische * .jpa-Backups meiner Site gespeichert hatte.
git filter-branch --prune-empty --index-filter 'git rm -rf --cached --ignore-unmatch MY-BIG-DIRECTORY-OR-FILE' --tag-name-filter cat -- --all
Platzieren Sie
MY-BIG-DIRECTORY
den betreffenden Ordner neu, um Ihren Verlauf ( einschließlich Tags ) vollständig neu zu schreiben .Quelle: https://web.archive.org/web/20170727144429/http://naleid.com:80/blog/2012/01/17/finding-and-purging-big-files-from-git-history/
quelle
Dadurch wird es aus Ihrem Verlauf entfernt
quelle
Ich habe im Grunde genommen getan, was auf dieser Antwort stand: https://stackoverflow.com/a/11032521/1286423
(Für die Geschichte werde ich es hier kopieren und einfügen)
Es hat nicht funktioniert, weil ich Dinge gerne umbenenne und viel bewege. Einige große Dateien befanden sich also in Ordnern, die umbenannt wurden, und ich denke, der GC konnte den Verweis auf diese Dateien aufgrund des Verweises in
tree
Objekten, die auf diese Datei verweisen, nicht löschen . Meine ultimative Lösung, um es wirklich zu töten, war:Mein Repo (das
.git
) hat sich von 32 MB auf 388 KB geändert, das selbst der Filterzweig nicht reinigen konnte.quelle
git filter-branch
ist ein leistungsstarker Befehl, mit dem Sie eine große Datei aus dem Commit-Verlauf löschen können. Die Datei bleibt eine Weile und Git entfernt sie in der nächsten Garbage Collection. Im Folgenden finden Sie den vollständigen Vorgang zum Löschen von Dateien aus dem Festschreibungsverlauf . Aus Sicherheitsgründen führt der folgende Prozess zuerst die Befehle in einem neuen Zweig aus. Wenn das Ergebnis Ihren Anforderungen entspricht, setzen Sie es auf den Zweig zurück, den Sie tatsächlich ändern möchten.quelle
Verwenden Sie Git Extensions , es ist ein UI-Tool. Es hat ein Plugin namens "Find large files", das große Dateien in Repositorys findet und das dauerhafte Entfernen ermöglicht.
Verwenden Sie 'git filter-branch' nicht, bevor Sie dieses Tool verwenden, da es keine Dateien finden kann, die von 'filter-branch' entfernt wurden (obwohl 'filter-branch' Dateien nicht vollständig aus den Repository-Pack-Dateien entfernt) .
quelle
Sie können dies mit dem folgenden
branch filter
Befehl tun :git filter-branch --tree-filter 'rm -rf path/to/your/file' HEAD
quelle
Es gibt sehr gute Antworten in diesem Thread, aber mittlerweile sind viele davon veraltet. Die Verwendung
git-filter-branch
wird nicht mehr empfohlen, da die Verwendung in großen Repositorys schwierig und äußerst langsam ist.git-filter-repo
ist viel schneller und einfacher zu bedienen.git-filter-repo
ist ein Python-Skript, das unter github verfügbar ist: https://github.com/newren/git-filter-repo .Sie benötigen nur eine Datei: das Python3-Skript git-filter-repo. Kopieren Sie es in einen Pfad, der in der PATH-Variablen enthalten ist. Unter Windows müssen Sie möglicherweise die erste Zeile des Skripts ändern (siehe INSTALL.md). Sie müssen Python3 auf Ihrem System installiert haben, aber das ist keine große Sache.
Zuerst kannst du rennen
Auf diese Weise können Sie bestimmen, was als Nächstes zu tun ist.
Sie können Ihre DVD-Rip-Datei überall löschen:
Filter-Repo ist sehr schnell. Eine Aufgabe, die auf meinem Computer mit Filter-Branch ungefähr 9 Stunden dauerte, wurde mit Filter-Repo in 4 Minuten erledigt. Mit Filter-Repo können Sie noch viele weitere schöne Dinge tun. Siehe dazu die Dokumentation.
Warnung: Führen Sie dies auf einer Kopie Ihres Repositorys aus. Viele Aktionen von Filter-Repo können nicht rückgängig gemacht werden. filter-repo ändert die Commit-Hashes aller geänderten Commits (natürlich) und aller ihrer Nachkommen bis zu den letzten Commits!
quelle
Wenn Sie auf dieses Problem stoßen,
git rm
wird dies nicht ausreichen, da git sich daran erinnert, dass die Datei einmal in unserem Verlauf vorhanden war, und daher einen Verweis darauf behält.Um die Sache noch schlimmer zu machen, ist das erneute Basieren auch nicht einfach, da jegliche Verweise auf den Blob verhindern, dass der Git-Garbage-Collector den Raum aufräumt. Dies umfasst Remote-Referenzen und Reflog-Referenzen.
Ich habe
git forget-blob
ein kleines Skript zusammengestellt , das versucht, alle diese Referenzen zu entfernen, und dann git filter-branch verwendet, um jedes Commit in der Verzweigung neu zu schreiben.Sobald Ihr Blob vollständig nicht mehr referenziert ist,
git gc
wird er entferntDie Verwendung ist ziemlich einfach
git forget-blob file-to-forget
. Weitere Informationen erhalten Sie hierhttps://ownyourbits.com/2017/01/18/completely-remove-a-file-from-a-git-repository-with-git-forget-blob/
Ich habe dies dank der Antworten von Stack Overflow und einigen Blogeinträgen zusammengestellt. Credits an sie!
quelle
Neben
git filter-branch
(langsame, aber reine Git-Lösung) und BFG (einfacher und sehr leistungsfähiger) gibt es noch ein anderes Tool zum Filtern mit guter Leistung:https://github.com/xoofx/git-rocket-filter
Aus seiner Beschreibung:
Der Zweck von Git-Rocket-Filter ähnelt dem Befehl
git-filter-branch
und bietet die folgenden einzigartigen Funktionen:quelle