Comment faire pour supprimer les blobs non référencés de mon git repo

j'ai un GitHub repo qui avait deux branches - master & release.

la branche de publication contenait des fichiers de distribution binaires qui contribuaient à une très grande taille de repo (> 250 Mo), donc j'ai décidé de nettoyer les choses.

J'ai d'abord supprimé la branche de publication à distance, via git push origin :release

puis j'ai supprimé la branche de publication locale. D'abord j'ai essayé git branch -d release , mais git a dit "erreur: la branche 'release' est pas un ancêtre de votre TÊTE." ce qui est vrai, alors j'ai fait git branch -D release pour le forcer à être supprimé.

mais la taille de mon dépôt, localement et sur GitHub, était encore énorme. Alors j'ai parcouru la liste habituelle des commandes git, comme git gc --prune=today --aggressive , sans succès.

en suivant les instructions de Charles Bailey à SO 1029969 j'ai pu obtenir une liste de SHA1 pour les plus grands blobs. J'ai ensuite utilisé le script de DONC 460331 pour trouver les gouttes...et les cinq plus grands n'existent pas, bien que des petites taches soient trouvées, donc je sais que le script fonctionne.

je pense que ces blogs sont les binaires de la branche release, et ils ont d'une manière ou d'une autre été laissés après la suppression de cette branche. Quelle est la bonne façon de se débarrasser d'eux?

91
git
demandé sur Community 2009-12-15 05:28:06

10 réponses

... et sans plus attendre, puis-je vous présenter ce script utile, git-gc-all , garanti pour supprimer all vos déchets git jusqu'à ce qu'ils pourraient venir des variables de configuration supplémentaires:

git -c gc.reflogExpire=0 -c gc.reflogExpireUnreachable=0 -c gc.rerereresolved=0 \
    -c gc.rerereunresolved=0 -c gc.pruneExpire=now gc "$@"

vous pourriez aussi avoir besoin d'exécuter quelque chose comme ceux-ci d'abord, Oh mon Dieu, git est compliqué!!

git remote rm origin
rm -rf .git/refs/original/ .git/refs/remotes/ .git/*_HEAD .git/logs/
git for-each-ref --format="%(refname)" refs/original/ | xargs -n1 --no-run-if-empty git update-ref -d

j'ai mis tout cela dans un script, ici:

http://sam.nipl.net/b/git-gc-all-ferocious

edit: vous pourriez aussi avoir besoin de supprimer quelques tags, merci Zitrax:

git tag | xargs git tag -d
150
répondu Sam Watkins 2018-03-26 05:10:46

comme décrit ici , il suffit d'utiliser

git reflog expire --expire-unreachable=now --all
git gc --prune=now

git reflog expire --expire-unreachable=now --all supprime toutes les références de commits inaccessibles dans reflog .

git gc --prune=now supprime les commits eux-mêmes.

Attention : seule l'utilisation de git gc --prune=now ne fonctionnera pas car ces propagations sont encore référencées dans le refrog. Par conséquent, il est obligatoire d'effacer le nouveau carnet.

47
répondu Eliko 2017-05-23 11:54:50

, Comme mentionné dans cette SORTE de réponse , git gc peut en fait augmenter la taille de l'opération!

Voir aussi ce fil 1519170920"

maintenant git a un mécanisme de sécurité pour pas supprimer les objets non référencés tout de suite lors de l'exécution " git gc ".

Par défaut, les objets non référencés sont conservés pour une période de 2 semaines. Ceci est pour vous faciliter la tâche de récupérer les branches supprimées accidentellement ou les propagations, ou pour éviter une course où un objet créé juste avant dans le processus d'être mais pas encore référencé pourrait être supprimé par un processus ' git gc ' fonctionnant en parallèle.

ainsi, pour donner ce délai de grâce aux objets emballés mais non référencés, le processus de reconditionnement pousse ces objets non référencés hors du pack dans leur forme lâche afin qu'ils puissent être vieillis et finalement élagués.

Les objets qui ne sont pas référencés sont généralement peu nombreux. Avoir 404855 objets non référencés c'est beaucoup, et être envoyé ces objets en premier lieu via un clone est stupide et un gaspillage complet de bande passante réseau.

en tout cas... Pour résoudre votre problème, vous avez simplement besoin d'exécuter ' git gc "avec l'argument --prune=now pour désactiver ce délai de grâce et se débarrasser de ces objets non référencés tout de suite (sûr seulement si aucun autre git les activités se déroulent en même temps, ce qui devrait être facile à assurer sur un poste de travail).

et BTW, en utilisant git gc --aggressive "avec une version git ultérieure (ou git repack -a -f -d --window=250 --depth=250 ')

le même fil mentionne :

 git config pack.deltaCacheSize 1

qui limite la taille du cache delta à un octet (le désactivant effectivement) au lieu de la valeur par défaut de 0 qui signifie illimité. Avec qui Je suis capable de reconditionner ce dépôt en utilisant la commande git repack ci-dessus sur un système x86-64 avec 4 Go de RAM et en utilisant 4 threads (c'est un Noyau quad). L'utilisation de la mémoire résidente augmente cependant à près de 3,3 GO.

si votre machine est SMP et que vous n'avez pas assez de RAM, vous pouvez réduire le nombre de threads à un seul:

git config pack.threads 1

en outre, vous pouvez limiter l'utilisation de la mémoire avec le --window-memory argument à git repack ".

Par exemple, l'utilisation de --window-memory=128M devrait maintenir une limite supérieure raisonnable sur le delta l'utilisation de la mémoire de recherche bien que cela puisse avoir pour résultat une correspondance delta moins optimale si la contient beaucoup de fichiers volumineux.


sur le devant de la branche filtrante, vous pouvez considérer (avec prudence) ce script

#!/bin/bash
set -o errexit

# Author: David Underhill
# Script to permanently delete files/folders from your git repository.  To use 
# it, cd to your repository's root and then run the script with a list of paths
# you want to delete, e.g., git-delete-history path1 path2

if [ $# -eq 0 ]; then
    exit 0
fi

# make sure we're at the root of git repo
if [ ! -d .git ]; then
    echo "Error: must run this script from the root of a git repository"
    exit 1
fi

# remove all paths passed as arguments from the history of the repo
files=$@
git filter-branch --index-filter "git rm -rf --cached --ignore-unmatch $files" HEAD

# remove the temporary history git-filter-branch otherwise leaves behind for a long time
rm -rf .git/refs/original/ && git reflog expire --all &&  git gc --aggressive --prune
29
répondu VonC 2017-05-23 10:31:30

git gc --prune=now , ou le faible niveau git prune --expire now .

18
répondu Jakub Narębski 2009-12-16 20:14:06

chaque fois que votre tête bouge, git trace ceci dans le reflog . Si vous avez supprimé les "commits", vous avez toujours" dangling commits "parce qu'ils sont toujours référencés par le reflog pendant ~30 jours. C'est le filet de sécurité lorsque vous supprimez s'engage par accident.

vous pouvez utiliser la commande git reflog supprimer les propagations spécifiques, repack, etc.., ou juste la commande de haut niveau:

git gc --prune=now
12
répondu vdboor 2009-12-18 12:36:06

vous pouvez utiliser git forget-blob .

l'usage est assez simple git forget-blob file-to-forget . Vous pouvez obtenir plus d'information ici

https://ownyourbits.com/2017/01/18/completely-remove-a-file-from-a-git-repository-with-git-forget-blob/

il disparaîtra de tous les commits dans votre histoire, reconfigurer, tags et ainsi de suite

je rencontre le même problème de temps en temps, et à chaque fois je dois revenez à ce poste et d'autres, c'est pourquoi j'ai automatisé le processus.

crédits à des contributeurs tels que Sam Watkins

4
répondu nachoparker 2017-01-23 07:21:52

essayer d'utiliser git-filter - branch - ce n'est pas supprimer de gros blobs, mais peut supprimer de gros fichiers que vous spécifiez à partir de la pension entière. Pour moi, il réduit la taille de la pension de centaines de Mo à 12 Mo.

2
répondu W55tKQbuRu28Q4xv 2009-12-15 04:23:55

avant de faire git filter-branch et git gc , vous devriez examiner les étiquettes qui sont présentes dans votre repo. Tout système réel qui dispose de tagging automatique pour des choses comme l'intégration continue et les déploiements fera des objets indésirables encore référencés par ces tags, donc gc ne peut pas les enlever et vous continuerez toujours à vous demander pourquoi la taille de repo est encore si grande.

la meilleure façon de se débarrasser de tous les trucs non désirés est de lancer git-filter & git gc et puis pousser maître à une nouvelle mise à nu. Le nouveau repo nu aura l'arbre nettoyé.

1
répondu v_abhi_v 2015-10-01 09:02:23

parfois, la raison pour laquelle "gc" ne fait pas beaucoup de bien est qu'il y a un rebase inachevé ou un stash basé sur un vieux commit.

0
répondu StellarVortex 2011-12-02 12:17:15

pour ajouter une autre astuce, n'oubliez pas d'utiliser git remote prune pour supprimer les branches obsolètes de vos télécommandes avant d'utiliser git gc

vous pouvez les voir avec branche git-a

c'est souvent utile quand on va chercher dans des dépôts GitHub ou fourchés...

0
répondu Tanguy 2013-02-12 11:58:38