web-dev-qa-db-de.com

Entfernen Sie den Ordner und seinen Inhalt aus dem git / GitHub-Verlauf

Ich habe an einem Repository in meinem GitHub-Konto gearbeitet und dabei bin ich auf ein Problem gestoßen.

  • Node.js-Projekt mit einem Ordner, in dem einige npm-Pakete installiert sind
  • Die Pakete befanden sich im Ordner node_modules
  • Fügte diesen Ordner zum Git-Repository hinzu und schob den Code nach Github (dachte damals nicht an den NPM-Teil)
  • Es wurde erkannt, dass Sie diesen Ordner nicht wirklich benötigen, um Teil des Codes zu sein
  • Löschte diesen Ordner, schob ihn

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?

267
Kartik

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.

468
Mohsen

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
196
Lee Netherton

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.

38
participant

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
20
Kim T

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
5
kcode

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

5
jgbarah

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.

3
LordObi