Não é possível enviar para o GitHub por causa do arquivo grande que eu já excluí

272

Atualmente eu tenho

  1. Repo vazio do GitHub
  2. Repo servidor SSH (principal)
  3. Repo local

O repositório do servidor SSH foi o repositório mais atualizado (site de produção), então fiz um clone do Git de lá para o local. Eu tentei fazer um git pushno GitHub.

Tudo correu bem, mas disse algo sobre o filename.gz ser muito grande para o GitHub. Como eu não precisava desse arquivo, executei vários comandos do Git para se livrar dele do cache do Git e depois retornei ao servidor SSH.

Não vejo o arquivo grande localmente, mas ele ainda está no servidor SSH, embora git diffnão retorne nada e git push retorne "Tudo está atualizado" - E mesmo que o arquivo não esteja visível no repositório local quando tento enviar para GitHub ainda recebo erro sobre isso

remoto: erro: o arquivo fpss.tar.gz tem 135,17 MB; isso excede o limite de tamanho de arquivo de 100 MB do GitHub

Eu segui as etapas em "corrigindo o problema" listadas na ajuda do GitHub, então isso não deveria ter sido suficiente?

Como o arquivo ainda está no éter quando não é local ou listado no status git / diff / push?

Kevin W.
fonte
2
O arquivo ainda está lá no histórico. Você precisa destruir o histórico, possivelmente esmagando os commits que adicionaram e removeram o arquivo.
Shahbaz
@ Shahbaz Segui as etapas em "corrigindo o problema" listadas neste site ... isso não deveria ter sido suficiente? help.github.com/articles/working-with-large-files
Kevin W.
O comando lá é mais avançado do que meu conhecimento de git, então não sei dizer. De qualquer forma, se git log -- the_big_filevocê estiver retornando alguma coisa, o arquivo ainda estará no histórico.
Shahbaz 24/10
@ Shahbaz que retorna nada> <
Kevin W.
Será que você também está enviando outras ramificações onde o arquivo existe? Além disso, se o arquivo ainda estiver no servidor, por que git pushdiria que está tudo atualizado? Desde que você mudou o histórico, deveria ter reclamado que o impulso não é possível e que você teria que forçá-lo.
Shahbaz

Respostas:

446

Você pode usar

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

Isso excluirá tudo do histórico desse arquivo. O problema é que o arquivo está presente no histórico.

Este comando altera os hashes de seus commits, o que pode ser um problema real, especialmente em repositórios compartilhados. Não deve ser realizado sem entender as consequências.

MacGyver
fonte
23
Trabalhou para mim, mas eu tinha que 'força' que: git filter-branch --índice-filter 'git rm -r --cached --ignore-unmatch <arquivo / dir>' -f CABEÇA
alexoviedo999
30
Este comando altera os hashes de seus commits, o que pode ser um problema real, especialmente em repositórios compartilhados. Não deve ser realizado sem entender as consequências.
24416 Chris
6
Você deveria substituir <arquivo / diretório> pelo nome do arquivo ou diretório que está causando o problema?
David Rhoden
12
Note que se você quiser aplicar essas alterações a todos os ramos, você precisa usar uma --allbandeira em vez deHEAD
Nick Spreitzer
9
Estou recebendo: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
68

Achei o esmagamento mais útil do que filter-branch. Eu fiz o seguinte:

  1. Exclua localmente arquivos grandes.
  2. Confirme as exclusões locais.
  3. Macio de reset número de volta X de commits (para mim foi 3): git reset --soft HEAD~3.
  4. Em seguida, reconfigure todas as alterações juntas (AKA squash) git commit -m "New message for the combined commit"
  5. Enviar confirmação achatada por push.

Caso especial (do usuário @lituo): se o procedimento acima não funcionar, você poderá ter esse caso. A confirmação 1 incluiu o arquivo grande e o envio da confirmação 1 falhou devido a um erro no arquivo grande. A confirmação 2 removeu o arquivo grande,git rm --cached [file_name]mas o envio da confirmação 2 ainda falhou. Você pode seguir as mesmas etapas acima, mas em vez de usarHEAD~3, useHEAD~2 .

Mas eu não sou uma classe de invólucro
fonte
2
Funcionou para mim, apenas tive que mesclar novamente as alterações dos três commits de volta ao meu repositório local antes que o push squash funcionasse.
DasWesen
5
Isso é MUITO melhor que a resposta principal. A resposta principal estraga todo o seu histórico de consolidação.
Manic.coder
Não resolver o meu problema
Hirak Sarkar
3
Essa é de longe a única resposta que corrige arquivos grandes não confirmados ou confirmados, sem destruir completamente o repositório! Voto a favor para que ele possa ir para o topo :-)
Ælex
1
@ mas eu não sou uma classe de wrapper: muito obrigado! isso funcionou como charme :)
POOJA GUPTA
63

Aqui está algo que achei super útil se você já estava mexendo com seu repo antes de pedir ajuda. Primeiro tipo:

git status

Depois disso, você deverá ver algo ao longo das linhas 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

A parte importante é o "2 confirma"! A partir daqui, vá em frente e digite:

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

Portanto, para o exemplo acima, digite-se:

git reset HEAD~2

Depois de digitar isso, seu "status git" deve dizer:

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

nothing to commit, working tree clean

A partir daí, você pode excluir o arquivo grande (supondo que ainda não o tenha feito) e deve poder confirmar novamente tudo sem perder seu trabalho.
Sei que essa não é uma resposta super sofisticada, mas espero que ajude!

Shreya
fonte
11
Vencedora. Solução simples, limpa, eficaz e construída com git. Respostas de amor como esta.
Reece Daniels
3
esta é a melhor solução que existe.
Wrahool 12/11/19
40

Se o arquivo foi adicionado ao seu commit mais recente e você não enviou o repositório remoto , é possível excluir o arquivo e alterar o commit, Retirado daqui :

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
fonte
1
Esta solução não funcionará desde que o arquivo não é mais no índice git (que resulta como untrackedlista de arquivos no git status.
loretoparisi
Nada está acontecendo. Depois de aplicar isso, reduziu o número total de arquivos, mas depois de mostrar o processo 99%, ele travou novamente. Alguma sugestão do que estou perdendo?
CoDe 8/17
4
o que significa -CHEAD?
Aerin
1
E se eu quiser tentar isso de um commit específico - não o último commit? Eu tentei, git rm --cached giant_file commit_idmas não funcionou :(
puifais
@puifais Gostaria de reverter para o commit anterior, executar essas etapas e depois mesclar com a atual. Eu não tenho certeza se esta é a melhor abordagem, eu não sou um especialista em Git
BlueMoon93
13

Eu tive um problema semelhante e usei a etapa acima para remover o arquivo. Funcionou perfeitamente.

Em seguida, recebi um erro em um segundo arquivo que precisava remover: remote: error: File <path/filename> is 109.99 MB; this exceeds GitHub's file size limit of 100.00 MB

Eu tentei o mesmo passo, recebi um erro: "A previous backup already exists in <path/filename>"

A partir de pesquisas neste site , usei o comando:git filter-branch --force --index-filter "git rm --cached --ignore-unmatch <path/filename>" --prune-empty --tag-name-filter cat -- --all

Funcionou muito bem, e os arquivos grandes foram removidos.

Inacreditavelmente, o envio ainda falhou com outro erro: error: RPC failed; curl 56 OpenSSL SSL_read: SSL_ERROR_SYSCALL, errno 104 fatal: The remote end hung up unexpectedly

Isso foi corrigido modificando diretamente o arquivo de configuração .git - postBuffer = 999999999

Depois disso, o impulso passou!

Andre Odendaal
fonte
1
uma pegadinha adicional que eu tive que lidar com a remoção de um arquivo grande (como acima) foi que uma das pastas tinha um caractere hash #. Isso causou nenhum problema em tudo para a operação normal git no entanto, para o git rmque eu precisava para dar o nome do caminho repositório completo para o arquivo e para escapar do # com uma barra invertida para obtê-lo para o trabalho
jacanterbury
Isso funcionou para mim também. Evitei o reset hardpasso na parte inferior da página com um simples empurrão. czettner.com/2015/07/16/...
Monte Hayward
Isso funcionou depois de também executar 'git empurrar origem -f'
kezzos
12

Por que o GitHub está rejeitando meu repositório, mesmo depois de excluir o arquivo grande?

O Git armazena o histórico completo do seu projeto, portanto, mesmo se você 'excluir' um arquivo do projeto, o repositório Git ainda terá uma cópia do arquivo no histórico e se tentar enviar para outro repositório (como um hospedado em GitHub) e, em seguida, o Git requer o repositório remoto tenha o mesmo histórico que o seu repositório local (ou seja, os mesmos arquivos grandes no seu histórico).

Como posso fazer com que o GitHub aceite meu repo?

Você precisa limpar o histórico Git do seu projeto localmente, removendo os arquivos grandes indesejados de todo o histórico e, em seguida, use apenas o histórico 'limpo' daqui para frente. Os IDs de confirmação Git das confirmações afetadas serão alterados.

Como limpo grandes arquivos do meu repositório Git?

A melhor ferramenta para limpar grandes arquivos indesejados do histórico do Git é o BFG Repo-Cleaner - é uma alternativa mais simples e rápida ao git-filter-branchprojetado especificamente para remover arquivos indesejados do histórico do Git.

Siga cuidadosamente as instruções de uso , a parte principal é exatamente isso:

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

Todos os arquivos com mais de 100 MB de tamanho (que não estão no seu commit mais recente ) serão removidos do histórico do seu repositório Git. Você pode usar git gcpara limpar os dados mortos:

$ git gc --prune=now --aggressive

O BFG é tipicamente pelo menos 10-50x mais rápido que a execução git-filter-branche geralmente muito mais fácil de usar.

Divulgação completa: sou o autor do BFG Repo-Cleaner.

Roberto Tyley
fonte
1
Meu caso teve complicações adicionais que impediram o esmagamento. A ferramenta BFG funcionou muito bem. Obrigado.
Dantopa
Esta é uma solução fenomenal
SexualPotatoes
5

Eu tentei todos os métodos acima, mas nenhum deles funciona para mim.

Então eu vim com minha própria solução.

  1. Primeiro de tudo, você precisa de um repositório local limpo e atualizado. Exclua todos os arquivos grandes.

  2. Agora crie uma nova pasta FORA da sua pasta de repositório e use "Git create repository here" para torná-lo um novo repositório Git, vamos chamá-lo de new_local_repo. É isso! Todos os métodos acima disseram que você precisa limpar o histórico ... bem, estou cansado disso, vamos criar um novo repositório que não tem histórico!

  3. Copie os arquivos do seu repositório local antigo e danificado para o novo e belo repositório. Observe que o logotipo verde no ícone da pasta desaparecerá, isso é promissor, porque este é um novo repositório!

  4. Confirme com a ramificação local e pressione para a nova ramificação remota. Vamos chamá-lo de new_remote_branch. Se você não souber como enviar um novo repositório local, pesquise no Google.

  5. Parabéns! Você enviou seu código limpo e atualizado para o GitHub. Se você não precisar mais da ramificação principal remota, poderá criar seu new_remote_branch como nova ramificação principal. Se você não sabe como fazê-lo, pesquise no Google.

  6. Última etapa, é hora de excluir o repo local antigo e fodido. No futuro, você usará apenas o new_local_repo.

Shuaibin Chang
fonte
4

Eu tenho o mesmo problema e nenhuma das respostas funciona para mim. Eu resolvi com as seguintes etapas:

1. Descubra quais confirmações contêm o arquivo grande

git log --all -- 'large_file`

A consolidação inferior é a consolidação mais antiga da lista de resultados.

2. Encontre o logo antes do mais antigo.

git log

Suponha que você tenha:

commit 3f7dd04a6e6dbdf1fff92df1f6344a06119d5d32

3. Git rebase

git rebase -i 3f7dd04a6e6dbdf1fff92df1f6344a06119d5d32

Dicas :

  1. Item da lista
  2. Acabei de escolher droppara as confirmações contém o arquivo grande.
  3. Você pode encontrar conflitos durante o rebase, corrigi-los e usá-los git rebase --continuepara continuar até terminar.
  4. Se algo der errado durante o rebase, use-o git rebase --abortpara cancelá-lo.
William Hu
fonte
1

A solução para manter os arquivos / pastas grandes dentro da pasta de trabalho

Esta é a linha que funcionou para resolver o problema solicitado aqui (da resposta 1):

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

Este comando também exclui o arquivo / dir se o arquivo / dir estiver dentro da árvore de trabalho.

Se você deseja manter o arquivo / pasta dentro da árvore de trabalho, proponho as seguintes etapas.

  1. Após esse erro, execute git reset HEAD^
  2. Adicione o arquivo / pasta em questão ao arquivo `` .gitignore```.

  3. Prossiga como de costume, o git add .que pode capturar outros arquivos / pastas, mas deve capturar o .gitignorearquivo. Em seguida é git commit -m"message"e finalmentegit push origin <branch_name>

Kiprono Elijah Koech
fonte
0

isso funcionou para mim. documentação do github Squashing Git Confirma a origem / mestre da redefinição do git

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

encontre a documentação aqui

Njoroge Mathu
fonte
0

Então, encontrei uma situação específica: clonei um repositório do gitlab, que continha um arquivo maior que 100 mb, mas foi removido em algum momento do histórico do git. Mais tarde, quando adicionei um novo repositório particular do github e tentei passar para o novo repositório, recebi o infame erro 'arquivo muito grande'. A essa altura, eu não tinha mais acesso ao repositório original do gitlab. No entanto, eu ainda era capaz de enviar para o novo bfg-repo-cleanerrepositório privado do github usando um repositório LOCAL na minha máquina:

$ 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
fonte
0

Às vezes, o arquivo é mantido no histórico de rastreamento, tente as seguintes etapas:

  1. git commit, Se você estiver vendo o modo de criação com o arquivo grande listado, faça:
  2. git filter-branch --index-filter 'git rm -r --cached --ignore-unmatch filename' HEAD. Você deve ver várias regravações mostradas no console, que terminam com:

    rm 'filename' e

    a última linha Ref foi reescrita.

Está feito.

Tree DR
fonte
-1

Estou adicionando à primeira resposta.

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

Haverá algum conflito de mesclagem da origem / mestre.

Sua ramificação e 'origem / mestre' divergiram e têm 114 e 109 confirmações diferentes cada, respectivamente. (use "git pull" para mesclar a ramificação remota na sua)

Por favor, execute isso

git reset --hard origem / master

Ele descartará todas as minhas mudanças organizadas e não organizadas, esquecerá tudo no meu ramo local atual e fará com que seja exatamente o mesmo que origem / mestre.

RAHUL KUMAR
fonte