Comment supprimer / supprimer un fichier volumineux de l'historique des validations dans le référentiel Git?

708

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?

culebrón
la source
9
Cet article devrait vous aider help.github.com/removing-sensitive-data
MBO
1
Notez que si votre gros fichier se trouve dans un sous-répertoire, vous devrez spécifier le chemin relatif complet.
Johan
1
Aussi lié help.github.com/en/articles/…
frederj
Beaucoup de réponses ci-dessous vantent BFG comme plus facile que git filter-branch, mais j'ai trouvé le contraire vrai.
2540625

Réponses:

605

Utilisez le BFG Repo-Cleaner , une alternative plus simple et plus rapide à git-filter-branchspé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:

$ java -jar bfg.jar --strip-blobs-bigger-than 100M my-repo.git

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 gcpour nettoyer les données mortes:

$ git gc --prune=now --aggressive

Le BFG est généralement au moins 10 à 50 fois plus rapide que son fonctionnement git-filter-branchet généralement plus facile à utiliser.

Divulgation complète: je suis l'auteur du BFG Repo-Cleaner.

Roberto Tyley
la source
4
@tony Cela vaut la peine de répéter l'intégralité de la procédure de clonage et d'effacement pour voir si le message vous demandant d'extraire se reproduit, mais c'est certainement parce que votre serveur distant est configuré pour rejeter les mises à jour non rapides (c'est-à-dire qu'il est configuré pour vous arrêter) de perdre l'histoire - c'est exactement ce que vous voulez faire). Vous devez faire modifier ce paramètre sur la télécommande, ou à défaut, pousser l'historique de mise à jour du référentiel vers un tout nouveau référentiel vierge.
Roberto Tyley
1
@RobertoTyley Merci. Je l'ai essayé 3 fois et tous ont abouti au même message. Je pense donc également que vous avez raison sur le serveur distant configuré pour rejeter les mises à jour non rapides. J'envisagerai simplement de pousser le dépôt mis à jour vers un tout nouveau dépôt. Je vous remercie!
Tony
7
@RobertoTyley Parfait, vous économisez mon temps, merci beaucoup. Au fait, vous devriez peut-être le faire git push --forceaprès vos étapes, sinon le repo à distance n'a toujours pas changé.
li2
3
+1 à l'ajout 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).
MatrixManAtYrService
25
Je pense que le jargon Trump des sorties de l'outil est un peu trop.
Chris
564

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 rebasedocumentation pour les étapes nécessaires après la réparation de votre historique.

Vous avez au moins deux options: git filter-branchet 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:

$ git lola --name-status
* f772d66 (HEAD, master) Login page
| A     login.html
* cb14efd Remove DVD-rip
| D     oops.iso
* ce36c98 Careless
| A     oops.iso
| A     other.html
* 5af4522 Admin page
| A     admin.html
* e738b63 Index
  A     index.html

Notez qu'il git lolas'agit d'un alias non standard mais très utile. Avec le --name-statuscommutateur, 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.isoest 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:

git filter-branch --prune-empty -d /dev/shm/scratch \
  --index-filter "git rm --cached -f --ignore-unmatch oops.iso" \
  --tag-name-filter cat -- --all

Options:

  • --prune-emptysupprime 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.
  • -dnomme 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/shmentraînera une exécution plus rapide .
  • --index-filterest l'événement principal et s'exécute par rapport à l'index à chaque étape de l'historique. Vous souhaitez supprimer oops.isooù qu'il se trouve, mais il n'est pas présent dans toutes les validations. La commande git rm --cached -f --ignore-unmatch oops.isosupprime le DVD-rip lorsqu'il est présent et n'échoue pas autrement.
  • --tag-name-filterdécrit comment réécrire les noms de balises. Un filtre de catest 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 options git filter-branch
  • --allce 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:

$ git lola --name-status
* 8e0a11c (HEAD, master) Login page
| A     login.html
* e45ac59 Careless
| A     other.html
|
| * f772d66 (refs/original/refs/heads/master) Login page
| | A   login.html
| * cb14efd Remove DVD-rip
| | D   oops.iso
| * ce36c98 Careless
|/  A   oops.iso
|   A   other.html
|
* 5af4522 Admin page
| A     admin.html
* e738b63 Index
  A     index.html

Notez que le nouveau commit «Careless» ajoute seulement other.htmlet que le commit «Remove DVD-rip» n'est plus sur la branche master. La branche étiquetée refs/original/refs/heads/mastercontient 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».

$ git update-ref -d refs/original/refs/heads/master
$ git reflog expire --expire=now --all
$ git gc --prune=now

Pour une alternative plus simple, clonez le référentiel pour éliminer les bits indésirables.

$ cd ~/src
$ mv repo repo.old
$ git clone file:///home/user/src/repo.old repo

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:

$ git lola --name-status
* 8e0a11c (HEAD, master) Login page
| A     login.html
* e45ac59 Careless
| A     other.html
* 5af4522 Admin page
| A     admin.html
* e738b63 Index
  A     index.html

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.isoet "Login page" a eu un nouveau parent, donc leurs SHA1 ont changé.

Rebase interactive

Avec une histoire de:

$ git lola --name-status
* f772d66 (HEAD, master) Login page
| A     login.html
* cb14efd Remove DVD-rip
| D     oops.iso
* ce36c98 Careless
| A     oops.iso
| A     other.html
* 5af4522 Admin page
| A     admin.html
* e738b63 Index
  A     index.html

vous voulez supprimer oops.isode "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 5af4522démarre un éditeur avec le contenu suivant.

pick ce36c98 Careless
pick cb14efd Remove DVD-rip
pick f772d66 Login page

# Rebase 5af4522..f772d66 onto 5af4522
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#  x, exec = run command (the rest of the line) using shell
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#

En exécutant notre plan, nous le modifions pour

edit ce36c98 Careless
pick f772d66 Login page

# Rebase 5af4522..f772d66 onto 5af4522
# ...

Autrement dit, nous supprimons la ligne avec «Supprimer DVD-rip» et modifions l'opération sur «Careless» editplutôt que pick.

Enregistrer-quitter l'éditeur nous dépose à une invite de commande avec le message suivant.

Stopped at ce36c98... Careless
You can amend the commit now, with

        git commit --amend

Once you are satisfied with your changes, run

        git rebase --continue

Comme le message nous l'indique, nous sommes sur le commit «Careless» que nous voulons éditer, nous exécutons donc deux commandes.

$ git rm --cached oops.iso
$ git commit --amend -C HEAD
$ git rebase --continue

Le premier supprime le fichier incriminé de l'index. Le second modifie ou modifie «Careless» pour être l'index mis à jour et -C HEADdemande à git de réutiliser l'ancien message de validation. Enfin, git rebase --continuecontinue avec le reste de l'opération de rebase.

Cela donne un historique de:

$ git lola --name-status
* 93174be (HEAD, master) Login page
| A     login.html
* a570198 Careless
| A     other.html
* 5af4522 Admin page
| A     admin.html
* e738b63 Index
  A     index.html

c'est ce que tu veux.

Greg Bacon
la source
4
Pourquoi je ne peux pas pousser lors de l'utilisation de git filter-branch, n'a pas réussi à pousser certaines références vers '[email protected]: product / myproject.git' Pour vous empêcher de perdre l'historique, les mises à jour non rapides ont été rejetées Fusionner la télécommande change avant de pousser à nouveau.
Agung Prasetyo
11
Ajoutez l' option -f(ou --force) à votre git pushcommande: «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. "
Greg Bacon
5
Il s'agit d'une réponse merveilleusement approfondie expliquant l'utilisation de git-filter-branch pour supprimer les gros fichiers indésirables de l'historique, mais il convient de noter que depuis que Greg a écrit sa réponse, le BFG Repo-Cleaner a été publié, ce qui est souvent plus rapide et plus facile à utiliser - voir ma réponse pour plus de détails.
Roberto Tyley
1
Après avoir effectué l'une des procédures ci-dessus, le référentiel distant (sur GitHub) ne supprime PAS le gros fichier. Seul le local le fait. Je force la poussée et le nada. Qu'est-ce que je rate?
azatar
1
cela fonctionne également sur les dirs. ... "git rm --cached -rf --ignore-unmatch path/to/dir"...
rynop
198

Pourquoi ne pas utiliser cette commande simple mais puissante?

git filter-branch --tree-filter 'rm -f DVD-rip' HEAD

L' --tree-filteroption 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 .

Gary Gauh
la source
3
C'est une bonne solution! J'ai créé un gist qui a un script python pour lister les fichiers et le cmd git qui supprimera le fichier que vous voulez nettoyer gist.github.com/ariv3ra/16fd94e46345e62cfcbf
punkdata
5
Beaucoup mieux que bfg. Je n'ai pas pu nettoyer le fichier d'un git avec bfg, mais cette commande a aidé
podarok
4
C'est bien. Juste une note pour les autres que vous devrez faire cela par branche si le gros fichier est dans plusieurs branches.
James
2
Sur Windows, j'ai obtenu 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
marcotama
2
Si vous savez commitoù vous placez le fichier (par exemple 35dsa2), vous pouvez le remplacer HEADpar 35dsa2..HEAD. tree-filterest beaucoup plus lent que index-filtercela, il n'essaiera pas de vérifier tous les commits et de les réécrire. si vous utilisez HEAD, il essaiera de le faire.
alpha_989
86

(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

git rev-list --objects --all \
| git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' \
| awk '/^blob/ {print substr($0,6)}' \
| sort --numeric-sort --key=2 \
| cut --complement --characters=13-40 \
| numfmt --field=2 --to=iec-i --suffix=B --padding=7 --round=nearest

Lorsque vous exécutez le code ci-dessus, vous obtiendrez une belle sortie lisible par l'homme comme ceci:

...
0d99bb931299  530KiB path/to/some-image.jpg
2ba44098e28f   12MiB path/to/hires-image.png
bd1741ddce0d   63MiB path/to/some-video-1080p.mp4

🚀 Suppression rapide de fichiers 🚀

Supposons que vous souhaitiez ensuite supprimer les fichiers aet à bpartir de chaque commit accessible HEAD, vous pouvez utiliser cette commande:

git filter-branch --index-filter 'git rm --cached --ignore-unmatch a b' HEAD
Sridhar Sarnobat
la source
3
Si votre dépôt a des balises, vous souhaiterez probablement également ajouter le drapeau --tag-name-filter catpour git filter-branch --index-filter 'git rm --cached --ignore-unmatch a b' --tag-name-filter cat HEAD
réétiqueter les nouveaux validations
3
Les instructions Mac et quelques autres informations apparaissent dans le message lié d'origine
nruth
3
git filter-branch --index-filter 'git rm --cached --ignore-unmatch <filename>' HEADbon de travail droit de la batte
eleijonmarck
ma réponse préférée. un léger ajustement à utiliser sur mac os (en utilisant les commandes gnu)git 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
Florian Oswald
script sympa avec la rev-list mais ça n'a pas fonctionné pour moi en tant qu'alias, une idée de comment faire?
Robin Manoli
47

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:

git filter-branch -f --index-filter "git rm -rf --cached --ignore-unmatch FOLDERNAME" -- --all

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:

rm -rf .git/refs/original/
git reflog expire --expire=now --all
git gc --prune=now
git gc --aggressive --prune=now

Poussez maintenant toutes les modifications vers le référentiel distant:

git push --all --force

Cela nettoiera le référentiel distant.

Justin
la source
A fonctionné à merveille pour moi.
Ramon Vasconcelos
3
Cela a également fonctionné pour moi. Supprime un dossier spécifique (dans mon cas, celui qui contenait des fichiers trop volumineux ou un dépôt Github) sur le référentiel, mais le conserve sur le système de fichiers local s'il existe.
skizzo
A travaillé pour moi! aucune histoire n'est laissée qui peut prêter à confusion (si quelqu'un où cloner en ce moment), assurez-vous que vous avez un plan pour mettre à jour les liens, les dépendances, etc.
rompus
38

Ces commandes ont fonctionné dans mon cas:

git filter-branch --force --index-filter 'git rm --cached -r --ignore-unmatch oops.iso' --prune-empty --tag-name-filter cat -- --all
rm -rf .git/refs/original/
git reflog expire --expire=now --all
git gc --prune=now
git gc --aggressive --prune=now

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):

# WARNING!!!
# this will rewrite completely your bitbucket refs
# will delete all branches that you didn't have in your local

git push --all --prune --force

# Once you pushed, all your teammates need to clone repository again
# git pull will not work
Kostanos
la source
4
En quoi est-ce différent de ce qui précède, pourquoi est-ce mieux?
Andy Hayden
1
Pour une raison quelconque, la version mkljun n'est pas réduite en espace git dans mon cas, j'avais déjà supprimé les fichiers de l'index en utilisant 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.
Kostanos
1
Cela a vraiment aidé, mais je devais utiliser l' -foption non seulement -rfici git rm --cached -rf --ignore-unmatch oops.isoau lieu de git rm --cached -r --ignore-unmatch oops.isoselon @ lfender6445 ci
drstevok
10

Notez 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.

$ git filter-branch --index-filter "git rm -rf --cached --ignore-unmatch YOURFILENAME" HEAD
$ rm -rf .git/refs/original/ 
$ git reflog expire --all 
$ git gc --aggressive --prune
$ git push origin master --force
mkljun
la source
11
N'exécutez PAS ces commandes à moins que vous ne vouliez vous créer une douleur immense. Il a supprimé beaucoup de mes fichiers de code source d'origine. J'ai supposé qu'il purgerait certains fichiers volumineux de mon historique de validation dans GIT (conformément à la question d'origine), cependant, je pense que cette commande est conçue pour purger définitivement les fichiers de votre arborescence de code source d'origine (grande différence!). Mon système: Windows, VS2012, Git Source Control Provider.
Contango
2
J'ai utilisé cette commande: git filter-branch --force --index-filter 'git rm --cached -r --ignore-unmatch oops.iso' --prune-empty --tag-name-filter cat -- --allau lieu du premier de votre code
Kostanos
8

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

Soheil
la source
7

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-DIRECTORYavec 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/

lfender6445
la source
1
Cette réponse m'a aidé, sauf que le script de la réponse a un léger problème et qu'il ne me recherche pas dans toutes les branches. Mais la commande dans le lien l'a parfaitement fait.
Ali B
5

Cela le supprimera de votre historique

git filter-branch --force --index-filter 'git rm -r --cached --ignore-unmatch bigfile.txt' --prune-empty --tag-name-filter cat -- --all
scintillait
la source
Cela a fonctionné pour moi merci !!
Sonja Brits
Cela fonctionne dans mon cas. Je lance cela sur votre branche principale.
S. Domeng
4

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)

$ git filter-branch --index-filter "git rm -rf --cached --ignore-unmatch YOURFILENAME" HEAD
$ rm -rf .git/refs/original/ 
$ git reflog expire --all 
$ git gc --aggressive --prune
$ git push origin master --force

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 treeobjets pointant vers ce fichier. Ma solution ultime pour vraiment le tuer était de:

# First, apply what's in the answer linked in the front
# and before doing the gc --prune --aggressive, do:

# Go back at the origin of the repository
git checkout -b newinit <sha1 of first commit>
# Create a parallel initial commit
git commit --amend
# go back on the master branch that has big file
# still referenced in history, even though 
# we thought we removed them.
git checkout master
# rebase on the newinit created earlier. By reapply patches,
# it will really forget about the references to hidden big files.
git rebase newinit

# Do the previous part (checkout + rebase) for each branch
# still connected to the original initial commit, 
# so we remove all the references.

# Remove the .git/logs folder, also containing references
# to commits that could make git gc not remove them.
rm -rf .git/logs/

# Then you can do a garbage collection,
# and the hidden files really will get gc'ed
git gc --prune --aggressive

Mon dépôt (le .git) est passé de 32 Mo à 388 Ko, que même la branche de filtre ne pouvait pas nettoyer.

Dolanor
la source
4

git filter-branchest 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.

# Do it in a new testing branch
$ git checkout -b test

# Remove file-name from every commit on the new branch
# --index-filter, rewrite index without checking out
# --cached, remove it from index but not include working tree
# --ignore-unmatch, ignore if files to be removed are absent in a commit
# HEAD, execute the specified command for each commit reached from HEAD by parent link
$ git filter-branch --index-filter 'git rm --cached --ignore-unmatch file-name' HEAD

# The output is OK, reset it to the prior branch master
$ git checkout master
$ git reset --soft test

# Remove test branch
$ git branch -d test

# Push it with force
$ git push --force origin master
zhangyu12
la source
2

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) .

Nir
la source
Cette méthode est trop lente pour les grands référentiels. Il a fallu plus d'une heure pour répertorier les fichiers volumineux. Ensuite, lorsque je vais supprimer des fichiers, après une heure, ce n'est que le tiers du chemin à travers le traitement du premier fichier que je veux supprimer.
kristianp
Oui, c'est lent, mais ça marche ... Savez-vous quelque chose de plus rapide?
Nir
1
Je ne l'ai pas utilisé, mais BFG Repo-Cleaner, selon une autre réponse sur cette page.
kristianp
2

Vous pouvez le faire en utilisant la branch filtercommande:

git filter-branch --tree-filter 'rm -rf path/to/your/file' HEAD

John Foley
la source
2

Il y a de très bonnes réponses dans ce fil, mais en attendant, beaucoup d'entre elles sont obsolètes. En utilisantgit-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-repoest 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

git filter-repo --analyze

Cela vous aide à déterminer quoi faire ensuite.

Vous pouvez supprimer votre fichier DVD-rip partout:

 git filter-repo --invert-paths --path-match DVD-rip

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!

Donat
la source
1

Lorsque vous rencontrez ce problème, git rmcela 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-blobun 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 gcsupprimez-le

L'utilisation est assez simple git forget-blob file-to-forget . Vous pouvez obtenir plus d'informations ici

https://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!

nachoparker
la source
vous devriez obtenir ceci en homebrew
Cameron E
0

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-branchtout en fournissant les fonctionnalités uniques suivantes:

  • Réécriture rapide des commits et des arbres (par ordre de x10 à x100).
  • Prise en charge intégrée de la liste blanche avec --keep (conserve les fichiers ou des répertoires) et de la liste noire avec les options --remove.
  • Utilisation du modèle de type .gitignore pour le filtrage des arbres
  • Script C # rapide et facile pour le filtrage de validation et le filtrage d'arbre
  • Prise en charge des scripts dans le filtrage d'arborescence par modèle de fichier / répertoire
  • Élaguer automatiquement la validation vide / inchangée, y compris les validations de fusion
Philippe
la source