Comment supprimer des objets inutilisés d'un référentiel git?

89

J'ai accidentellement ajouté, validé et poussé un énorme fichier binaire avec mon tout dernier commit dans un référentiel Git.

Comment puis-je faire en sorte que Git supprime le ou les objets qui ont été / ont été créés pour ce commit afin que mon .gitrépertoire redevienne à une taille raisonnable?

Edit : Merci pour vos réponses; J'ai essayé plusieurs solutions. Aucun n'a fonctionné. Par exemple, celui de GitHub a supprimé les fichiers de l'historique, mais la .gittaille du répertoire n'a pas diminué:

$ BADFILES=$(find test_data -type f -exec echo -n "'{}' " \;)

$ git filter-branch --index-filter "git rm -rf --cached --ignore-unmatch $BADFILES" HEAD
Rewrite 14ed3f41474f0a2f624a440e5a106c2768edb67b (66/66)
rm 'test_data/images/001.jpg'
[...snip...]
rm 'test_data/images/281.jpg'
Ref 'refs/heads/master' was rewritten

$ git log -p # looks nice

$ rm -rf .git/refs/original/
$ git reflog expire --all
$ git gc --aggressive --prune
Counting objects: 625, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (598/598), done.
Writing objects: 100% (625/625), done.
Total 625 (delta 351), reused 0 (delta 0)

$ du -hs .git
174M    .git
$ # still 175 MB :-(
Jonas H.
la source
13
Juste un rappel pour les modérateurs, cette question appartient à 100% au SO, pas au superutilisateur.
VonC du
Comme mentionné ici ( stackoverflow.com/questions/685319/… ), avez-vous essayé un reconditionnement après votre gc? git-repack -asuivi par git-prune-packedexemple. Voir blog.felipebalbi.com/2007/12/19
VonC
2
@Jonas: et si, après avoir fait tout cela, vous cloniez votre repo? Souhaitez-vous alors obtenir un clone avec la taille réduite souhaitée?
VonC du
1
@Jonas: après tout ce que vous avez fait ( filter-branch, gc, repack, ...), non, vous ne devriez pas voir une mauvaise commettre du tout. C'est un signe que le nettoyage n'a pas eu lieu comme prévu.
VonC du

Réponses:

127

J'ai répondu à cela ailleurs, et je vais copier ici puisque j'en suis fier!

... et sans plus tarder, puis-je vous présenter ce script utile, git-gc-all, garanti pour supprimer tous vos déchets git jusqu'à ce qu'ils puissent proposer 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 "$@"

L'option --aggressive peut être utile.

REMARQUE: cela supprimera TOUS les trucs non référencés, alors ne venez pas me pleurer si vous décidez plus tard que vous vouliez en garder certains!

Vous devrez peut-être également exécuter quelque chose comme ça en premier, oh mon Dieu, c'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 ça dans un script, ici:

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

Sam Watkins
la source
Comme dans stackoverflow.com/questions/1904860/… , +1 à vous encore.
VonC le
18
excellent: D mon plan diabolique pour obtenir plus de points en clonant les réponses a fonctionné !! 1;)
Sam Watkins
Oui! Cela a fonctionné, mais j'ai dû exécuter le script complet. Exécuter uniquement la commande gc (avec les options de configuration) ne suffisait pas.
Daniel
4
102m à 160k .. efficace et destructeur
Prusswan
4
Merci beaucoup pour le script! Bonus info: la xargscommande produit une erreur sur OS X en raison d'une option non reconnue. Solution la plus simple: installez GNU xargs via homebrew brew install findutilset remplacez-le xargspar gxargs.
qqilihq
26

Votre git reflog expire --allest incorrect. Il supprime les entrées de reflog qui sont plus anciennes que la date d'expiration, qui est par défaut de 90 jours. Utilisez git reflog expire --all --expire=now.

Ma réponse à une question similaire traite du problème du nettoyage des objets inutilisés d'un référentiel.

Josh Lee
la source
18

1) Supprimez le fichier du référentiel git (et non du système de fichiers):

  • git rm --cached path/to/file

2) Réduisez le repo en utilisant:

  • git gc,

  • ou git gc --aggressive

  • ou git prune

ou une combinaison des éléments ci-dessus comme suggéré dans cette question: Réduisez la taille du référentiel git

Jamie
la source
10

Ce guide sur la suppression des données sensibles peut s'appliquer, en utilisant la même méthode. Vous allez réécrire l'historique pour supprimer ce fichier de chaque révision dans laquelle il était présent. Ceci est destructeur et entraînera des conflits de dépôt avec toutes les autres extractions, donc avertissez d'abord les collaborateurs.

Si vous souhaitez garder le binaire disponible dans le dépôt pour d'autres personnes, il n'y a pas vraiment de moyen de faire ce que vous voulez. C'est à peu près tout ou rien.

Daenyth
la source
8

La clé pour moi s'est avérée être en cours d'exécution git repack -A -d -fet ensuite git gcréduire la taille du seul git pack que j'avais.

Andrew Charneski
la source
6

Hy!

Git ne reçoit que les objets dont il a réellement besoin lors du clonage de référentiels (si je comprends bien)

Vous pouvez donc modifier le dernier commit en supprimant le fichier ajouté par erreur, puis pousser vos modifications dans le référentiel distant (avec l'option -f pour écraser l'ancien commit sur le serveur également)

Ensuite, lorsque vous créez un nouveau clone de ce dépôt, son répertoire .git doit être aussi petit qu'avant la validation du ou des gros fichiers.

Si vous souhaitez également supprimer les fichiers inutiles du serveur, vous pouvez supprimer le référentiel sur le serveur et envoyer votre copie nouvellement clonée (qui a l'historique complet)

u-foka
la source
4
git filter-branch --index-filter 'git rm --cached --ignore-unmatch Filename' --prune-empty -- --all

N'oubliez pas de remplacer Filenamecelui que vous souhaitez supprimer du référentiel.

Martin
la source