Ich habe an einem Repository in meinem GitHub-Konto gearbeitet und dabei bin ich auf ein Problem gestoßen.
node_modules
In diesem Fall betrug die Größe des gesamten Git-Repos ungefähr 6MB, wobei der tatsächliche Code (mit Ausnahme dieses Ordners) nur ungefähr 300 KB betrug.
Was ich jetzt am Ende suche, ist eine Möglichkeit, die Details dieses Paketordners aus dem Git-Verlauf zu entfernen. Wenn also jemand den Ordner klont, muss er keine 6 MB-Verlauf herunterladen, in denen die einzigen tatsächlichen Dateien gespeichert sind, die er erhält ab dem letzten Commit wären es 300KB.
Ich habe nach möglichen Lösungen dafür gesucht und diese beiden Methoden ausprobiert
The Gist schien dort zu funktionieren, wo nach dem Ausführen des Skripts angezeigt wurde, dass dieser Ordner entfernt wurde, und dass anschließend 50 verschiedene Commits geändert wurden. Aber ich konnte den Code nicht pushen. Als ich versuchte, es zu pushen, stand dort Branch up to date
, Aber es wurden 50 Commits auf einem git status
Geändert. Die anderen 2 Methoden haben auch nicht geholfen.
Nun, obwohl es zeigte, dass es den Verlauf dieses Ordners beseitigt hat, war es immer noch ungefähr 6 MB, als ich die Größe dieses Repos auf meinem Localhost überprüfte. (Ich habe auch den Ordner refs/original
Gelöscht, aber die Änderung der Größe des Repos nicht bemerkt.).
Was ich klarstellen möchte, ist, ob es eine Möglichkeit gibt, nicht nur den Commit-Verlauf (was meiner Meinung nach das einzige ist, was passiert ist), sondern auch die Dateien, die git beibehält, wenn man einen Rollback durchführen möchte.
Nehmen wir an, es wird eine Lösung für dieses Problem vorgestellt, die auf meinem localhost angewendet wird, aber nicht auf dieses GitHub-Repo reproduziert werden kann. Ist es möglich, dieses Repo zu klonen, einen Rollback auf das erste Commit durchzuführen und es zu pushen (oder bedeutet das, dass Git dies tut)? Haben Sie noch eine Geschichte all dieser Verpflichtungen? - aka. 6MB).
Mein Endziel hier ist es, im Grunde den besten Weg zu finden, um die Ordnerinhalte von git zu entfernen, so dass ein Benutzer keine 6MB an Material herunterladen muss und möglicherweise noch die anderen Commits hat, die den Modulordner nie berührt haben (das ist hübsch viele von ihnen) in der Geschichte von Git.
Wie kann ich das machen?
Wenn Sie hier sind, um Code zu kopieren und einzufügen:
Dies ist ein Beispiel, das node_modules
Aus dem Verlauf entfernt
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 Referenzen im selben Baum (--tree-filter) wie HEAD (Ihr aktueller Zweig)) und führt den Befehl 'rm -rf node_modules' aus. Dieser Befehl löscht die node_modules Ordner (-r, ohne -r, rm löscht keine Ordner) ohne Aufforderung an den Benutzer (-f) Das hinzugefügte --Prune-empty löscht nutzlose (ändert nichts) Commits rekursiv.
Die zweite Zeile löscht den Verweis auf diesen alten Zweig.
Der Rest der Befehle ist relativ einfach.
Ich finde, dass die in anderen Antworten verwendete Option --tree-filter
Sehr langsam sein kann, insbesondere bei größeren Repositorys mit vielen Commits.
Hier ist die Methode, mit der ich ein Verzeichnis mit der Option --index-filter
Vollständig aus dem Git-Verlauf entferne, was sehr viel schneller geht:
# 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 dem gc
überprüfen mit:
git count-objects -vH
Zusätzlich zu der populären Antwort oben möchte ich einige Anmerkungen für Windows - Systeme hinzufügen. Der Befehl
git filter-branch --tree-filter 'rm -rf node_modules' --Prune-empty HEAD
funktioniert einwandfrei ohne jegliche Änderung! Daher dürfen Sie nicht Remove-Item
, del
oder irgendetwas anderes anstelle von rm -rf
Verwenden .
Wenn Sie einen Pfad zu einer Datei oder einem Verzeichnis angeben müssen, verwenden Sie Schrägstriche wie ./path/to/node_modules
.
Die beste und genaueste Methode, die ich gefunden habe, war das Herunterladen der Datei bfg.jar: https://rtyley.github.io/bfg-repo-cleaner/
Führen Sie dann die folgenden Befehle aus:
git clone --bare https://project/repository project-repository
cd project-repository
Java -jar bfg.jar --delete-folders DIRECTORY_NAME # i.e. 'node_modules' in other examples
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
Bitte beachten Sie, dass für Windows-Benutzer "
Anstelle von '
Verwendet wird. Außerdem wurde -f
Hinzugefügt, um den Befehl zu erzwingen, wenn bereits eine andere Sicherung vorhanden ist.
git filter-branch -f --tree-filter "rm -rf FOLDERNAME" --Prune-empty HEAD
git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
echo FOLDERNAME/ >> .gitignore
git add .gitignore
git commit -m "Removing FOLDERNAME from git history"
git gc
git Push Origin master --force
Vervollständige das Rezept zum Kopieren und Einfügen, indem du die Befehle in den Kommentaren hinzufügst (für die Lösung zum Kopieren und Einfügen), nachdem du sie getestet hast:
git filter-branch --tree-filter 'rm -rf node_modules' --Prune-empty HEAD
echo node_modules/ >> .gitignore
git add .gitignore
git commit -m 'Removing node_modules from git history'
git gc
git Push Origin master --force
Danach können Sie die Zeile "node_modules /" aus .gitignore entfernen
Ich habe die Ordner bin und obj aus alten C # -Projekten mit git unter Windows entfernt. Sei vorsichtig mit
git filter-branch --tree-filter "rm -rf bin" --Prune-empty HEAD
Es zerstört die Integrität der Git-Installation, indem der Ordner usr/bin im Git-Installationsordner gelöscht wird.