186 votes

Suppression d'un gros fichier .pack créé par git

J'ai intégré un grand nombre de fichiers dans une branche et j'ai fusionné, puis j'ai dû les supprimer et maintenant je me retrouve avec un gros fichier .pack dont je ne sais pas comment me débarrasser.

J'ai supprimé tous les fichiers en utilisant git rm -rf xxxxxx et j'ai également exécuté le --cached également.

Quelqu'un peut-il me dire comment je peux supprimer un gros fichier .pack qui se trouve actuellement dans le répertoire suivant :

.git/objects/pack/pack-xxxxxxxxxxxxxxxxx.pack

Dois-je simplement supprimer la branche que j'ai encore mais que je n'utilise plus ? Ou dois-je faire quelque chose d'autre ?

Je ne suis pas sûr que cela fasse une grande différence, mais un cadenas apparaît contre le fichier.

Gracias


EDIT

Voici quelques extraits de mon bash_history qui devraient vous donner une idée de la façon dont j'ai réussi à me mettre dans cet état (supposons qu'à ce stade, je travaille sur une branche git appelée "ma-branche" et que j'ai un dossier contenant d'autres dossiers/fichiers) :

git add .
git commit -m "Adding my branch changes to master"
git checkout master
git merge my-branch
git rm -rf unwanted_folder/
rm -rf unwanted_folder/     (not sure why I ran this as well but I did)

Je pensais avoir également exécuté la commande suivante, mais elle n'apparaît pas dans l'historique de bash avec les autres :

git rm -rf --cached unwanted_folder/

J'ai également pensé que j'avais exécuté quelques commandes git (comme git gc ) pour essayer de mettre de l'ordre dans le fichier pack mais ils n'apparaissent pas non plus dans le fichier .bash_history.

262voto

loganfsmyth Points 25483

Le problème est que, même si vous avez supprimé les fichiers, ils sont toujours présents dans les révisions précédentes. C'est tout l'intérêt de git : même si vous supprimez quelque chose, vous pouvez toujours le récupérer en accédant à l'historique.

Ce que vous cherchez à faire s'appelle réécrire l'histoire. git filter-branch commande.

GitHub a une bonne explication du problème sur son site. https://help.github.com/articles/remove-sensitive-data

Pour répondre plus directement à votre question, vous devez exécuter cette commande avec unwanted_filename_or_folder remplacés en conséquence :

git filter-branch --index-filter 'git rm -r --cached --ignore-unmatch unwanted_filename_or_folder' --prune-empty

Cela supprimera toutes les références aux fichiers de l'historique actif du repo.

L'étape suivante consiste à effectuer un cycle GC pour forcer toutes les références au fichier à expirer et à être supprimées du fichier d'emballage. Rien ne doit être remplacé dans ces commandes.

git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin
# or, for older git versions (e.g. 1.8.3.1) which don't support --stdin
# git update-ref $(git for-each-ref --format='delete %(refname)' refs/original)
git reflog expire --expire=now --all
git gc --aggressive --prune=now

22voto

onlynone Points 472

Scénario A : Si vos fichiers volumineux n'ont été ajoutés qu'à une branche, vous n'avez pas besoin d'exécuter la commande git filter-branch . Il suffit de supprimer la branche et de lancer le ramassage des ordures :

git branch -D mybranch
git reflog expire --expire-unreachable=all --all
git gc --prune=all

Scénario B : Cependant, il semble, d'après votre historique bash, que vous ayez fusionné les changements dans master. Si vous n'avez partagé les changements avec personne (pas de git push encore). La chose la plus simple serait de réinitialiser master avant la fusion avec la branche qui contenait les gros fichiers. Cela éliminera tous les commits de votre branche et tous les commits faits sur master après la fusion. Vous risquez donc de perdre des modifications - en plus des gros fichiers - que vous auriez pu souhaiter :

git checkout master
git log # Find the commit hash just before the merge
git reset --hard <commit hash>

Exécutez ensuite les étapes du scénario A.

Scénario C : S'il y a eu d'autres changements dans la branche ou sur master après la fusion que vous souhaitez conserver, il serait préférable de rebaser master et d'inclure sélectivement les commits que vous souhaitez :

git checkout master
git log # Find the commit hash just before the merge
git rebase -i <commit hash>

Dans votre éditeur, supprimez les lignes correspondant aux modifications qui ont ajouté les gros fichiers, mais laissez tout le reste tel quel. Sauvegardez et quittez. Votre branche master ne devrait contenir que ce que vous voulez, et aucun fichier volumineux. Notez que git rebase sans -p éliminera les commits de fusion, de sorte que vous aurez un historique linéaire pour le master après que <commit hash> . Cela vous convient probablement, mais si ce n'est pas le cas, vous pouvez essayer avec -p mais git help rebase dit combining -p with the -i option explicitly is generally not a good idea unless you know what you are doing .

Exécutez ensuite les commandes du scénario A.

18voto

Benjamin Wasula Points 121

Exécutez la commande suivante, en remplaçant PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA avec le chemin d'accès au fichier que vous souhaitez supprimer, et pas seulement son nom de fichier. Ces arguments seront :

  1. Forcer Git à traiter, mais pas à extraire, l'historique complet de chaque branche et balise
  2. Supprime le fichier spécifié, ainsi que tous les commits vides générés en conséquence
  3. Remplacer les balises existantes

    git filter-branch --force --index-filter "git rm --cached --ignore-unmatch PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA" --prune-empty --tag-name-filter cat -- --all

Cela supprimera de force toutes les références aux fichiers de l'historique actif du repo.

L'étape suivante consiste à effectuer un cycle GC pour forcer toutes les références au fichier à expirer et à être supprimées du fichier pack. Rien ne doit être remplacé dans ces commandes.

git update-ref -d refs/original/refs/remotes/origin/master
git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin
git reflog expire --expire=now --all
git gc --aggressive --prune=now

15voto

Timo Points 2412

Comme Loganfsmyth l'a déjà indiqué dans son répondre Dans ce cas, vous devez purger l'historique git car les fichiers continuent d'y exister même après les avoir supprimés du repo. Documentation officielle de GitHub recommander BFG que je trouve plus facile à utiliser que filter-branch :

Supprimer des fichiers de l'historique

Télécharger BFG sur leur site internet. Assurez-vous d'avoir installé Java, puis créez un clone miroir et purgez l'historique. Assurez-vous de remplacer YOUR_FILE_NAME avec le nom du fichier que vous souhaitez supprimer :

git clone --mirror git://example.com/some-big-repo.git
java -jar bfg.jar --delete-files YOUR_FILE_NAME some-big-repo.git
cd some-big-repo.git
git reflog expire --expire=now --all && git gc --prune=now --aggressive
git push

Supprimer un dossier

Même chose que ci-dessus, mais utilisez --delete-folders

java -jar bfg.jar --delete-folders YOUR_FOLDER_NAME some-big-repo.git

Autres options

BFG permet également des options encore plus fantaisistes (voir documents ) comme ceux-ci :

Supprimer tous les fichiers de plus de 100M de l'historique :

java -jar bfg.jar --strip-blobs-bigger-than 100M some-big-repo.git

Important !

Lors de l'utilisation de BFG, veillez à ce que les deux YOUR_FILE_NAME et YOUR_FOLDER_NAME ne sont en effet que des noms de fichiers/dossiers. Ce ne sont pas des chemins et donc quelque chose comme foo/bar.jpg ne fonctionnera pas ! Au lieu de cela, tous les fichiers/dossiers avec le nom spécifié seront supprimés de l'historique du repo, quel que soit le chemin ou la branche dans laquelle ils existaient.

8voto

Michael Durrant Points 30342

Une option :

courir git gc manuellement pour condenser un certain nombre de fichiers d'emballage en un ou quelques fichiers d'emballage. Cette opération est persistante (c'est-à-dire que le gros fichier pack conservera son comportement de compression), il peut donc être bénéfique de compresser un référentiel périodiquement avec la commande git gc --aggressive

Une autre option consiste à sauvegarder le code et le fichier .git quelque part, puis à supprimer le fichier .git et à recommencer en utilisant le code existant, en créant un nouveau dépôt git ( git init ).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X