Como encontrar / identificar arquivos grandes / commits no histórico do Git?

Eu tenho um repository de 300 MB. Meus arquivos atualmente com check-out pesam 2 MB, e o repository git pesa 298 MB. Este é basicamente um repository somente de código que não deve pesar mais do que alguns MB.

Provavelmente, alguém em algum momento cometeu alguns arquivos pesados ​​por acidente (vídeo, imagens enormes, etc), e depois os removeu … mas não do git, então nós temos um histórico com arquivos grandes inúteis. Como posso rastrear os arquivos grandes no histórico do git? Existem mais de 400 commits, portanto, um por tempo será demorado.

NOTA : minha pergunta não é sobre como remover o arquivo , mas como encontrá- lo em primeiro lugar.

Eu encontrei este script muito útil no passado para encontrar objects grandes (e não óbvios) em um repository git:


#!/bin/bash #set -x # Shows you the largest objects in your repo's pack file. # Written for osx. # # @see https://stubbisms.wordpress.com/2009/07/10/git-script-to-show-largest-pack-objects-and-trim-your-waist-line/ # @author Antony Stubbs # set the internal field spereator to line break, so that we can iterate easily over the verify-pack output IFS=$'\n'; # list all objects including their size, sort by size, take top 10 objects=`git verify-pack -v .git/objects/pack/pack-*.idx | grep -v chain | sort -k3nr | head` echo "All sizes are in kB's. The pack column is the size of the object, compressed, inside the pack file." output="size,pack,SHA,location" allObjects=`git rev-list --all --objects` for y in $objects do # extract the size in bytes size=$((`echo $y | cut -f 5 -d ' '`/1024)) # extract the compressed size in bytes compressedSize=$((`echo $y | cut -f 6 -d ' '`/1024)) # extract the SHA sha=`echo $y | cut -f 1 -d ' '` # find the objects location in the repository tree other=`echo "${allObjects}" | grep $sha` #lineBreak=`echo -e "\n"` output="${output}\n${size},${compressedSize},${other}" done echo -e $output | column -t -s ', ' 

Isso lhe dará o nome do object (SHA1sum) do blob, e então você pode usar um script como este:

  • Qual commit tem esse blob?

… para encontrar o commit que aponta para cada um desses blobs.

One Uma concha incrivelmente rápida one

Este script de shell exibe todos os objects blob no repository, classificados do menor para o maior.

Para o meu repository de amostras, ele foi executado cerca de 100 vezes mais rápido do que os outros encontrados aqui.
No meu fiel sistema Athlon II X4, ele lida com o repository do Kernel Linux com seus 5,6 milhões de objects em pouco mais de um minuto .

O script base

 git rev-list --objects --all \ | git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' \ | sed -n 's/^blob //p' \ | sort --numeric-sort --key=2 \ | cut -c 1-12,41- \ | numfmt --field=2 --to=iec-i --suffix=B --padding=7 --round=nearest 

Quando você executar o código acima, você obterá uma saída legível, como esta:

 ... 0d99bb931299 530KiB path/to/some-image.jpg 2ba44098e28f 12MiB path/to/hires-image.png bd1741ddce0d 63MiB path/to/some-video-1080p.mp4 

Usuários de Mac : Como o numfmt não está disponível no macOS, você pode fazer a brew install coreutils --with-default-names ou simplesmente omitir a última linha e lidar com os tamanhos brutos de byte.

Filtrando

Para obter mais filtragem , insira qualquer uma das seguintes linhas antes da linha de sort .

Para excluir arquivos que estão presentes no HEAD , insira a seguinte linha:

 | grep -vF --file=< (git ls-tree -r HEAD | awk '{print $3}') \ 

Para mostrar apenas arquivos que excedam o tamanho especificado (por exemplo, 1 MiB = 2 20 B), insira a seguinte linha:

 | awk '$2 >= 2^20' \ 

Saída para computadores

Para gerar uma saída mais adequada para processamento posterior por computadores, omita as duas últimas linhas do script base. Eles fazem toda a formatação. Isso vai deixar você com algo assim:

 ... 0d99bb93129939b72069df14af0d0dbda7eb6dba 542455 path/to/some-image.jpg 2ba44098e28f8f66bac5e21210c2774085d2319b 12446815 path/to/hires-image.png bd1741ddce0d07b72ccf69ed281e09bf8a2d0b2f 65183843 path/to/some-video-1080p.mp4 

Remoção de arquivos

Para a remoção real do arquivo, confira esta pergunta sobre o tópico .

Eu encontrei uma solução de uma linha na página wiki do Departamento de Física da ETH em Zurique (perto do final da página). Basta fazer um git gc para remover lixo obsoleto e, em seguida,

 git rev-list --objects --all | grep "$(git verify-pack -v .git/objects/pack/*.idx | sort -k 3 -n | tail -10 | awk '{print$1}')" 

lhe dará os 10 maiores arquivos no repository.

Há também uma solução mais preguiçosa agora disponível, GitExtensions agora tem um plugin que faz isso na interface do usuário (e lida com a história reescreve também).

Diálogo GitExtensions 'Find large files'

Etapa 1 Grave todos os arquivos SHA1s em um arquivo de texto:

 git rev-list --objects --all | sort -k 2 > allfileshas.txt 

Etapa 2 Classifique os blobs do maior para o menor e grave os resultados no arquivo de texto:

 git gc && git verify-pack -v .git/objects/pack/pack-*.idx | egrep "^\w+ blob\W+[0-9]+ [0-9]+ [0-9]+$" | sort -k 3 -n -r > bigobjects.txt 

Passo 3a Combine os dois arquivos de texto para obter informações sobre o nome do arquivo / sha1 / size:

 for SHA in `cut -f 1 -d\ < bigobjects.txt`; do echo $(grep $SHA bigobjects.txt) $(grep $SHA allfileshas.txt) | awk '{print $1,$3,$7}' >> bigtosmall.txt done; 

Etapa 3b Se você tiver nomes de arquivos ou nomes de caminhos contendo espaços, tente essa variação da Etapa 3a. Usa cut vez de awk para obter as colunas desejadas incl. espaços da coluna 7 ao final da linha:

 for SHA in `cut -f 1 -d\ < bigobjects.txt`; do echo $(grep $SHA bigobjects.txt) $(grep $SHA allfileshas.txt) | cut -d ' ' -f'1,3,7-' >> bigtosmall.txt done; 

Agora você pode olhar o arquivo bigtosmall.txt para decidir quais arquivos você deseja remover do seu histórico do Git.

Etapa 4 Para executar a remoção (observe que esta parte está lenta, pois examinará cada confirmação em seu histórico de dados sobre o arquivo identificado):

 git filter-branch --tree-filter 'rm -f myLargeFile.log' HEAD 

Fonte

Etapas 1-3a foram copiados de Finding e Purging Big Files From Git History

EDITAR

O artigo foi excluído em algum momento no segundo semestre de 2017, mas uma cópia arquivada dele ainda pode ser acessada usando o Wayback Machine .

Você deve usar o BFG Repo-Cleaner .

Segundo o site:

O BFG é uma alternativa mais simples e rápida ao git-filter-branch para limpar dados ruins do histórico do seu repository Git:

  • Removendo Crazy Big Files
  • Removendo senhas, credenciais e outros dados privados

O procedimento clássico para reduzir o tamanho de um repository seria:

 git clone --mirror git://example.com/some-big-repo.git java -jar bfg.jar --strip-biggest-blobs 500 some-big-repo.git cd some-big-repo.git git reflog expire --expire=now --all git gc --prune=now --aggressive git push 

Se você quer apenas ter uma lista de arquivos grandes, então eu gostaria de lhe fornecer o seguinte one-liner ( source at renuo ):

 join -o "1.1 1.2 2.3" < (git rev-list --objects --all | sort) <(git verify-pack -v objects/pack/*.idx | sort -k3 -n | tail -5 | sort) | sort -k3 -n 

De quem será a saída:

 commit file name size in bytes 72e1e6d20... db/players.sql 818314 ea20b964a... app/assets/images/background_final2.png 6739212 f8344b9b5... data_test/pg_xlog/000000010000000000000001 1625545 1ecc2395c... data_development/pg_xlog/000000010000000000000001 16777216 bc83d216d... app/assets/images/background_1forfinal.psd 95533848 

A última input na lista aponta para o maior arquivo no seu histórico do git.

Você pode usar esta saída para garantir que você não está apagando coisas com o BFG que você precisaria em seu histórico.

Se você estiver no Windows, aqui está um script do PowerShell que imprimirá os 10 maiores arquivos em seu repository:

 $revision_objects = git rev-list --objects --all; $files = $revision_objects.Split() | Where-Object {$_.Length -gt 0 -and $(Test-Path -Path $_ -PathType Leaf) }; $files | Get-Item -Force | select fullname, length | sort -Descending -Property Length | select -First 10 

Como posso rastrear os arquivos grandes no histórico do git?

Comece analisando, validando e selecionando a causa raiz. Use git-repo-analysis para ajudar.

Você também pode encontrar algum valor nos relatórios detalhados gerados pelo BFG Repo-Cleaner , que podem ser executados rapidamente clonando-os em um droplet Digital Ocean usando sua taxa de transferência de rede de 10 MiB / s.

Eu tropecei nisso pela mesma razão que qualquer outra pessoa. Mas os roteiros citados não funcionaram bem para mim. Eu fiz um que é mais um híbrido daqueles que eu vi e agora vive aqui – https://gitlab.com/inorton/git-size-calc