Parfois, je laissais tomber un DVD-rip dans un projet de site Web, puis négligemment git commit -a -m ...
, et, zap, le dépôt était gonflé de 2,2 concerts. La prochaine fois, j'ai fait quelques modifications, supprimé le fichier vidéo et tout validé, mais le fichier compressé est toujours là dans le référentiel, dans l'historique.
Je sais que je peux démarrer des branches à partir de ces validations et rebaser une branche sur une autre. Mais que dois-je faire pour fusionner les 2 validations afin que le gros fichier ne s'affiche pas dans l'historique et soit nettoyé lors de la procédure de récupération de place?
git filter-branch
, mais j'ai trouvé le contraire vrai.Réponses:
Utilisez le BFG Repo-Cleaner , une alternative plus simple et plus rapide à
git-filter-branch
spécifiquement conçue pour supprimer les fichiers indésirables de l'historique Git.Suivez attentivement les instructions d'utilisation , la partie principale est la suivante:
Tous les fichiers de plus de 100 Mo (qui ne figurent pas dans votre dernière validation) seront supprimés de l'historique de votre référentiel Git. Vous pouvez ensuite utiliser
git gc
pour nettoyer les données mortes:Le BFG est généralement au moins 10 à 50 fois plus rapide que son fonctionnement
git-filter-branch
et généralement plus facile à utiliser.Divulgation complète: je suis l'auteur du BFG Repo-Cleaner.
la source
git push --force
après vos étapes, sinon le repo à distance n'a toujours pas changé.git push --force
. A noter également: les poussées forcées peuvent ne pas être autorisées par la télécommande (gitlab.com ne le fait pas, par défaut. Il fallait "déprotéger" la branche).Ce que vous voulez faire est très perturbant si vous avez publié l'historique à d'autres développeurs. Voir «Récupération à partir d'une rebase en amont» dans la
git rebase
documentation pour les étapes nécessaires après la réparation de votre historique.Vous avez au moins deux options:
git filter-branch
et un rebase interactif, tous deux expliqués ci-dessous.En utilisant
git filter-branch
J'ai eu un problème similaire avec les données de test binaires volumineuses d'une importation Subversion et j'ai écrit sur la suppression des données d'un référentiel git .
Supposons que votre historique Git soit:
Notez qu'il
git lola
s'agit d'un alias non standard mais très utile. Avec le--name-status
commutateur, nous pouvons voir les modifications d'arborescence associées à chaque commit.Dans le commit «Careless» (dont le nom d'objet SHA1 est ce36c98), le fichier
oops.iso
est le DVD-rip ajouté par accident et supprimé lors du prochain commit, cb14efd. En utilisant la technique décrite dans le billet de blog susmentionné, la commande à exécuter est:Options:
--prune-empty
supprime les validations qui deviennent vides ( c'est-à - dire , ne modifient pas l'arborescence) à la suite de l'opération de filtrage. Dans le cas typique, cette option produit un historique plus propre.-d
nomme un répertoire temporaire qui n'existe pas encore à utiliser pour créer l'historique filtré. Si vous utilisez une distribution Linux moderne, la spécification d'une arborescence/dev/shm
entraînera une exécution plus rapide .--index-filter
est l'événement principal et s'exécute par rapport à l'index à chaque étape de l'historique. Vous souhaitez supprimeroops.iso
où qu'il se trouve, mais il n'est pas présent dans toutes les validations. La commandegit rm --cached -f --ignore-unmatch oops.iso
supprime le DVD-rip lorsqu'il est présent et n'échoue pas autrement.--tag-name-filter
décrit comment réécrire les noms de balises. Un filtre decat
est l'opération d'identité. Votre référentiel, comme l'exemple ci-dessus, peut ne pas avoir de balises, mais j'ai inclus cette option pour une généralité complète.--
spécifie la fin des optionsgit filter-branch
--all
ce qui suit--
est un raccourci pour toutes les références. Votre référentiel, comme l'exemple ci-dessus, ne peut avoir qu'une seule référence (maître), mais j'ai inclus cette option pour une généralité complète.Après quelques barattages, l'histoire est maintenant:
Notez que le nouveau commit «Careless» ajoute seulement
other.html
et que le commit «Remove DVD-rip» n'est plus sur la branche master. La branche étiquetéerefs/original/refs/heads/master
contient vos commits originaux au cas où vous auriez fait une erreur. Pour le supprimer, suivez les étapes de la «Liste de contrôle pour la réduction d'un référentiel».Pour une alternative plus simple, clonez le référentiel pour éliminer les bits indésirables.
L'utilisation d'une
file:///...
URL de clonage copie des objets plutôt que de créer uniquement des liens physiques.Maintenant, votre histoire est:
Les noms d'objet SHA1 pour les deux premières validations («Index» et «Page Admin») sont restés les mêmes car l'opération de filtrage n'a pas modifié ces validations. "Careless" a perdu
oops.iso
et "Login page" a eu un nouveau parent, donc leurs SHA1 ont changé.Rebase interactive
Avec une histoire de:
vous voulez supprimer
oops.iso
de "Careless" comme si vous ne l'aviez jamais ajouté, puis "Remove DVD-rip" est inutile pour vous. Ainsi, notre plan d'entrer dans un rebase interactif est de conserver la «page Admin», de modifier «Careless» et de supprimer «Remove DVD-rip».L'exécution
$ git rebase -i 5af4522
démarre un éditeur avec le contenu suivant.En exécutant notre plan, nous le modifions pour
Autrement dit, nous supprimons la ligne avec «Supprimer DVD-rip» et modifions l'opération sur «Careless»
edit
plutôt quepick
.Enregistrer-quitter l'éditeur nous dépose à une invite de commande avec le message suivant.
Comme le message nous l'indique, nous sommes sur le commit «Careless» que nous voulons éditer, nous exécutons donc deux commandes.
Le premier supprime le fichier incriminé de l'index. Le second modifie ou modifie «Careless» pour être l'index mis à jour et
-C HEAD
demande à git de réutiliser l'ancien message de validation. Enfin,git rebase --continue
continue avec le reste de l'opération de rebase.Cela donne un historique de:
c'est ce que tu veux.
la source
-f
(ou--force
) à votregit push
commande: «Habituellement, la commande refuse de mettre à jour une référence distante qui n'est pas un ancêtre de la référence locale utilisée pour la remplacer. Ce drapeau désactive la vérification. Cela peut entraîner la perte de validations du référentiel distant; utilisez-le avec soin. "... "git rm --cached -rf --ignore-unmatch path/to/dir"...
Pourquoi ne pas utiliser cette commande simple mais puissante?
L'
--tree-filter
option exécute la commande spécifiée après chaque extraction du projet, puis valide à nouveau les résultats. Dans ce cas, vous supprimez un fichier appelé DVD-rip de chaque instantané, qu'il existe ou non.Si vous savez quel commit a introduit l'énorme fichier (disons 35dsa2), vous pouvez remplacer HEAD par 35dsa2..HEAD pour éviter de réécrire trop d'historique, évitant ainsi des validations divergentes si vous n'avez pas encore poussé. Ce commentaire gracieuseté de @ alpha_989 semble trop important pour être omis ici.
Voir ce lien .
la source
fatal: bad revision 'rm'
, que j'ai corrigé en utilisant"
au lieu de'
. Commande générale:git filter-branch --force --index-filter "git rm --cached -r --ignore-unmatch oops.iso" --prune-empty --tag-name-filter cat -- --all
commit
où vous placez le fichier (par exemple35dsa2
), vous pouvez le remplacerHEAD
par35dsa2..HEAD
.tree-filter
est beaucoup plus lent queindex-filter
cela, il n'essaiera pas de vérifier tous les commits et de les réécrire. si vous utilisez HEAD, il essaiera de le faire.(La meilleure réponse que j'ai vue à ce problème est: https://stackoverflow.com/a/42544963/714112 , copiée ici car ce fil apparaît haut dans les classements de recherche Google mais pas l'autre)
🚀 Une doublure de coque incroyablement rapide 🚀
Ce script shell affiche tous les objets blob dans le référentiel, triés du plus petit au plus grand.
Pour mon échantillon repo, il a fonctionné environ 100 fois plus vite que les autres trouvés ici.
Sur mon fidèle système Athlon II X4, il gère le référentiel du noyau Linux avec ses 5 622 155 objets en un peu plus d'une minute .
Le script de base
Lorsque vous exécutez le code ci-dessus, vous obtiendrez une belle sortie lisible par l'homme comme ceci:
🚀 Suppression rapide de fichiers 🚀
Supposons que vous souhaitiez ensuite supprimer les fichiers
a
et àb
partir de chaque commit accessibleHEAD
, vous pouvez utiliser cette commande:la source
--tag-name-filter cat
pourgit filter-branch --index-filter 'git rm --cached --ignore-unmatch a b' --tag-name-filter cat HEAD
git filter-branch --index-filter 'git rm --cached --ignore-unmatch <filename>' HEAD
bon de travail droit de la battegit rev-list --objects --all \ | git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' \ | awk '/^blob/ {print substr($0,6)}' \ | sort --numeric-sort --key=2 \ | gnumfmt --field=2 --to=iec-i --suffix=B --padding=7 --round=nearest
Après avoir essayé pratiquement toutes les réponses dans SO, j'ai finalement trouvé ce joyau qui a rapidement supprimé et supprimé les gros fichiers de mon référentiel et m'a permis de synchroniser à nouveau: http://www.zyxware.com/articles/4027/how-to-delete -fichiers-permanents-de-vos-dépôts-git locaux et distants
CD dans votre dossier de travail local et exécutez la commande suivante:
remplacez FOLDERNAME par le fichier ou le dossier que vous souhaitez supprimer du référentiel git donné.
Une fois cela fait, exécutez les commandes suivantes pour nettoyer le référentiel local:
Poussez maintenant toutes les modifications vers le référentiel distant:
Cela nettoiera le référentiel distant.
la source
Ces commandes ont fonctionné dans mon cas:
C'est peu différent des versions ci-dessus.
Pour ceux qui ont besoin de pousser cela vers github / bitbucket (je n'ai testé cela qu'avec bitbucket):
la source
git rm --cached files
. La proposition de Greg Bacon est plus complète, et tout à fait la même chose pour cette mine, mais il a manqué l'index --force pour les cas où vous utilisez filter-branch plusieurs fois, et il a écrit tellement d'informations, que ma version est comme reprendre de celui-ci.-f
option non seulement-rf
icigit rm --cached -rf --ignore-unmatch oops.iso
au lieu degit rm --cached -r --ignore-unmatch oops.iso
selon @ lfender6445 ciNotez simplement que ces commandes peuvent être très destructrices. Si plus de gens travaillent sur le dépôt, ils devront tous tirer le nouvel arbre. Les trois commandes du milieu ne sont pas nécessaires si votre objectif n'est PAS de réduire la taille. Parce que la branche de filtre crée une sauvegarde du fichier supprimé et peut y rester longtemps.
la source
git filter-branch --force --index-filter 'git rm --cached -r --ignore-unmatch oops.iso' --prune-empty --tag-name-filter cat -- --all
au lieu du premier de votre codegit filter-branch --tree-filter 'rm -f path/to/file' HEAD
a bien fonctionné pour moi, même si je suis tombé sur le même problème que celui décrit ici , que j'ai résolu en suivant cette suggestion .Le livre pro-git contient un chapitre entier sur l' historique de réécriture - jetez un œil à la section
filter-branch
/ Supprimer un fichier de chaque validation .la source
Si vous savez que votre commit était récent au lieu de parcourir l'arborescence entière, procédez comme suit:
git filter-branch --tree-filter 'rm LARGE_FILE.zip' HEAD~10..HEAD
la source
Je suis tombé sur cela avec un compte bitbucket, où j'avais accidentellement stocké des sauvegardes ginormous * .jpa de mon site.
git filter-branch --prune-empty --index-filter 'git rm -rf --cached --ignore-unmatch MY-BIG-DIRECTORY-OR-FILE' --tag-name-filter cat -- --all
Relacez
MY-BIG-DIRECTORY
avec le dossier en question pour réécrire complètement votre historique ( y compris les balises ).source: https://web.archive.org/web/20170727144429/http://naleid.com:80/blog/2012/01/17/finding-and-purging-big-files-from-git-history/
la source
Cela le supprimera de votre historique
la source
J'ai essentiellement fait ce qui était sur cette réponse: https://stackoverflow.com/a/11032521/1286423
(pour l'histoire, je vais le copier-coller ici)
Cela n'a pas fonctionné, car j'aime beaucoup renommer et déplacer les choses. Donc, certains gros fichiers se trouvaient dans des dossiers qui ont été renommés, et je pense que le GC n'a pas pu supprimer la référence à ces fichiers en raison de la référence dans les
tree
objets pointant vers ce fichier. Ma solution ultime pour vraiment le tuer était de:Mon dépôt (le
.git
) est passé de 32 Mo à 388 Ko, que même la branche de filtre ne pouvait pas nettoyer.la source
git filter-branch
est une commande puissante que vous pouvez utiliser pour supprimer un énorme fichier de l'historique des validations. Le fichier restera pendant un certain temps et Git le supprimera dans la prochaine récupération de place. Vous trouverez ci-dessous le processus complet de suppression des fichiers de l'historique des validations . Pour des raisons de sécurité, le processus ci-dessous exécute d'abord les commandes sur une nouvelle branche. Si le résultat correspond à vos besoins, réinitialisez-le sur la branche que vous souhaitez réellement modifier.la source
Utilisez Git Extensions , c'est un outil d'interface utilisateur. Il a un plugin nommé "Find large files" qui trouve les fichiers lage dans les référentiels et permet de les supprimer de manière permanente.
N'utilisez pas 'git filter-branch' avant d'utiliser cet outil, car il ne pourra pas trouver les fichiers supprimés par 'filter-branch' (Altough 'filter-branch' ne supprime pas complètement les fichiers des fichiers du pack de référentiel) .
la source
Vous pouvez le faire en utilisant la
branch filter
commande:git filter-branch --tree-filter 'rm -rf path/to/your/file' HEAD
la source
Il y a de très bonnes réponses dans ce fil, mais en attendant, beaucoup d'entre elles sont obsolètes. En utilisant
git-filter-branch
n'est plus recommandée, car elle est difficile à utiliser et extrêmement lente sur les grands référentiels.git-filter-repo
est beaucoup plus rapide et simple à utiliser.git-filter-repo
est un script Python, disponible sur github: https://github.com/newren/git-filter-repo .Vous n'avez besoin que d'un seul fichier: le script Python3 git-filter-repo. Copiez-le dans un chemin d'accès inclus dans la variable PATH. Sous Windows, vous devrez peut-être modifier la première ligne du script (voir INSTALL.md). Vous devez installer Python3 installé sur votre système, mais ce n'est pas un gros problème.
Vous pouvez d'abord courir
Cela vous aide à déterminer quoi faire ensuite.
Vous pouvez supprimer votre fichier DVD-rip partout:
Filter-repo est vraiment rapide. Une tâche qui a pris environ 9 heures sur mon ordinateur par filtre-branche, a été réalisée en 4 minutes par filtre-repo. Vous pouvez faire bien plus de choses sympas avec le filtre-repo. Reportez-vous à la documentation pour cela.
Avertissement: faites-le sur une copie de votre référentiel. De nombreuses actions de filtrage-repo ne peuvent pas être annulées. filter-repo changera les hachages de validation de toutes les validations modifiées (bien sûr) et de tous leurs descendants jusqu'aux dernières validations!
la source
Lorsque vous rencontrez ce problème,
git rm
cela ne suffira pas, car git se souvient que le fichier a existé une fois dans notre historique, et gardera donc une référence à celui-ci.Pour aggraver les choses, le rebasage n'est pas facile non plus, car toute référence à l'objet blob empêchera git garbage collector de nettoyer l'espace. Cela inclut les références distantes et les références de reflog.
J'ai mis en place
git forget-blob
un petit script qui essaie de supprimer toutes ces références, puis utilise git filter-branch pour réécrire chaque commit de la branche.Une fois que votre blob ne sera plus référencé,
git gc
supprimez-leL'utilisation est assez simple
git forget-blob file-to-forget
. Vous pouvez obtenir plus d'informations icihttps://ownyourbits.com/2017/01/18/completely-remove-a-file-from-a-git-repository-with-git-forget-blob/
J'ai mis cela ensemble grâce aux réponses de Stack Overflow et à certaines entrées de blog. Des crédits pour eux!
la source
Outre
git filter-branch
(solution git lente mais pure) et BFG (plus facile et très performant), il existe également un autre outil pour filtrer avec de bonnes performances:https://github.com/xoofx/git-rocket-filter
De sa description:
Le but de git-rocket-filter est similaire à la commande
git-filter-branch
tout en fournissant les fonctionnalités uniques suivantes:la source