Como remover objetos não usados ​​de um repositório git?

90

Eu acidentalmente adicionei, enviei e enviei um enorme arquivo binário com meu último commit para um repositório Git.

Como posso fazer o Git remover o (s) objeto (s) que foi / foram criados para esse commit para que meu .git diretório diminua para um tamanho normal novamente?

Edit : Obrigado por suas respostas; Tentei várias soluções. Nenhum funcionou. Por exemplo, o do GitHub removeu os arquivos do histórico, mas o .gittamanho do diretório não diminuiu:

$ BADFILES=$(find test_data -type f -exec echo -n "'{}' " \;)

$ git filter-branch --index-filter "git rm -rf --cached --ignore-unmatch $BADFILES" HEAD
Rewrite 14ed3f41474f0a2f624a440e5a106c2768edb67b (66/66)
rm 'test_data/images/001.jpg'
[...snip...]
rm 'test_data/images/281.jpg'
Ref 'refs/heads/master' was rewritten

$ git log -p # looks nice

$ rm -rf .git/refs/original/
$ git reflog expire --all
$ git gc --aggressive --prune
Counting objects: 625, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (598/598), done.
Writing objects: 100% (625/625), done.
Total 625 (delta 351), reused 0 (delta 0)

$ du -hs .git
174M    .git
$ # still 175 MB :-(
Jonas H.
fonte
13
Apenas um lembrete para os moderadores, esta questão 100% pertence ao SO, não ao superusuário.
VonC
Conforme mencionado aqui ( stackoverflow.com/questions/685319/… ), você tentou um reembalagem após seu gc? git-repack -aseguido por, git-prune-packedpor exemplo. Veja blog.felipebalbi.com/2007/12/19/…
VonC
2
@Jonas: e se, depois de fazer tudo isso, você clonar seu repo? Você , em seguida, obter um clone com o tamanho reduzido desejado?
VonC
1
@ Jonas: depois de tudo que você fez ( filter-branch, gc, repack, ...), não, você não deve ver qualquer mau cometer em tudo. Isso é um sinal de que a limpeza não ocorreu conforme o esperado.
VonC

Respostas:

129

Eu respondi isso em outro lugar, e vou copiar aqui, pois tenho orgulho disso!

... e sem mais delongas, posso apresentar a você este script útil, git-gc-all, garantido para remover todo o seu lixo git até que eles possam vir com variáveis ​​de configuração extras:

git -c gc.reflogExpire=0 -c gc.reflogExpireUnreachable=0 \
  -c gc.rerereresolved=0 -c gc.rerereunresolved=0 \
  -c gc.pruneExpire=now gc "$@"

A opção --aggressive pode ser útil.

NOTA: isso removerá TODAS as coisinhas não referenciadas, então não venha chorar para mim se você decidir mais tarde que deseja manter algumas delas!

Você também pode precisar executar algo assim primeiro, oh querido, git é complicado !!

git remote rm origin
rm -rf .git/refs/original/ .git/refs/remotes/ .git/*_HEAD .git/logs/
git for-each-ref --format="%(refname)" refs/original/ |
  xargs -n1 --no-run-if-empty git update-ref -d

Coloquei tudo isso em um script, aqui:

http://sam.nipl.net/b/git-gc-all-ferocious

Sam Watkins
fonte
Como em stackoverflow.com/questions/1904860/… , +1 para você novamente.
VonC de
18
excelente: D meu plano maligno de conseguir mais pontos clonando respostas funcionou !! 1;)
Sam Watkins
Sim! Isso funcionou, mas eu tive que executar o script completo. Executar apenas o comando gc (com opções de configuração) não foi suficiente.
Daniel
4
102m a 160k .. eficaz e destrutivo
prusswan
4
Muito obrigado pelo script! Informações de bônus: O xargscomando produz um erro no OS X por causa de uma opção não reconhecida. Solução mais simples: Instale o GNU xargs via homebrew brew install findutilse substitua xargspor gxargs.
qqilihq
26

Seu git reflog expire --allestá incorreto. Ele remove as entradas de reflog mais antigas do que o tempo de expiração, cujo padrão é 90 dias. Use git reflog expire --all --expire=now.

Minha resposta a uma pergunta semelhante trata do problema de realmente limpar objetos não utilizados de um repositório.

Josh Lee
fonte
18

1) Remova o arquivo do repo git (e não do sistema de arquivos):

  • git rm --cached path/to/file

2) Reduza o repo usando:

  • git gc,

  • ou git gc --aggressive

  • ou git prune

ou uma combinação das opções acima, conforme sugerido nesta pergunta: Reduza o tamanho do repositório git

Jamie
fonte
10

Este guia sobre a remoção de dados confidenciais pode ser aplicado, usando o mesmo método. Você estará reescrevendo o histórico para remover esse arquivo de todas as revisões em que ele estava presente. Isso é destrutivo e causará conflitos de repo com quaisquer outros checkouts, então avise os colaboradores primeiro.

Se você deseja manter o binário disponível no repo para outras pessoas, não há uma maneira real de fazer o que você deseja. É quase tudo ou nada.

Daenyth
fonte
8

A chave para mim acabou sendo executar git repack -A -d -fe git gcreduzir o tamanho do pacote git único que eu tinha.

Andrew Charneski
fonte
6

Hy!

Git só recebe objetos de que realmente precisa ao clonar repositórios (se bem entendi)

Então você pode corrigir o último commit removendo o arquivo adicionado por engano, então enviar suas alterações para o repositório remoto (com a opção -f para sobrescrever o commit antigo no servidor também)

Então, quando você fizer um novo clone desse repo, seu diretório .git deverá ser tão pequeno quanto antes dos arquivos grandes enviados.

Opcionalmente, se você deseja remover os arquivos desnecessários do servidor também, você pode excluir o repositório no servidor e enviar sua cópia recém-clonada (que tem o histórico completo)

u-foka
fonte
5
git filter-branch --index-filter 'git rm --cached --ignore-unmatch Filename' --prune-empty -- --all

Lembre-se de mudar Filenamepara aquele que você deseja remover do repositório.

Martin
fonte