497 Stimmen

Entfernen des Ordners und seines Inhalts aus dem Verlauf von Git/GitHub

Ich habe an einem Repository auf meinem GitHub-Konto gearbeitet und bin über dieses Problem gestolpert.

  • Node.js-Projekt mit einem Ordner, in dem ein paar npm-Pakete installiert sind
  • Die Pakete waren in node_modules Ordner
  • Den Ordner zum Git-Repository hinzugefügt und den Code auf Github gepusht (zu diesem Zeitpunkt habe ich nicht an den npm-Teil gedacht)
  • Ich habe festgestellt, dass dieser Ordner nicht wirklich Teil des Codes sein muss.
  • Diesen Ordner gelöscht, verschoben

Zu diesem Zeitpunkt betrug die Größe des gesamten Git-Repositoriums etwa 6MB wo der eigentliche Code (alles außer diesem Ordner) nur etwa 300 KB .

Nun, was ich am Ende suche, ist ein Weg, um die Details dieses Paketordners aus der Git-Historie loszuwerden, so dass, wenn jemand es klont, sie nicht 6mb im Wert von Geschichte herunterladen müssen, wo die einzigen tatsächlichen Dateien, die sie ab der letzten Übertragung erhalten würden, 300KB sein würden.

Ich habe nach möglichen Lösungen für dieses Problem gesucht und diese 2 Methoden ausprobiert

Das Gist schien zu funktionieren, da es nach dem Ausführen des Skripts anzeigte, dass der Ordner gelöscht wurde und danach zeigte es an, dass 50 verschiedene Commits geändert wurden. Aber es ließ mich den Code nicht pushen. Als ich versuchte, ihn zu pushen, sagte es Branch up to date zeigte aber, dass 50 Übertragungen bei einer git status . Die anderen 2 Methoden haben auch nicht geholfen.

Obwohl es anzeigte, dass die Historie des Ordners gelöscht wurde, war die Größe des Repos auf meinem Localhost immer noch rund 6 MB groß. (Ich habe auch die refs/original aber die Größe des Projektarchivs hat sich nicht geändert).

Was ich zu klären suche, ist, ob es eine Möglichkeit gibt, nicht nur die Commit-Historie loszuwerden (was das Einzige ist, von dem ich glaube, dass es passiert ist), sondern auch die Dateien, die Git behält, wenn man ein Rollback machen will.

Sagen wir, eine Lösung für diese präsentiert wird und auf meinem localhost angewendet wird, aber kann nicht reproduziert werden, dass GitHub Repo, ist es möglich, dass Repo zu klonen, Rollback zum ersten Commit führen Sie den Trick und pushen Sie es (oder bedeutet das, dass Git noch eine Geschichte von all diesen Commits haben wird? - aka. 6MB).

Mein Endziel hier ist im Grunde den besten Weg zu finden, um den Ordnerinhalt von Git loszuwerden, so dass ein Benutzer nicht 6MB im Wert von Sachen herunterladen muss und immer noch möglicherweise die anderen Commits, die nie berührt den Ordner Module (das ist so ziemlich alle von ihnen) in Git Geschichte haben.

Wie kann ich das tun?

688voto

Mohsen Punkte 61518

_WARNUNG : git filter-branch ist nicht mehr offiziell empfohlen . Die offizielle Empfehlung lautet, Folgendes zu verwenden git-filter-repo ; siehe André Anjos' Antwort für Details ._


Wenn Sie hier sind, um Code zu kopieren und einzufügen:

Dies ist ein Beispiel für die Beseitigung von node_modules aus der Geschichte

git filter-branch --tree-filter "rm -rf node_modules" --prune-empty HEAD
git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
echo node_modules/ >> .gitignore
git add .gitignore
git commit -m 'Removing node_modules from git history'
git gc
git push origin master --force

Was git eigentlich macht:

Die erste Zeile durchläuft alle Verweise auf denselben Baum ( --tree-filter ) als HEAD (Ihr aktueller Zweig), indem Sie den Befehl rm -rf node_modules . Dieser Befehl löscht den Ordner node_modules ( -r , ohne -r , rm löscht keine Ordner), ohne dass der Benutzer eine Aufforderung erhält ( -f ). Der Zusatz --prune-empty löscht nutzlose (nichts verändernde) Commits rekursiv.

Die zweite Zeile löscht den Verweis auf diesen alten Zweig.

Der Rest der Befehle ist relativ einfach.

332voto

Lee Netherton Punkte 19699

Ich finde, dass die --tree-filter Option, die in anderen Antworten verwendet wird, kann sehr langsam sein, besonders bei größeren Repositories mit vielen Commits.

Hier ist die Methode, die ich verwende, um ein Verzeichnis vollständig aus der Git-Historie zu entfernen, indem ich die --index-filter die viel schneller läuft:

# Make a fresh clone of YOUR_REPO
git clone YOUR_REPO
cd YOUR_REPO

# Create tracking branches of all branches
for remote in `git branch -r | grep -v /HEAD`; do git checkout --track $remote ; done

# Remove DIRECTORY_NAME from all commits, then remove the refs to the old commits
# (repeat these two commands for as many directories that you want to remove)
git filter-branch --index-filter 'git rm -rf --cached --ignore-unmatch DIRECTORY_NAME/' --prune-empty --tag-name-filter cat -- --all
git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d

# Ensure all old refs are fully removed
rm -Rf .git/logs .git/refs/original

# Perform a garbage collection to remove commits with no refs
git gc --prune=all --aggressive

# Force push all branches to overwrite their history
# (use with caution!)
git push origin --all --force
git push origin --tags --force

Sie können die Größe des Repositorys vor und nach der gc mit:

git count-objects -vH

202voto

André Anjos Punkte 3673

Die aktuelle Antwort auf diese Frage scheint zu sein, dass no utilice filter-branch direkt zu verwenden (zumindest wird dies von Git selbst nicht mehr empfohlen) und diese Arbeit auf ein externes Tool zu verlagern. Im Besonderen, git-filter-repo wird derzeit empfohlen. Der Autor dieses Tools liefert Argumente darüber, warum die Verwendung von filter-branch direkt zu Problemen führen kann.

Die meisten der oben genannten mehrzeiligen Skripte zum Entfernen von dir aus der Geschichte könnte umgeschrieben werden als:

git filter-repo --path dir --invert-paths

Das Werkzeug ist offensichtlich viel leistungsfähiger als nur das. Sie können Filter nach Autor, E-Mail, Artikelname und mehr anwenden ( vollständige Manpage hier ). Außerdem ist es schnell . Die Installation ist einfach - es ist in einer Vielzahl von Formaten verteilt .

58voto

participant Punkte 2861

Zusätzlich zu der beliebten Antwort über Ich möchte noch einige Anmerkungen machen für Windows -Systeme. Der Befehl

git filter-branch --tree-filter 'rm -rf node_modules' --prune-empty HEAD
  • funktioniert perfekt ohne jegliche Änderung! Deshalb, Sie dürfen nicht utilice Remove-Item , del oder etwas anderes anstelle von rm -rf .

  • Wenn Sie einen Pfad zu einer Datei oder einem Verzeichnis angeben müssen, verwenden Sie Schrägstriche のように ./path/to/node_modules

30voto

Kim T Punkte 4542

Die beste und genaueste Methode, die ich gefunden habe, ist der Download der Datei bfg.jar: https://rtyley.github.io/bfg-repo-cleaner/

Führen Sie dann die Befehle aus:

git clone --bare https://project/repository project-repository
cd project-repository
java -jar bfg.jar --delete-folders DIRECTORY_NAME
git reflog expire --expire=now --all && git gc --prune=now --aggressive
git push --mirror https://project/new-repository

Wenn Sie Dateien löschen möchten, verwenden Sie stattdessen die Option delete-files:

java -jar bfg.jar --delete-files *.pyc

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X