Supprimer le gros fichier .pack créé par git

112

J'ai archivé une charge de fichiers dans une branche et fusionné, puis j'ai dû les supprimer et il me reste maintenant un gros fichier .pack dont je ne sais pas comment me débarrasser.

J'ai supprimé tous les fichiers en utilisant git rm -rf xxxxxxet j'ai également exécuté l' --cachedoption.

Quelqu'un peut-il me dire comment 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 y a-t-il autre chose dont j'ai besoin pour courir?

Je ne sais pas quelle différence cela fait mais il montre un cadenas contre le fichier.

Merci


ÉDITER

Voici quelques extraits de mon bash_history qui devraient donner une idée de la façon dont j'ai réussi à entrer dans cet état (supposons qu'à ce stade je travaille sur une branche git appelée 'my-branch' et que j'ai un dossier contenant plus de dossiers / des dossiers):

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 aussi exécuté ce qui suit mais il n'apparaît pas dans le bash_history avec les autres:

git rm -rf --cached unwanted_folder/

Je pensais aussi avoir exécuté des commandes git (comme git gc) pour essayer de ranger le fichier du pack mais elles n'apparaissent pas non plus dans le fichier .bash_history.

user1116573
la source
Pouvez-vous préciser comment vous les avez supprimés? S'ils sont toujours dans l'historique des validations, ils sont toujours dans vos fichiers de pack.
loganfsmyth
Salut @loganfsmyth, j'ai ajouté les scripts d'historique bash qui, espérons-le, vous aideront.
user1116573

Réponses:

201

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, c'est que 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 la réécriture de l'historique, et cela impliquait la git filter-branchcommande.

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

Pour répondre plus directement à votre question, vous devez essentiellement exécuter cette commande en unwanted_filename_or_folderremplaçant 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 dépôt.

Étape suivante, effectuer un cycle GC pour forcer toutes les références au fichier à expirer et à purger du packfile. 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
loganfsmyth
la source
3
Je l'ai marqué comme accepté si cela facilite la tâche à quiconque aborde cette question à l'avenir, bien que j'aie résolu mon problème à l'époque en créant un nouveau
dépôt
3
Je ne sais pas comment tu as trouvé ça mais ... Toi l'homme. Merci.
Ezekiel Victor
5
Cette réponse m'a orienté dans la bonne direction. Mais pour supprimer réellement les fichiers, 3 commandes supplémentaires sont nécessaires 1) git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin2) git reflog expire --expire=now --all3)git gc --prune=now
arod
3
Je trouve l'utilisation bfgbeaucoup plus facile. Il est également recommandé dans la documentation officielle de github: help.github.com/articles/…
Timo
2
@Timo Il est bon d'ajouter une nouvelle réponse, si les choses ont changé avec le temps. Fonce!
loganfsmyth
12

Scénario A : Si vos gros fichiers ont été ajoutés uniquement à une branche, vous n'avez pas besoin de l'exécuter git filter-branch. Il vous suffit de supprimer la branche et d'exécuter le garbage collection:

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 de bash, que vous ayez fusionné les modifications dans master. Si vous n'avez partagé les modifications avec personne (pas git pushencore). Le plus simple serait de réinitialiser le maître avant la fusion avec la branche contenant les gros fichiers. Cela éliminera tous les commits de votre branche et tous les commits effectués sur master après la fusion. Vous risquez donc de perdre les modifications - en plus des gros fichiers - que vous auriez peut-être réellement souhaitées:

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 avait d'autres modifications de la branche ou des modifications sur le maître après la fusion que vous souhaitez conserver, il serait préférable de rebaser le maître et d'inclure sélectivement les validations 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 qui correspondent aux validations qui ont ajouté les gros fichiers, mais laissez tout le reste tel quel. Sauvegarder et quitter. Votre branche principale ne doit contenir que ce que vous voulez et pas de gros fichiers. Notez que git rebasesans -psupprimer les validations de fusion, vous vous retrouverez donc avec un historique linéaire pour le maître après <commit hash>. Cela vous convient probablement, mais sinon, vous pouvez essayer avec -p, mais git help rebasedit 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.

seul
la source
Il existe une variante du scénario A ici avec, cependant, un problème supplémentaire inattendu.
Scénario Un problème de mine résolu, pour supprimer une grande quantité de fichier de pack temporaire. Le référentiel a été géré par un serveur de build et cela provoque la création de fichiers indésirables dans le dossier .git / objects / pack. Je pourrais libérer de précieux Go de mon disque.
xrissz
7

Comme loganfsmyth l'a déjà indiqué dans sa réponse , vous devez purger l'historique de git car les fichiers continuent à y exister même après les avoir supprimés du dépôt. Les documents officiels GitHub recommandent BFG que je trouve plus facile à utiliser que filter-branch:

Supprimer des fichiers de l'historique

Téléchargez BFG depuis leur site Web. Assurez-vous que java est installé, puis créez un clonage miroir et purgez l'historique. Assurez-vous de remplacer YOUR_FILE_NAMEpar 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

Idem 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 sophistiquées (voir la documentation ) comme celles-ci:

Supprimez tous les fichiers de plus de 100 Mo de l'historique:

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

Important!

Lors de l' exécution BFG, faites attention que les deux YOUR_FILE_NAMEet YOUR_FOLDER_NAMEsont en effet que des noms de fichier / dossier. Ce ne sont pas des chemins , donc quelque chose comme ça foo/bar.jpgne fonctionnera pas! Au lieu de cela, tous les fichiers / dossiers portant le nom spécifié seront supprimés de l'historique du dépôt, quel que soit le chemin ou la branche où ils existaient.

Timo
la source
Je me demande si je veux appliquer cet bfgoutil à un référentiel git local, à quoi devrait ressembler la commande?
Angel Todorov
5

Une option:

exécutez git gcmanuellement pour condenser un certain nombre de fichiers de pack en un ou quelques fichiers de pack. Cette opération est persistante (c'est-à-dire que le gros fichier pack conservera son comportement de compression), il peut donc être avantageux de compresser un référentiel périodiquement avecgit gc --aggressive

Une autre option consiste à enregistrer le code et le .git quelque part, puis à supprimer le .git et à recommencer à utiliser ce code existant, en créant un nouveau référentiel git ( git init).

Michael Durrant
la source
Salut Michael, j'ai essayé de courir git gcet je me suis contenté de quelques fichiers de pack, mais le plus gros en fait toujours partie et j'aimerais simplement m'en débarrasser pour pouvoir sauvegarder le dossier en externe plus facilement (zip avant était 1 -2 Mo, maintenant 55 Mo). À moins que quelqu'un ne puisse suggérer autre chose, je pense que je devrai peut-être créer un nouveau git. Je suppose que cela signifie que je perdrai l'accès aux succursales que j'ai actuellement, etc.?
user1116573
2
J'ai renoncé à essayer et j'ai simplement supprimé le dossier .git et créé un nouveau référentiel git comme vous l'avez dit. Je vais considérer cela comme une leçon apprise. Merci Michael.
user1116573
4
Cela n'a pas beaucoup de sens. Pourquoi ne pouvez-vous pas simplement dire à git de consolider le référentiel actuel et de supprimer les fichiers du pack dans le processus?
jml
4

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

  1. Forcer Git à traiter, mais pas à extraire, l'historique complet de chaque branche et balise
  2. Supprimez le fichier spécifié, ainsi que tous les commits vides générés en conséquence
  3. Remplacez vos 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 dépôt.

Étape suivante, effectuer un cycle GC pour forcer toutes les références au fichier à expirer et à purger du fichier du 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
Benjamin Wasula
la source
Enfin, à partir de la 2ème partie, j'ai obtenu un repo 28G à 158M. Presque rien d'autre sur Google n'a fonctionné. Je vous remercie.
Sridhar Sarnobat le
J'ai suivi les étapes ci-dessus et j'ai poussé comme "git push origin --force --all" et mes branches distantes (master, develop et feature / ASD-1010) n'ont toujours pas été nettoyées. Lorsque j'ai été cloné à partir du dépôt distant, les fichiers .pack étaient toujours présents. Comment puis-je refléter ce nettoyage sur toutes les branches git distantes?
Sambit Swain
1

Je suis un peu en retard pour le spectacle, mais au cas où la réponse ci-dessus ne résoudrait pas la question, j'ai trouvé un autre moyen. Supprimez simplement le gros fichier spécifique de .pack. J'ai eu ce problème où j'ai enregistré accidentellement un gros fichier de 2 Go. J'ai suivi les étapes expliquées dans ce lien: http://www.ducea.com/2012/02/07/howto-completely-remove-a-file-from-git-history/

Rishabh Kumar
la source
Après avoir fait cette méthode, il supprimera complètement l'historique complet du projet ou supprimera simplement le fichier spécifié.
Samim Aftab Ahmed
-3

c'est plus une solution pratique qu'une solution de codage. zip le fichier. Ouvrez le zip au format d'affichage de fichier (différent de la décompression). Supprimez le fichier .pack. Décompressez et remplacez le dossier. Fonctionne comme un charme!

shreya10
la source