Datei aus dem Git-Repository entfernen (Verlauf)

78

(gelöst, siehe unten im Fragetext)
Wenn ich schon lange danach suche, habe ich bis jetzt Folgendes:

Ziemlich die gleiche Methode, aber beide belassen Objekte in Packdateien ... stecken geblieben.
Was ich versucht habe:

git filter-branch --index-filter 'git rm --cached --ignore-unmatch file_name'
rm -Rf .git/refs/original
rm -Rf .git/logs/
git gc

Ich habe immer noch Dateien im Paket, und so weiß ich es:

git verify-pack -v .git/objects/pack/pack-3f8c0...bb.idx | sort -k 3 -n | tail -3

Und das:

git filter-branch --index-filter "git rm -rf --cached --ignore-unmatch file_name" HEAD
rm -rf .git/refs/original/ && git reflog expire --all &&  git gc --aggressive --prune

Das Gleiche...

Versucht git cloneTrick, es entfernte einige der Dateien (~ 3000 von ihnen), aber die größten Dateien sind noch da ...

Ich habe einige große Legacy-Dateien im Repository, ~ 200M, und ich möchte sie wirklich nicht dort haben ... Und ich möchte das Repository nicht auf 0 zurücksetzen :(

LÖSUNG: Dies ist der kürzeste Weg, um die Dateien loszuwerden:

  1. check .git / packed-refs - mein Problem war, dass ich dort eine refs/remotes/origin/masterZeile für ein Remote-Repository hatte, es löschen, sonst wird git diese Dateien nicht entfernen
  2. (optional) git verify-pack -v .git/objects/pack/#{pack-name}.idx | sort -k 3 -n | tail -5 - um nach den größten Dateien zu suchen
  3. (optional) git rev-list --objects --all | grep a0d770a97ff0fac0be1d777b32cc67fe69eb9a98 - um zu überprüfen, was diese Dateien sind
  4. git filter-branch --index-filter 'git rm --cached --ignore-unmatch file_names' - um eine Datei aus allen Revisionen zu entfernen
  5. rm -rf .git/refs/original/ - um das Backup von git zu entfernen
  6. git reflog expire --all --expire='0 days' - um alle losen Gegenstände zu verfallen
  7. git fsck --full --unreachable - um zu überprüfen, ob lose Gegenstände vorhanden sind
  8. git repack -A -d - Umpacken
  9. git prune - um diese Objekte endgültig zu entfernen
Boris Churzin
quelle
zneak - meine frage steht im titel. gbacon - probiert die, die Dateien bleiben noch in der Pack-Datei ...
Boris Churzin
Wenn Sie sich den Artikel ansehen, auf den in den Duplikaten verwiesen wird, wird gezeigt, wie Sie Ihren Objektspeicher komprimieren, nachdem die fehlerhafte Datei entfernt wurde.
Kyle Butt
1
Dies war ein Lebensretter. Mentale Anmerkung: Fügen Sie .gitignore immer potenziell große * .log-Dateien hinzu. Ging von einem 800mb Repo auf 6mb danach.
JackCA
1
Schritt 2 und 3 in einem for i in `git verify-pack -v .git/objects/pack/#{pack-name}.idx | sort -k 3 -n | tail -5` ; do git rev-list --objects --all | grep $(echo $i | sed 's/ .*//g') ; done
Geermc4

Antworten:

65

Ich kann nicht sicher sagen, ohne Zugriff auf Ihre Repository-Daten, aber ich glaube, es gibt wahrscheinlich einen oder mehrere gepackte Refs, die noch auf alte Commits von vor Ihrer Ausführung verweisen git filter-branch. Dies würde erklären, warumgit fsck --full --unreachable der große Blob nicht als nicht erreichbares Objekt bezeichnet wird, obwohl Sie Ihr Reflog abgelaufen und die ursprünglichen (entpackten) Refs entfernt haben.

Folgendes würde ich tun (nachdem git filter-branchund git gcgetan worden bin):

1) Stellen Sie sicher, dass die Originalreferenzen weg sind:

rm -rf .git/refs/original

2) Alle Reflog-Einträge verfallen lassen:

git reflog expire --all --expire='0 days'

3) Überprüfen Sie, ob alte Refs verpackt sind

Dies kann möglicherweise schwierig sein, je nachdem, wie viele Refs Sie haben. Ich kenne keine Git-Befehle, die dies automatisieren, daher denke ich, dass Sie dies manuell tun müssen. Erstellen Sie ein Backup von .git/packed-refs. Jetzt bearbeiten .git/packed-refs. Überprüfen Sie, ob alte Refs vorhanden sind (insbesondere, ob die Refs von verpackt wurden).git/refs/original ). Wenn Sie alte finden, die nicht vorhanden sein müssen, löschen Sie sie (entfernen Sie die Zeile für diesen Verweis).

Überprüfen Sie nach dem Bereinigen der packed-refsDatei, ob git fsckdie nicht erreichbaren Objekte angezeigt werden:

git fsck --full --unreachable

Wenn dies funktioniert hat und git fsckIhr großer Blob nun als nicht erreichbar gemeldet wird, können Sie mit dem nächsten Schritt fortfahren.

4) Packen Sie Ihre gepackten Archive neu ein

git repack -A -d

Dadurch wird sichergestellt, dass die nicht erreichbaren Objekte ausgepackt werden und ausgepackt bleiben .

5) Beschneiden Sie lose (nicht erreichbare) Gegenstände

git prune

Und das sollte es tun. Git sollte wirklich eine bessere Möglichkeit haben, gepackte Refs zu verwalten. Vielleicht gibt es einen besseren Weg, den ich nicht kenne. In Ermangelung eines besseren Weges packed-refskönnte die manuelle Bearbeitung der Datei der einzige Weg sein.

Dan Moulding
quelle
1
Yey !!! Ich liebe dich ! Das Problem war in der gepackten Refs-Datei, es gab Refs / Fernbedienungen / Ursprung / Master aus der Zeit, als ich es auf einem Server gesichert habe ... als ich es entfernt hatte, begann alles zu verschwinden ... Danke! (Aktualisierung des
Fragenkörpers
15

Ich würde empfehlen, den BFG Repo-Cleaner zu verwenden , eine einfachere und schnellere Alternative zu dem git-filter-branchspeziell für das Umschreiben von Dateien aus dem Git-Verlauf entwickelten. Eine Möglichkeit, Ihr Leben hier einfacher zu machen, besteht darin, dass standardmäßig alle Referenzen behandelt werden (alle Tags, Zweige, Dinge wie Refs / Fernbedienungen / Ursprung / Master usw.), aber es ist auch 10-50x schneller.

Befolgen Sie diese Schritte hier sorgfältig: http://rtyley.github.com/bfg-repo-cleaner/#usage - aber das Kernbit ist genau das: Laden Sie das JAR der BFG herunter (erfordert Java 6 oder höher) und führen Sie diesen Befehl aus ::

$ java -jar bfg.jar  --delete-files file_name  my-repo.git

Alle benannten Dateien file_name(die nicht in Ihrem letzten Commit enthalten sind) werden vollständig aus dem Verlauf Ihres Repositorys entfernt . Sie können dann git gcdie toten Daten entfernen:

$ git gc --prune=now --aggressive

Das BFG ist im Allgemeinen viel einfacher zu verwenden als git-filter-branch- die Optionen sind auf diese beiden gängigen Anwendungsfälle zugeschnitten:

  • Verrückte große Dateien entfernen
  • Entfernen von Passwörtern, Anmeldeinformationen und anderen privaten Daten

Vollständige Offenlegung: Ich bin der Autor des BFG Repo-Cleaner.

Roberto Tyley
quelle
Bereinigt dies auch private Daten von Remote-Repos nach dem Push?
Thomas Lauria
@ThomasLauria yup, die gleichen gereinigten Refs werden beim Drücken auf Remote-Repos übertragen - die Anweisungen unter rtyley.github.io/bfg-repo-cleaner/#usage sollten dies abdecken. Wenn Sie die Kontrolle über das Remote-Repo haben, können Sie nach dem Drücken auch "git gc --prune = now --aggressive" darauf ausführen, um sicherzustellen, dass tote Objekte auch sofort daraus entfernt werden.
Roberto Tyley
@RobertoTyley Dies kann dazu führen, dass zwei Commits im Verlauf nacheinander angezeigt werden und denselben Baum haben (wenn bei einem dieser Commits nur die gelöschten Dateien hinzugefügt wurden). Kennen Sie eine einfache Möglichkeit, solche Commits aus dem Commit-Verlauf zu entfernen, da sie künstlich erscheinen?
user44400
@ RobertoTyley Ich denke, das betrifft ein anderes Problem. In dem von mir beschriebenen Fall ist nur ein Repository beteiligt. Aber git filter-branch --prune-emptyscheint die Lösung für meine Frage zu sein (obwohl Sie ein anderes Tool verwenden, lassen Sie mich bitte wissen, ob der BFG Repo-Cleaner dasselbe tun kann).
user44400
6

Ich fand dies sehr hilfreich beim Entfernen eines ganzen Ordners, da mir das oben Genannte nicht wirklich geholfen hat: https://help.github.com/articles/remove-sensitive-data .

Ich benutzte:

git filter-branch -f --force \
--index-filter 'git rm -rf --cached --ignore-unmatch folder/sub-folder' \
--prune-empty --tag-name-filter cat -- --all

rm -rf .git/refs/original/
git reflog expire --expire=now --all
git gc --prune=now
git gc --aggressive --prune=now
Mike Averto
quelle
5

Ich habe versucht, eine große Datei in der Geschichte loszuwerden, und die obigen Antworten haben bis zu einem gewissen Punkt funktioniert. Der Punkt ist: Sie funktionieren nicht, wenn Sie Tags haben. Wenn das Commit mit der großen Datei über ein Tag erreichbar ist, müssen Sie den Befehl filter-branchs folgendermaßen anpassen:

git filter-branch --tag-name-filter cat \
--index-filter 'git rm --cached --ignore-unmatch huge_file_name' -- \
--all --tags
BHMulder
quelle
2

Siehe: Wie entferne ich vertrauliche Dateien aus dem Git-Verlauf?

Das Obige schlägt fehl, wenn die Datei in einer Version nicht vorhanden ist. In diesem Fall behebt der Schalter '--ignore-unmatch' das Problem:

git filter-branch -f --index-filter 'git rm --cached --ignore-unmatch <filename>' HEAD

Um dann alle losen Gegenstände aus dem Repostiry herauszuholen:

git gc --prune='0 days ago'
Wayne Conrad
quelle
Ja, habe es versucht, habe immer noch die Dateien im Paket, und die Größe hat sich nicht zu sehr geändert ...
Boris Churzin
Ich habe gerade einen Git-Sandkasten gemacht und es versucht. Auch hier nicht gut. Mal sehen, was ich herausfinden kann.
Wayne Conrad
Der in der Antwort? :) Es ist das gleiche wie ich gepostet habe, und es lässt die Datei immer noch im Paket ... versuchen Sie es mit einer Git-Sandbox, machen Sie Git-GC, damit es die Datei packt, und führen Sie diese dann aus ...
Boris Churzin
Oh, die losen Gegenstände? Siehe oben. Ich würde dazu neigen, sie in zwei Wochen Müll sammeln zu lassen (die Standardeinstellung für gc); Das Töten aller losen Gegenstände ist wie das Leeren des Mülls - ich verliere alle Möglichkeiten, etwas zurückzubekommen, das ich versehentlich gelöscht habe.
Wayne Conrad
:) habe es auch versucht ... habe einige der Dateien entfernt, aber die größten sind noch da ...
Boris Churzin
2

Sie haben verschiedene Gründe für eine immer noch große Git-Repo-Größe git gc, da nicht alle losen Gegenstände entfernt werden .

Ich erläutere diese Gründe in " Reduzieren der Größe des Git-Repositorys" ".

Ein Trick, den Sie in Ihrem Fall testen sollten, wäre das Klonen Ihres "bereinigten" Git-Repos und ob der Klon die richtige Größe hat.

('"gereinigtes" Repo' ist das, bei dem Sie das angewendet haben filter-branch, und dann gcund prune)

VonC
quelle
Ja, habe es bereits getestet und jetzt erneut getestet, es hat das Repository um 2k reduziert :) und die Dateien sind immer noch da ...
Boris Churzin
Was seltsam ist git count-objects -v -> count: 0, size: 0, in-pack: 10021, packs: 1, size-pack: 244547, prune-packable: 0, garbage: 0, ist aber:git clone test1 test2 -> Checking out files: 100% (8509/8509), done
Boris Churzin
1

Ich hatte das gleiche Problem und fand auf Github ein großartiges Tutorial , in dem Schritt für Schritt erklärt wird, wie Sie versehentlich festgeschriebene Dateien entfernen können.

Hier ist eine kleine Zusammenfassung des Verfahrens, wie es Cupcake vorgeschlagen hat.

Wenn Sie eine Datei mit dem Namen haben file_to_remove, die aus dem Verlauf entfernt werden soll:

cd path_to_parent_dir

git filter-branch --force --index-filter \
  'git rm --cached --ignore-unmatch file_to_remove' \
  --prune-empty --tag-name-filter cat -- --all
Cyril Leroux
quelle
1
Nur-Link-Antworten werden beim Stapelüberlauf dringend empfohlen. Wenn der Link in Zukunft unterbrochen wird, wird die Antwort unbrauchbar. Bitte fassen Sie die relevanten Informationen zusammen, die in dem Link in Ihrer Antwort enthalten sind.