Supprimer le fichier du dépôt git (historique)

(résolu, voir bas du corps de la question)

En cherchant cela depuis longtemps maintenant, ce que j'ai jusqu'à maintenant est:

à peu près la même méthode, mais les deux laissent des objets en paquet fichier... Enliser.

Ce que j'ai essayé:

git filter-branch --index-filter 'git rm --cached --ignore-unmatch file_name'
rm -Rf .git/refs/original
rm -Rf .git/logs/
git gc

ont encore des fichiers dans le pack, et c'est comme ça que je le sais:

git verify-pack -v .git/objects/pack/pack-3f8c0...bb.idx | sort -k 3 -n | tail -3

et ceci:

git filter-branch --index-filter "git rm -rf --cached --ignore-unmatch file_name" HEAD
rm -rf .git/refs/original/ && git reflog expire --all &&  git gc --aggressive --prune

pareil...

essayé git clone astuce, il a enlevé certains des fichiers (~3000 d'entre eux), mais les plus gros fichiers sont toujours là...

j'ai quelques gros fichiers hérités dans le dépôt, ~200M, et je ne veux vraiment pas là... Et je ne veux pas réinitialiser le dépôt à 0 : (

SOLUTION: C'est le chemin le plus court pour se débarrasser des fichiers:

  1. vérifier .git / packed-refs - mon problème était que j'avais là une ligne refs/remotes/origin/master pour un dépôt distant, supprimez-la, sinon git ne supprimera pas ces fichiers
  2. (facultatif) git verify-pack -v .git/objects/pack/#{pack-name}.idx | sort -k 3 -n | tail -5 - pour vérifier les plus grands fichiers
  3. (optionnel) git rev-list --objects --all | grep a0d770a97ff0fac0be1d777b32cc67fe69eb9a98 - pour vérifier ce que sont ces fichiers
  4. git filter-branch --index-filter 'git rm --cached --ignore-unmatch file_names' - supprimer un fichier de toutes les révisions
  5. rm -rf .git/refs/original/ - pour supprimer la sauvegarde de git
  6. git reflog expire --all --expire='0 days' - expirer tous les objets en vrac
  7. git fsck --full --unreachable - pour vérifier s'il y a des objets en vrac
  8. git repack -A -d - reconditionnement
  9. git prune - pour finalement supprimer ces objets
72
demandé sur Boris Churzin 2010-01-29 22:27:38

8 réponses

Je ne peux pas en être sûr sans avoir accès à vos données de dépôt, mais je crois qu'il y a probablement un ou plusieurs réferences emballées faisant encore référence à de vieilles commits d'avant que vous n'ayez lancé git filter-branch . Cela expliquerait pourquoi git fsck --full --unreachable ne qualifie pas le gros blob d'objet inaccessible, même si vous avez expiré votre rechog et retiré les références originales (déballées).

voici ce que je ferais (après git filter-branch et git gc ont été faits):

1) Assurez-vous que les références originales ont disparu:

rm -rf .git/refs/original

2) expirent toutes les entrées de reflog:

git reflog expire --all --expire='0 days'

3) Vérifier s'il s'agit d'un vieux colis réf.

cela pourrait être délicat, en fonction du nombre de références emballées que vous avez. Je ne connais aucune commande Git qui automatise ça., donc je pense que vous devrez le faire manuellement. Faites une copie de sauvegarde de .git/packed-refs . Maintenant, éditez .git/packed-refs . Vérifier s'il s'agit d'anciens réf (en particulier, voir s'il a emballé l'un des réf de .git/refs/original ). Si vous en trouvez d'anciennes qui n'ont pas besoin d'être là, supprimez-les (supprimez la ligne correspondant à cette référence).

après avoir nettoyé le fichier packed-refs , voir si git fsck remarque les objets inaccessibles:

git fsck --full --unreachable

si cela a fonctionné, et git fsck déclare maintenant votre grande tache comme inaccessible, vous pouvez passer à l'étape suivante.

4) Remballer votre archive compressé(s)

git repack -A -d

cela permettra de s'assurer que les objets inaccessibles sont déballés et stay unpacked.

5) Tailler en vrac (inaccessible) des objets

git prune

et ça devrait le faire. Git devrait vraiment avoir une meilleure façon de gérer les références emballées. Peut-être il ya une meilleure façon que je ne connais pas. En l'absence d'une meilleure solution, l'édition manuelle du fichier packed-refs pourrait être la seule solution.

61
répondu Dan Moulding 2010-02-01 21:39:55

je recommande d'utiliser le BFG Repo-Cleaner , une alternative plus simple et plus rapide à git-filter-branch spécifiquement conçu pour réécrire des fichiers à partir de l'histoire Git. Une façon dont il rend votre vie plus facile ici, c'est qu'il gère réellement tous références par défaut (toutes les étiquettes, les branches, les choses comme réfs/remotes/origin/master, etc) mais il est aussi 10-50x plus rapide.

Vous devez suivre attentivement ces étapes ici: http://rtyley.github.com/bfg-repo-cleaner/#usage - mais le bit de base est juste ceci: téléchargez le jar de BFG (nécessite Java 6 ou au-dessus) et exécutez cette commande:

$ java -jar bfg.jar  --delete-files file_name  my-repo.git

tout fichier nommé file_name (qui n'est pas dans votre dernier commit) sera totalement supprimé de l'historique de votre dépôt. Vous pouvez ensuite utiliser git gc pour nettoyer les morts de données:

$ git gc --prune=now --aggressive

le BFG est généralement beaucoup plus simple à utiliser que git-filter-branch - les options sont adaptées autour de ces deux cas d'utilisation commune:

  • Retrait Fou De Gros Fichiers
  • suppression mots de passe, justificatifs d'identité & autres données privées

divulgation Complète: je suis l'auteur de la BFG Repo-Cleaner.

9
répondu Roberto Tyley 2013-04-16 20:06:49

j'ai trouvé cela très utile en ce qui concerne la suppression d'un dossier entier car ce qui précède ne m'a pas vraiment aidé: https://help.github.com/articles/remove-sensitive-data .

j'ai utilisé:

git filter-branch -f --force \
--index-filter 'git rm -rf --cached --ignore-unmatch folder/sub-folder' \
--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
6
répondu Mike Averto 2014-04-04 00:06:34

j'essayais de me débarrasser d'un gros dossier dans l'histoire, et les réponses ci-dessus ont fonctionné, jusqu'à un certain point. Le fait est qu'ils ne fonctionnent pas si vous avez des étiquettes. Si le commit contenant le gros fichier est accessible à partir d'une balise, alors vous devrez ajuster la commande filter-branches thusly:

git filter-branch --tag-name-filter cat \
--index-filter 'git rm --cached --ignore-unmatch huge_file_name' -- \
--all --tags
4
répondu BHMulder 2014-04-04 00:08:52

voir: Comment puis-je supprimer les fichiers sensibles de l'histoire de git

ce qui précède échouera si le fichier n'existe pas dans un Rév. dans ce cas, le commutateur '--ignore-unmatch' le réparera:

git filter-branch -f --index-filter 'git rm --cached --ignore-unmatch <filename>' HEAD

puis, pour obtenir tous les objets en vrac hors de la reprise de possession:

git gc --prune='0 days ago'
2
répondu Wayne Conrad 2017-05-23 12:10:50

vous avez diverses raisons pour une taille encore grande git repo après git gc , car il ne supprime pas tous les objets en vrac .

je détail les raisons dans " réduire le dépôt git de taille "

mais une astuce à tester dans votre cas serait de clone votre" nettoyé "Git repo et voir si le clone a la taille appropriée.

("nettoyé" repo "étant celui où vous avez appliqué le filter-branch , puis gc et prune )

1
répondu VonC 2017-05-23 12:26:29

ceci devrait être couvert par la commande git obliterate dans les Extras Git ( https://github.com/visionmedia/git-extras ).

git obliterate <filename>
0
répondu Spain Train 2013-03-25 20:25:49

j'ai eu le même problème et j'ai trouvé un grand tutoriel sur github qui expliquent étape par étape comment se débarrasser des fichiers que vous avez accidentellement commis.

Voici un petit résumé de la procédure Cupcake suggéré.

si vous avez un fichier nommé file_to_remove à supprimer de l'historique:

cd path_to_parent_dir

git filter-branch --force --index-filter \
  'git rm --cached --ignore-unmatch file_to_remove' \
  --prune-empty --tag-name-filter cat -- --all
0
répondu Cyril Leroux 2014-04-04 09:57:07