Impossible de pousser vers GitHub à cause d'un gros fichier que j'ai déjà supprimé

272

Actuellement j'ai

  1. Dépôt GitHub vide
  2. Dépôt de serveur SSH (principal)
  3. Dépôt local

Le repo du serveur SSH était le repo le plus récent (site de production), j'ai donc fait un clone Git de là vers le local. J'ai ensuite essayé de faire un git pushGitHub.

Tout s'est bien passé, mais cela a dit que le nom de fichier.gz était trop grand pour GitHub. Je n'avais pas besoin de ce fichier, j'ai donc exécuté plusieurs commandes Git pour m'en débarrasser du cache Git, puis repoussé vers le serveur SSH.

Je ne vois pas le gros fichier localement mais il est toujours sur le serveur SSH même si git diffne renvoie rien et git push renvoie "Tout est à jour" - Et même si le fichier n'est pas visible dans le référentiel local lorsque j'essaie de pousser vers GitHub je reçois toujours une erreur à ce sujet

à distance: erreur: le fichier fpss.tar.gz fait 135,17 Mo; cela dépasse la limite de taille de fichier de GitHub de 100 Mo

J'ai suivi les étapes sous "résoudre le problème" répertoriées dans l'aide de GitHub, cela n'aurait-il pas dû être suffisant?

Comment le fichier est-il toujours dans l'éther quand il n'est pas local ou répertorié dans git status / diff / push?

Kevin W.
la source
2
Le fichier est toujours là dans l'histoire. Vous devez détruire l'historique, éventuellement en écrasant les commits qui ont ajouté et supprimé le fichier.
Shahbaz
@Shahbaz J'ai suivi les étapes sous "résoudre le problème" répertoriées sur ce site ... cela n'aurait-il pas dû être suffisant? help.github.com/articles/working-with-large-files
Kevin W.
La commande y est plus avancée que ma connaissance de git, donc je ne peux pas vraiment le dire. Quoi qu'il en soit, si git log -- the_big_filevous retourne quelque chose, le fichier est toujours dans l'historique.
Shahbaz
@Shahbaz qui ne renvoie rien> <
Kevin W.
Se pourrait-il que vous poussiez également d'autres branches là où le fichier existe? De plus, si le fichier est toujours sur le serveur, pourquoi dirait-il git pushque tout est à jour? Depuis que vous avez changé d'histoire, il aurait dû se plaindre que la poussée n'est pas possible et que vous auriez à la forcer.
Shahbaz

Réponses:

448

Vous pouvez utiliser

git filter-branch --index-filter 'git rm -r --cached --ignore-unmatch <file/dir>' HEAD

Cela supprimera tout dans l'historique de ce fichier. Le problème est que le fichier est présent dans l'historique.

Cette commande modifie les hachages de vos validations, ce qui peut être un vrai problème, en particulier sur les référentiels partagés. Il ne doit pas être effectué sans comprendre les conséquences.

MacGyver
la source
24
A fonctionné pour moi mais j'ai dû le 'forcer': git filter-branch --index-filter 'git rm -r --cached --ignore-unmatch <file / dir>' -f HEAD
alexoviedo999
31
Cette commande modifie les hachages de vos validations, ce qui peut être un vrai problème, en particulier sur les référentiels partagés. Il ne doit pas être effectué sans comprendre les conséquences.
Chris
6
Êtes-vous censé remplacer <fichier / répertoire> par le nom du fichier ou du répertoire à l'origine du problème?
David Rhoden
12
Notez que si vous souhaitez appliquer ces modifications à TOUTES les branches, vous devez utiliser un --allindicateur au lieu deHEAD
Nick Spreitzer
9
J'obtiens:Rewrite 657560fa18c030bcfac9132ce1c3541e84a5bc2c (1/10) (0 seconds passed, remaining 0 predicted) /usr/lib/git-core/git-filter-branch: 1: eval: Syntax error: end of file unexpected
João Abrantes
69

J'ai trouvé que le squash était plus utile que filter-branch. J'ai fait ce qui suit:

  1. Supprimez localement les fichiers volumineux.
  2. Validez les suppressions locales.
  3. Retour soft reset X nombre de commits (pour moi , il était 3): git reset --soft HEAD~3.
  4. Réengagez ensuite tous les changements ensemble (AKA squash) git commit -m "New message for the combined commit"
  5. Appuyez sur commit écrasé.

Cas spécial (de l'utilisateur @lituo): Si ci-dessus ne fonctionne pas, vous pouvez avoir ce cas. La validation 1 incluait le fichier volumineux et la transmission de la validation 1 a échoué en raison d'une erreur de fichier volumineux. Commit 2 a supprimé le fichier volumineux,git rm --cached [file_name]mais la transmission de Commit 2 a toujours échoué. Vous pouvez suivre les mêmes étapes ci-dessus mais au lieu d'utiliserHEAD~3, utilisezHEAD~2.

Mais je ne suis pas une classe Wrapper
la source
2
J'ai travaillé pour moi, je devais juste re-fusionner les modifications des trois validations dans mon référentiel local avant que la poussée de squash ne fonctionne.
dasWesen
5
C'est BEAUCOUP mieux que la meilleure réponse. La meilleure réponse gâche tout votre historique de commit.
manic.coder
N'a pas résolu mon problème
Hirak Sarkar
3
C'est de loin la seule réponse qui corrige les gros fichiers non validés ou validés, sans nuquer complètement le référentiel! Surévalué pour qu'il puisse passer au sommet :-)
Ælex
1
@mais je ne suis pas une classe wrapper: merci beaucoup! cela a fonctionné comme un charme :)
POOJA GUPTA
64

Voici quelque chose que j'ai trouvé très utile si vous avez déjà joué avec votre repo avant de demander de l'aide. Premier type:

git status

Après cela, vous devriez voir quelque chose dans le sens de

On branch master
Your branch is ahead of 'origin/master' by 2 commits.
  (use "git push" to publish your local commits)

nothing to commit, working tree clean

La partie importante est le "2 commits"! De là, allez-y et tapez:

git reset HEAD~<HOWEVER MANY COMMITS YOU WERE BEHIND>

Ainsi, pour l'exemple ci-dessus, on taperait:

git reset HEAD~2

Après avoir tapé cela, votre "statut git" devrait dire:

On branch master
Your branch is up to date with 'origin/master'.

nothing to commit, working tree clean

À partir de là, vous pouvez supprimer le gros fichier (en supposant que vous ne l'avez pas déjà fait) et vous devriez pouvoir tout recommencer sans perdre votre travail.
Je sais que ce n'est pas une réponse super sophistiquée, mais j'espère que cela aide!

Shreya
la source
11
Gagnant. Solution simple, propre, efficace et construite par git. L'amour répond comme ça.
Reece Daniels
3
c'est la meilleure solution qui soit.
wrahool
40

Si le fichier a été ajouté avec votre commit le plus récent et que vous n'avez pas poussé vers le référentiel distant , vous pouvez supprimer le fichier et modifier le commit, à partir d' ici :

git rm --cached giant_file
    # Stage "giant_file" for removal with "git rm"
    # Leave it on disk with "--cached". if you want to remove it from disk
    # then ignore the "--cached" parameter
git commit --amend -CHEAD
    # Commit the current tree without the giant file using "git commit"
    # Amend the previous commit with your change "--amend" 
    # (simply making a new commit won't work, as you need
    # to remove the file from the unpushed history as well)
    # Use the log/authorship/timestamp of the last commit (the one we are
    # amending) with "-CHEAD", equivalent to --reuse-message=HEAD
git push
    # Push our rewritten, smaller commit with "git push"
BlueMoon93
la source
1
Cette solution ne fonctionnera pas car le fichier n'est plus dans l'index git (il en résulte comme untrackedliste de fichiers à git status.
loretoparisi
Rien ne se passe. Après avoir appliqué cela, il a réduit le nombre total de fichiers, mais après avoir montré le processus à 99%, il est resté bloqué. Une suggestion sur ce qui me manque?
CoDe
4
que signifie -CHEAD?
Aerin
1
Que faire si je veux essayer ceci à partir d'un commit spécifique - pas le tout dernier commit? J'ai essayé git rm --cached giant_file commit_idmais ça n'a pas marché :(
puifais
@puifais Je reviendrais au commit précédent, je ferais ces étapes, puis je fusionnerais avec l'actuel. Je ne sais pas si c'est la meilleure approche, je ne suis pas un expert Git
BlueMoon93
13

J'ai eu un problème similaire et j'ai utilisé l' étape ci-dessus pour supprimer le fichier. Cela a parfaitement fonctionné.

J'ai ensuite reçu une erreur sur un deuxième fichier que je devais supprimer: remote: error: File <path/filename> is 109.99 MB; this exceeds GitHub's file size limit of 100.00 MB

J'ai essayé la même étape, j'ai eu une erreur: "A previous backup already exists in <path/filename>"

De la recherche sur ce site, j'ai utilisé la commande:git filter-branch --force --index-filter "git rm --cached --ignore-unmatch <path/filename>" --prune-empty --tag-name-filter cat -- --all

Fonctionne très bien et les gros fichiers ont été supprimés.

Incroyablement, le push a toujours échoué avec une autre erreur: error: RPC failed; curl 56 OpenSSL SSL_read: SSL_ERROR_SYSCALL, errno 104 fatal: The remote end hung up unexpectedly

J'ai résolu ce problème en modifiant directement le fichier de configuration .git - postBuffer = 999999999

Après cela, la poussée est passée!

Andre Odendaal
la source
1
un problème supplémentaire que j'ai dû composer avec la suppression d'un gros fichier (comme ci-dessus) était que l'un des dossiers avait un caractère de hachage #. Cela n'a causé aucun problème pour le fonctionnement normal de Git, cependant, pour que git rmj'avais besoin de donner le nom complet du chemin du référentiel pour le fichier et d'échapper au # avec une barre oblique inverse pour le faire fonctionner
Jacanterbury
cela a fonctionné pour moi aussi. J'ai évité l' reset hardétape au bas de la page avec une simple poussée. czettner.com/2015/07/16/…
Monte Hayward
Cela a fonctionné après avoir également exécuté 'git push -f origin'
kezzos
12

Pourquoi GitHub rejette mon dépôt, même après avoir supprimé le gros fichier?

Git stocke l'historique complet de votre projet, donc même si vous `` supprimez '' un fichier de votre projet, le référentiel Git a toujours une copie du fichier dans son historique, et si vous essayez de pousser vers un autre référentiel (comme celui hébergé sur GitHub), puis Git requiert que le référentiel distant ait le même historique que votre référentiel local (c'est-à-dire les mêmes gros fichiers dans son historique).

Comment puis-je faire en sorte que GitHub accepte mon dépôt?

Vous devez nettoyer l'historique Git de votre projet localement, en supprimant les gros fichiers indésirables de tout l'historique, puis utiliser uniquement l'historique `` nettoyé '' à l'avenir. Les identifiants de validation Git des validations affectées changeront.

Comment nettoyer les gros fichiers de mon référentiel Git?

Le meilleur outil pour nettoyer les gros fichiers indésirables de l'historique Git est le BFG Repo-Cleaner - c'est 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 beaucoup plus facile à utiliser.

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

Roberto Tyley
la source
1
Mon cas a eu des complications supplémentaires qui ont empêché l'écrasement. L'outil BFG a très bien fonctionné. Merci.
dantopa
Ceci est une solution phénoménale
SexualPotatoes
5

J'ai essayé toutes les méthodes ci-dessus, mais aucune ne fonctionne pour moi.

Ensuite, j'ai trouvé ma propre solution.

  1. Tout d'abord, vous avez besoin d'un dépôt local propre et à jour. Supprimez tous les putains de gros fichiers.

  2. Créez maintenant un nouveau dossier À L'EXTÉRIEUR de votre dossier repo et utilisez "Git create repository here" pour en faire un nouveau dépôt Git, appelons-le new_local_repo. Ça y est ...! Toutes les méthodes ci-dessus ont dit que vous devez nettoyer l'historique ... eh bien, j'en ai marre de ça, créons un nouveau dépôt qui n'a aucun historique!

  3. Copiez les fichiers de votre ancien référentiel local foutu vers le nouveau et magnifique référentiel. Notez que le logo vert sur l'icône du dossier disparaîtra, c'est prometteur car c'est un nouveau repo!

  4. Validez sur la branche locale, puis appuyez sur pour créer une nouvelle branche distante. Appelons cela new_remote_branch. Si vous ne savez pas comment pousser à partir d'un nouveau dépôt local, recherchez-le sur Google.

  5. Félicitations! Vous avez transmis votre code propre et à jour à GitHub. Si vous n'avez plus besoin de la branche principale distante, vous pouvez faire de votre new_remote_branch une nouvelle branche principale. Si vous ne savez pas comment le faire, recherchez-le sur Google.

  6. Dernière étape, il est temps de supprimer l'ancien référentiel local foutu. À l'avenir, vous n'utiliserez que new_local_repo.

Shuaibin Chang
la source
4

J'ai le même problème et aucune des réponses ne fonctionne pour moi. J'ai résolu par les étapes suivantes:

1. Trouvez quel (s) commit (s) contient le gros fichier

git log --all -- 'large_file`

La dernière validation est la plus ancienne validation de la liste des résultats.

2. Trouvez celui juste avant le plus ancien.

git log

Supposons que vous ayez:

commit 3f7dd04a6e6dbdf1fff92df1f6344a06119d5d32

3. Git rebase

git rebase -i 3f7dd04a6e6dbdf1fff92df1f6344a06119d5d32

Astuces :

  1. Élément de liste
  2. Je choisis juste droppour les commits contient le gros fichier.
  3. Vous pouvez rencontrer des conflits lors du rebasage, les corriger et utiliser git rebase --continue continuer jusqu'à ce que vous ayez terminé.
  4. Si quelque chose s'est mal passé lors du rebase, utilisez-le git rebase --abortpour l'annuler.
William Hu
la source
1

La solution pour conserver les gros fichiers / dossiers dans le dossier de travail

C'est la ligne qui a travaillé pour résoudre le problème posé ici (à partir de la réponse 1):

git filter-branch --index-filter 'git rm -r --cached --ignore-unmatch <file/dir>' HEAD

Cette commande supprime également le fichier / dir si le fichier / dir se trouve dans l'arborescence de travail.

Si vous souhaitez conserver le fichier / dossier dans l'arborescence de travail, je propose de suivre les étapes suivantes.

  1. Après cette erreur, exécutez git reset HEAD^
  2. Ajoutez le fichier / dossier en question dans le fichier `` .gitignore ''.

  3. Procédez comme d'habitude git add .qui pourrait capturer d'autres fichiers / dossiers mais doit capturer le .gitignorefichier. Vient ensuite git commit -m"message"et enfingit push origin <branch_name>

Kiprono Elijah Koech
la source
0

cela a fonctionné pour moi. documentation de github Squashing Git Commits git reset origin / master

git checkout master && git pull;
git merge feature_branch;
git add . --all;
git commit -m "your commit message"

trouver la documentation ici

Njoroge Mathu
la source
0

J'ai donc rencontré une situation particulière: j'ai cloné un référentiel de gitlab, qui contenait un fichier de plus de 100 Mo, mais a été supprimé à un moment donné de l'historique de git. Plus tard, lorsque j'ai ajouté un nouveau dépôt privé github et que j'ai essayé de pousser vers le nouveau dépôt, j'ai eu la fameuse erreur «fichier trop volumineux». À ce stade, je n'avais plus accès au dépôt gitlab d'origine. Cependant, je pouvais toujours pousser vers le nouveau bfg-repo-cleanerdépôt github privé en utilisant un référentiel LOCAL sur ma machine:

$ cd ~
$ curl https://repo1.maven.org/maven2/com/madgag/bfg/1.13.0/bfg-1.13.0.jar > bfg.jar
$ cd my-project
$ git gc
$ cd ../
$ java -jar bfg.jar --strip-blobs-bigger-than 100M my-project
$ cd my-project
$ git reflog expire --expire=now --all && git gc --prune=now --aggressive
$ git remote -v # confirm origin is the remote you want to push to
$ git push origin master
Donato
la source
0

Parfois, le fichier est conservé dans l'historique de suivi, essayez les étapes suivantes:

  1. git commit, Si vous voyez le mode de création avec le gros fichier répertorié, procédez comme suit:
  2. git filter-branch --index-filter 'git rm -r --cached --ignore-unmatch filename' HEAD. Vous devriez voir un tas de réécritures affichées dans votre console qui se termine par:

    rm 'filename' et

    la dernière ligne Ref a été réécrite.

C'est fait.

Tree DR
la source
-1

J'ajoute à la première réponse.

git filter-branch --index-filter 'git rm -r --cached --ignore-unmatch' HEAD

Il y aura un conflit de fusion d'origine / maître.

Votre branche et «origine / maître» ont divergé et ont respectivement 114 et 109 commits différents. (utilisez "git pull" pour fusionner la branche distante dans la vôtre)

Veuillez exécuter ceci

git reset --hard origin / master

Il supprimera toutes mes modifications échelonnées et non échelonnées, oubliera tout sur ma branche locale actuelle et le rendra exactement identique à origin / master.

RAHUL KUMAR
la source