web-dev-qa-db-fra.com

Supprimer le dossier et son contenu de l'historique de git / GitHub

Je travaillais sur un référentiel sur mon compte GitHub et je suis tombé sur un problème.

  • Projet Node.js avec un dossier avec quelques paquets npm installés
  • Les paquets étaient dans le dossier node_modules
  • Ajout de ce dossier dans le dépôt git et transmission du code à github (je ne pensais pas à la partie npm à ce moment-là)
  • Réalisé que vous n'avez pas vraiment besoin de ce dossier pour faire partie du code
  • Supprimé ce dossier, poussé

À ce moment-là, la taille du total des dépôts git était d’environ 6 Mo , le code réel (tous les fichiers sauf ce dossier) étant d’environ 300 KB .

Ce que je recherche à la fin, c’est un moyen de supprimer les détails de ce dossier dans l’historique de git. Ainsi, si quelqu'un le copie, il n’est pas nécessaire de télécharger 6 Mo d’historique, où se trouvent les seuls fichiers qu’ils obtiendront. à partir du dernier commit serait 300KB.

J'ai cherché des solutions possibles pour cela et essayé ces 2 méthodes

Il semblait que Gist fonctionnait à un endroit où, après avoir exécuté le script, il a montré qu’il s’était débarrassé de ce dossier, puis que 50 commits différents avaient été modifiés. Mais cela ne m'a pas laissé pousser ce code. Lorsque j’ai essayé d’appuyer sur Push, il a déclaré Branch up to date mais a montré que 50 commits ont été modifiés sur un git status. Les 2 autres méthodes n'ont pas aidé non plus.

Maintenant, même si cela montrait qu'il s'était débarrassé de l'historique de ce dossier, lorsque j'ai vérifié la taille de ce dépôt sur mon hôte local, il était toujours d'environ 6 Mo. (J'ai également supprimé le dossier refs/original mais je n'ai pas vu le changement de taille du référentiel).

Ce que je cherche à clarifier, c’est qu’il existe un moyen de supprimer non seulement l’historique des mises à jour (ce qui est la seule chose qui me semble avoir été commise), mais également ces fichiers que git maintient en supposant que l’on veut revenir en arrière.

Disons qu'une solution est présentée pour cela et qu'elle est appliquée sur mon hôte local mais ne peut pas être reproduite sur ce rapport GitHub, est-il possible de cloner ce rapport, de revenir au premier commit et de le pousser (ou est-ce que cela signifie que git avez-vous toujours une histoire de tous ces commits? (alias 6MB).

Mon objectif final est ici de trouver le meilleur moyen de supprimer le contenu du dossier de git afin qu’un utilisateur n’ait pas à télécharger une quantité de fichiers de 6Mo et éventuellement avoir les autres commits qui n’ont jamais touché le dossier modules ( beaucoup d'entre eux) dans l'histoire de git.

Comment puis-je faire ceci?

267
Kartik

Si vous êtes ici pour copier/coller du code:

Ceci est un exemple qui supprime node_modules de l'historique

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

ce que fait réellement:

La première ligne parcourt toutes les références de la même arborescence (--tree-filter) que HEAD (votre branche actuelle), en exécutant la commande 'rm -rf node_modules'. Cette commande supprime le dossier node_modules (-r, sans -r, rm ne supprimera pas de dossiers), sans invite donnée à l'utilisateur (-f). Le paramètre ajouté --Prune-empty supprime les modifications inutiles (sans rien changer) et les valide de manière récursive.

La deuxième ligne supprime la référence à cette ancienne branche.

Le reste des commandes est relativement simple.

468
Mohsen

Je trouve que l'option --tree-filter utilisée dans d'autres réponses peut être très lente, en particulier sur les référentiels plus grands comportant de nombreux commits.

Voici la méthode que j'utilise pour supprimer complètement un répertoire de l'historique git en utilisant l'option --index-filter, qui s'exécute beaucoup plus rapidement:

# 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

Vous pouvez vérifier la taille du référentiel avant et après le gc avec:

git count-objects -vH
196
Lee Netherton

En plus de la réponse populaire ci-dessus , j'aimerais ajouter quelques notes pour les systèmes Windows . La commande

git filter-branch --tree-filter 'rm -rf node_modules' --Prune-empty HEAD
  • fonctionne parfaitement sans aucune modification ! Par conséquent, vous ne devez pas utiliser Remove-Item, del ou quoi que ce soit d'autre que rm -rf.

  • Si vous devez spécifier un chemin d'accès à un fichier ou à un répertoire, utilisez des barres obliques telles que ./path/to/node_modules

38
participant

La meilleure et la plus précise des méthodes que j'ai trouvées consistait à télécharger le fichier bfg.jar: https://rtyley.github.io/bfg-repo-cleaner/

Puis lancez les commandes:

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

Si vous souhaitez supprimer des fichiers, utilisez plutôt l'option delete-files:

Java -jar bfg.jar --delete-files *.pyc
20
Kim T

Pour les utilisateurs Windows, veuillez noter que vous devez utiliser " au lieu de '. Vous avez également ajouté -f pour forcer la commande si une autre sauvegarde est déjà présente.

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

Terminez la recette copier-coller, en ajoutant simplement les commandes dans les commentaires (pour la solution de copier-coller), après les avoir testées:

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

Après cela, vous pouvez supprimer la ligne "node_modules /" de .gitignore

5
jgbarah

J'ai supprimé les dossiers bin et obj de vieux projets C # en utilisant git sous Windows. Attention à

git filter-branch --tree-filter "rm -rf bin" --Prune-empty HEAD

Cela détruit l'intégrité de l'installation de git en supprimant le dossier usr/bin dans le dossier d'installation de git.

3
LordObi