Entfernen Sie die große .pack-Datei, die von git erstellt wurde

111

Ich habe eine Menge Dateien in einen Zweig eingecheckt und zusammengeführt und musste sie dann entfernen. Jetzt bleibt mir eine große .pack-Datei, die ich nicht entfernen kann.

Ich habe alle Dateien mit gelöscht git rm -rf xxxxxxund auch die --cachedOption ausgeführt.

Kann mir jemand sagen, wie ich eine große .pack-Datei entfernen kann, die sich derzeit im folgenden Verzeichnis befindet:

.git/objects/pack/pack-xxxxxxxxxxxxxxxxx.pack

Muss ich nur den Zweig entfernen, den ich noch habe, aber nicht mehr benutze? Oder muss ich noch etwas ausführen?

Ich bin nicht sicher, wie viel Unterschied es macht, aber es zeigt ein Vorhängeschloss gegen die Datei.

Vielen Dank


BEARBEITEN

Hier sind einige Auszüge aus meiner bash_history, die eine Vorstellung davon geben sollen, wie ich in diesen Zustand gekommen bin (nehmen wir an, ich arbeite an einem Git-Zweig namens 'my-branch' und habe einen Ordner mit mehr Ordnern / Dateien):

git add .
git commit -m "Adding my branch changes to master"
git checkout master
git merge my-branch
git rm -rf unwanted_folder/
rm -rf unwanted_folder/     (not sure why I ran this as well but I did)

Ich dachte, ich hätte auch folgendes ausgeführt, aber es erscheint nicht in der bash_history mit den anderen:

git rm -rf --cached unwanted_folder/

Ich dachte auch, ich hätte einige Git-Befehle (wie git gc) ausgeführt, um zu versuchen, die Pack-Datei aufzuräumen, aber sie erscheinen auch nicht in der .bash_history-Datei.

user1116573
quelle
Können Sie klarstellen, wie Sie sie entfernt haben? Wenn sie sich noch im Commit-Verlauf befinden, befinden sie sich immer noch in Ihren Pack-Dateien.
Loganfsmyth
Hallo @loganfsmyth, ich habe die Bash-Verlaufsskripte hinzugefügt, die hoffentlich helfen werden.
user1116573

Antworten:

199

Das Problem ist, dass die Dateien, obwohl Sie sie entfernt haben, in früheren Revisionen immer noch vorhanden sind. Das ist der springende Punkt bei git: Selbst wenn Sie etwas löschen, können Sie es durch Zugriff auf den Verlauf zurückerhalten.

Was Sie tun möchten, wird als Umschreiben des Verlaufs bezeichnet und beinhaltet den git filter-branchBefehl.

GitHub hat eine gute Erklärung des Problems auf ihrer Website. https://help.github.com/articles/remove-sensitive-data

Um Ihre Frage direkter zu beantworten, müssen Sie diesen Befehl grundsätzlich ausführen unwanted_filename_or_folderund entsprechend ersetzen:

git filter-branch --index-filter 'git rm -r --cached --ignore-unmatch unwanted_filename_or_folder' --prune-empty

Dadurch werden alle Verweise auf die Dateien aus dem aktiven Verlauf des Repos entfernt.

Nächster Schritt: Durchführen eines GC-Zyklus, um zu erzwingen, dass alle Verweise auf die Datei abgelaufen sind und aus der Packdatei gelöscht werden. In diesen Befehlen muss nichts ersetzt werden.

git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin
# or, for older git versions (e.g. 1.8.3.1) which don't support --stdin
# git update-ref $(git for-each-ref --format='delete %(refname)' refs/original)
git reflog expire --expire=now --all
git gc --aggressive --prune=now
loganfsmyth
quelle
3
Ich habe es als akzeptiert markiert, wenn es für jeden, der in Zukunft zu dieser Frage kommt, einfacher ist, obwohl ich mein Problem zu diesem Zeitpunkt tatsächlich gelöst habe, indem ich ein
neues
3
Ich weiß nicht, wie du darauf gekommen bist, aber ... du der Mann. Vielen Dank.
Ezekiel Victor
5
Diese Antwort zeigte mir die richtige Richtung. Aber um die Dateien tatsächlich zu löschen, werden 3 weitere Befehle benötigt 1) git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin2) git reflog expire --expire=now --all3)git gc --prune=now
arod
3
Ich finde die Verwendung bfgviel einfacher. Es wird auch in offiziellen Github-Dokumenten empfohlen: help.github.com/articles/…
Timo
2
@ Timo Es ist gut, eine neue Antwort hinzuzufügen, wenn sich die Dinge im Laufe der Zeit geändert haben. Tue es!
Loganfsmyth
12

Szenario A : Wenn Ihre großen Dateien nur einem Zweig hinzugefügt wurden, müssen Sie sie nicht ausführen git filter-branch. Sie müssen nur den Zweig löschen und die Speicherbereinigung ausführen:

git branch -D mybranch
git reflog expire --expire-unreachable=all --all
git gc --prune=all

Szenario B : Es sieht jedoch so aus, als hätten Sie die Änderungen basierend auf Ihrem Bash-Verlauf in Master zusammengeführt. Wenn Sie die Änderungen noch niemandem mitgeteilt haben (noch keine git push). Am einfachsten wäre es, den Master vor dem Zusammenführen mit dem Zweig mit den großen Dateien zurückzusetzen. Dadurch werden alle Commits aus Ihrem Zweig und alle Commits, die nach dem Zusammenführen zum Master gemacht wurden, entfernt. So verlieren Sie möglicherweise Änderungen - zusätzlich zu den großen Dateien -, die Sie möglicherweise tatsächlich wollten:

git checkout master
git log # Find the commit hash just before the merge
git reset --hard <commit hash>

Führen Sie dann die Schritte aus Szenario A aus.

Szenario C : Wenn nach der Zusammenführung andere Änderungen aus dem Zweig oder Änderungen am Master vorgenommen wurden, die Sie beibehalten möchten, ist es am besten, den Master neu zu starten und die gewünschten Commits selektiv einzuschließen:

git checkout master
git log # Find the commit hash just before the merge
git rebase -i <commit hash>

Entfernen Sie in Ihrem Editor Zeilen, die den Commits entsprechen, mit denen die großen Dateien hinzugefügt wurden, lassen Sie jedoch alles andere unverändert. Speichern und Beenden. Ihr Hauptzweig sollte nur das enthalten, was Sie möchten, und keine großen Dateien. Beachten Sie, dass git rebaseohne -pMerge-Commit-Commits eliminiert werden, sodass Sie nachher einen linearen Verlauf für den Master erhalten <commit hash>. Das ist wahrscheinlich okay für dich, aber wenn nicht, könntest du es versuchen -p, git help rebasesagt aber combining -p with the -i option explicitly is generally not a good idea unless you know what you are doing.

Führen Sie dann die Befehle aus Szenario A aus.

nur keiner
quelle
Es gibt eine Variante von Szenario A hier mit, aber ein extra unerwartetes Problem.
Szenario Ein gelöstes Minenproblem, um eine große Menge temporärer Packdateien zu löschen. Das Repository wurde von einem Build-Server verwaltet und verursacht unerwünschte Dateierstellung im Ordner .git / objects / pack. Ich könnte wertvolle GBs von meiner Festplatte freigeben.
xrissz
7

Wie loganfsmyth bereits in seiner Antwort angegeben hat , müssen Sie den Git-Verlauf löschen, da die Dateien dort auch nach dem Löschen aus dem Repo weiterhin vorhanden sind. Offizielle GitHub-Dokumente empfehlen BFG, das ich einfacher zu verwenden finde als filter-branch:

Dateien aus dem Verlauf löschen

Laden Sie BFG von ihrer Website herunter. Stellen Sie sicher, dass Sie Java installiert haben, erstellen Sie dann einen Spiegelklon und löschen Sie den Verlauf. Stellen Sie sicher, dass Sie YOUR_FILE_NAMEden Namen der Datei ersetzen, die Sie löschen möchten:

git clone --mirror git://example.com/some-big-repo.git
java -jar bfg.jar --delete-files YOUR_FILE_NAME some-big-repo.git
cd some-big-repo.git
git reflog expire --expire=now --all && git gc --prune=now --aggressive
git push

Löschen Sie einen Ordner

Wie oben, aber verwenden --delete-folders

java -jar bfg.jar --delete-folders YOUR_FOLDER_NAME some-big-repo.git

Andere Optionen

BFG ermöglicht auch noch schickere Optionen (siehe Dokumente ) wie diese:

Entfernen Sie alle Dateien, die größer als 100 MB sind, aus dem Verlauf:

java -jar bfg.jar --strip-blobs-bigger-than 100M some-big-repo.git

Wichtig!

Achten Sie beim Ausführen von BFG darauf, dass beide YOUR_FILE_NAMEund YOUR_FOLDER_NAMEtatsächlich nur Datei- / Ordnernamen sind. Sie sind keine Pfade , also foo/bar.jpgwird so etwas nicht funktionieren! Stattdessen werden alle Dateien / Ordner mit dem angegebenen Namen aus dem Repo-Verlauf entfernt, unabhängig davon, welcher Pfad oder Zweig vorhanden war.

Timo
quelle
Ich frage mich, ob ich dieses bfgTool auf ein lokales Git-Repo anwenden möchte , wie der Befehl aussehen soll.
Angel Todorov
5

Eine Option:

git gcManuell ausführen, um eine Anzahl von Packdateien in eine oder mehrere Packdateien zu komprimieren. Dieser Vorgang ist dauerhaft (dh die große Packdatei behält ihr Komprimierungsverhalten bei), daher kann es vorteilhaft sein, ein Repository regelmäßig mit zu komprimierengit gc --aggressive

Eine andere Möglichkeit besteht darin, den Code und .git irgendwo zu speichern und dann die .git zu löschen und diesen vorhandenen Code erneut zu verwenden, um ein neues git-Repository ( git init) zu erstellen .

Michael Durrant
quelle
Hallo Michael, ich habe versucht zu laufen git gcund bin auf ein paar Packdateien gekommen, aber die große ist immer noch eine davon, und ich möchte sie einfach loswerden, damit ich den Ordner extern einfacher sichern kann (zip vorher war 1) -2 MB, jetzt 55 MB). Es sei denn, jemand kann etwas anderes vorschlagen. Ich denke, ich muss möglicherweise einen neuen Idioten kreieren. Ich gehe davon aus, dass dies bedeutet, dass ich den Zugriff auf die Filialen verliere, die ich derzeit habe.
user1116573
2
Ich habe den Versuch aufgegeben und einfach den .git-Ordner gelöscht und ein neues Git-Repository erstellt, wie Sie sagten. Ich werde es als eine Lektion betrachten, die wir gelernt haben. Danke Michael.
user1116573
4
Das macht nicht viel Sinn. Warum können Sie git nicht einfach anweisen, das aktuelle Repository zu konsolidieren und dabei die Pack-Dateien zu entfernen?
jml
4

Führen Sie den folgenden Befehl aus und ersetzen Sie ihn PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATAdurch den Pfad zu der Datei, die Sie entfernen möchten, und nicht nur durch den Dateinamen. Diese Argumente werden:

  1. Erzwingen Sie, dass Git den gesamten Verlauf jedes Zweigs und Tags verarbeitet, aber nicht auscheckt
  2. Entfernen Sie die angegebene Datei sowie alle daraus resultierenden leeren Commits
  3. Überschreiben Sie Ihre vorhandenen Tags
git filter-branch --force --index-filter "git rm --cached --ignore-unmatch PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA" --prune-empty --tag-name-filter cat -- --all

Dadurch werden alle Verweise auf die Dateien zwangsweise aus dem aktiven Verlauf des Repos entfernt.

Nächster Schritt: Durchführen eines GC-Zyklus, um zu erzwingen, dass alle Verweise auf die Datei abgelaufen sind und aus der Packdatei gelöscht werden. In diesen Befehlen muss nichts ersetzt werden.

git update-ref -d refs/original/refs/remotes/origin/master
git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin
git reflog expire --expire=now --all
git gc --aggressive --prune=now
Benjamin Wasula
quelle
Ab dem 2. Teil bekam ich schließlich ein 28G Repo auf 158M. Bei Google hat fast nichts anderes funktioniert. Danke dir.
Sridhar Sarnobat
1

Ich bin etwas spät dran für die Show, aber falls die obige Antwort die Frage nicht gelöst hat, habe ich einen anderen Weg gefunden. Entfernen Sie einfach die spezifische große Datei aus .pack. Ich hatte dieses Problem, bei dem ich versehentlich eine große 2-GB-Datei eingecheckt habe. Ich habe die in diesem Link erläuterten Schritte befolgt: http://www.ducea.com/2012/02/07/howto-completely-remove-a-file-from-git-history/

Rishabh Kumar
quelle
Nach dieser Methode wird der gesamte Verlauf des Projekts vollständig entfernt, oder es wird nur die angegebene Datei entfernt.
Samim Aftab Ahmed
-3

Dies ist eher eine praktische als eine Codierungslösung. Zip die Datei. Öffnen Sie die Zip-Datei im Dateiansichtformat (anders als beim Entpacken). Löschen Sie die .pack-Datei. Entpacken und ersetzen Sie den Ordner. Klappt wunderbar!

shreya10
quelle