Git: Comment supprimer un fichier du commit historique?

113

J'ai commit avec l'ID 56f06019 (par exemple). Dans ce commit, j'ai accidentellement commis un gros fichier (50 Mo). Dans un autre commit, j'ajoute le même fichier mais dans la bonne taille (petit). Maintenant, mon dépôt lorsque je cloné est trop lourd: (Comment supprimer ce gros fichier de l'historique du dépôt pour réduire la taille de mon dépôt?

Marioosh
la source
dans mon cas, ce n'est pas un gros fichier, mais un fichier de configuration contenant des crédits de base de données. J'étudiais git, à ce moment-là je n'étais pas au courant de .gitignore.
Rashi
1
connexes help.github.com/articles/...
Trevor Boyd Smith

Réponses:

165

Le chapitre 9 du livre Pro Git contient une section sur la suppression d'objets .

Permettez-moi de décrire brièvement les étapes ici:

git filter-branch --index-filter \
    'git rm --cached --ignore-unmatch path/to/mylarge_50mb_file' \
    --tag-name-filter cat -- --all

Comme l'option de rebasage décrite précédemment, filter-branchest l'opération de réécriture. Si vous avez publié l'historique, vous devrez --forcepousser les nouvelles références.

L' filter-branchapproche est considérablement plus puissante que l' rebaseapproche, car elle

  • vous permet de travailler sur toutes les branches / refs à la fois,
  • renomme toutes les balises à la volée
  • fonctionne correctement même s'il y a eu plusieurs validations de fusion depuis l'ajout du fichier
  • fonctionne proprement même si le fichier a été (ré) ajouté / supprimé plusieurs fois dans l'historique de la (des) branche (s)
  • ne crée pas de nouveaux commits non liés, mais les copie en modifiant les arbres qui leur sont associés. Cela signifie que les éléments tels que les validations signées, les notes de validation, etc. sont préservés

filter-branch conserve également les sauvegardes, de sorte que la taille du dépôt ne diminuera pas immédiatement à moins que vous n'expiriez les reflogs et le ramasse-miettes:

rm -Rf .git/refs/original       # careful
git gc --aggressive --prune=now # danger
sehe
la source
1
Il convient de noter que cela ne semble pas fonctionner sous Windows cmd.exe. Cela semble fonctionner sous cygwin bien, cependant.
Faux nom
2
J'ai fait fonctionner la branche de filtre git ci-dessus en utilisant des guillemets doubles au lieu de guillemets simples (sur Windows Server 2012 cmd.exe)
JCii
1
Ce qui a fonctionné pour moi, c'est cette ligne de commande de branche de filtre. git filter-branch --force --index-filter 'git rm --ignore-unmatch --cached PathTo/MyFile/ToRemove.dll' -- fbf28b005^.. Ensuite rm --recursive --force .git/refs/original, rm --recursive --force .git/logs j'ai utilisé le git prune --expire now et git gc --aggressive cela a mieux fonctionné pour moi que vos étapes exactes énumérées ci-dessus. Merci d'avoir inclus le lien vers le livre Git Pro car il était inestimable.
dacke.geo
Après la commande filter-branch, la seule façon de réduire la taille du dossier .git était de suivre la commande trouvée ici: stackoverflow.com/questions/1904860/... git -c gc.reflogExpire = 0 -c gc. reflogExpireUnreachable = 0 -c gc.rerereresolved = 0 \ -c gc.rerereunresolved = 0 -c gc.pruneExpire = now gc "$ @"
Steve Ardis
Pour réduire le dépôt, j'ai utilisé les commandes répertoriées dans git filter-branch doc: git-scm.com/docs
Ludovic Ronsin
0

Vous aurez besoin de git rebase en mode interactif voir un exemple ici: Comment puis-je supprimer un commit sur GitHub? et comment supprimer les anciens commits .

Si votre commit est à HEAD moins 10 commits:

$ git rebase -i HEAD~10

Après l'édition de votre historique, vous devez pousser le "nouvel" historique, vous devez ajouter le +to force (voir la refspec dans les options push ):

$ git push origin +master

Si d'autres personnes ont déjà cloné votre référentiel, vous devrez les informer, car vous venez de modifier l'historique.

Loïc d'Anterroches
la source
3
Cela ne supprime pas le gros fichier de l'historique. En outre, la manière canonique pour pousser la force est git push --forceou git push -f(qui ne nécessite pas que les gens de connaître la cible de poussée de la branche)
sehe
Sur la base de la question, le nouveau fichier est exactement le même que l'ancien fichier, c'est-à-dire le même chemin. C'est pourquoi vous ne pouvez pas utiliser directement git rmsur le chemin.
Loïc d'Anterroches
2
@sehe, si vous faites un rebase en éliminant le commit avec l'énorme fichier, il est parti pour de bon.
vonbrand
@vonbrand uniquement à partir de cette branche que vous avez rebasée. Je ne suppose pas que la branche «de» soit supprimée. Mais oui, si vous supprimez une branche d'arbre de révision, qui va aider à : _
sehe
@sehe, bien sûr, vous devez chasser toutes les branches contenant le commit incriminé. Si c'est avant un peu de buisson dans le repo, vous aurez beaucoup de réorganisation à faire. Mais rebase est l'outil pour cela.
vonbrand
0

J'ai essayé d'utiliser la réponse suivante sur Windows https://stackoverflow.com/a/8741530/8461756

Les guillemets simples ne fonctionnent pas sous Windows, vous avez besoin de guillemets doubles.

La suite a fonctionné pour moi.

git filter-branch --force --index-filter "git rm --cached --ignore-unmatch PathRelativeRepositoryRoot / bigfile.csv" - --all

Après avoir supprimé le gros fichier, j'ai pu transmettre mes modifications à github master.

Sandeep Dixit
la source
0

Vous pouvez utiliser une simple commande pour supprimer

 git rm -r -f app/unused.txt 
 git rm -r -f yourfilepath
mini développeur
la source