Solucionando Problemas de Desempenho Causados por Arquivos Grandes no Git
Diagnostique repositórios Git lentos causados por arquivos grandes, escolha o Git LFS com cuidado e limpe o histórico sem surpreender sua equipe.
Solucionando Problemas de Desempenho Causados por Arquivos Grandes no Git
Arquivos grandes prejudicam o Git de uma forma que é fácil de ignorar até que o repositório já esteja doloroso de usar. Um único vídeo, arquivo, dump de banco de dados ou arquivo de design pode não parecer perigoso quando alguém o adiciona. O problema começa quando esse arquivo muda várias vezes. O Git mantém o histórico, e cada clone tem que carregar esse histórico.
O sintoma geralmente é vago no início. git clone demora mais do que deveria. git fetch parece lento em Wi-Fi de hotel. Trabalhos de CI gastam muito tempo verificando o repositório antes mesmo de construir. Desenvolvedores começam a usar clones locais antigos porque um clone novo é irritante. Esse é o momento de inspecionar o repositório em vez de dizer a todos para terem paciência.
Confirme que arquivos grandes são o problema
Comece com verificações simples:
du -sh .git
git count-objects -vH
du -sh .git informa o peso do banco de dados do repositório local. git count-objects -vH mostra objetos soltos e o tamanho do pacote. Se o tamanho do pacote for grande em comparação com a árvore de origem real, o histórico provavelmente está carregando cargas antigas.
Para encontrar arquivos grandes no checkout atual:
find . -path ./.git -prune -o -type f -size +10M -print
Isso mostra apenas o que existe agora. Um repositório pode estar lento por causa de um arquivo que foi excluído há meses. Para inspecionar o histórico, o Git LFS fornece um relatório útil mesmo antes de você migrar qualquer coisa:
git lfs migrate info --everything --above=10MB
Se o Git LFS não estiver instalado, você ainda pode investigar com comandos internos do Git, mas o comando acima é geralmente a visão mais direta para esse problema específico.
Decida o que pertence ao Git
Nem todo arquivo grande é um erro. Um pequeno conjunto de ativos binários estáveis pode ser aceitável. Um repositório para código de infraestrutura não deve conter imagens de VM, backups de banco de dados, exportações de clientes ou artefatos de build. Um repositório de jogos pode conter legitimamente ativos de arte e áudio, mas esses arquivos geralmente precisam de Git LFS ou um sistema de ativos separado.
Uma regra prática é esta: Git é excelente para texto fonte e arquivos de suporte pequenos. Git é ruim para blobs binários que mudam com frequência. Se o arquivo não puder ser revisado de forma significativa em um diff e mudar com frequência, provavelmente não deve viver como um objeto Git normal.
Candidatos comuns para Git LFS incluem:
*.psd
*.ai
*.mp4
*.mov
*.wav
*.zip
*.uasset
*.fbx
*.blend
Tenha cuidado com padrões amplos de imagem. Rastrear cada *.png no LFS pode ser útil para um repositório com muito design, mas pode ser irritante para um aplicativo web com muitos ícones pequenos. Os padrões devem corresponder aos arquivos que realmente causam dor.
Use Git LFS para arquivos grandes futuros
O Git LFS armazena um pequeno arquivo de ponteiro no Git e mantém o conteúdo grande no armazenamento LFS. O histórico normal do Git permanece mais leve, enquanto os usuários ainda obtêm o arquivo real na árvore de trabalho quando o LFS o baixa.
Instale e inicialize:
git lfs install
Rastreie os padrões de arquivo que você realmente precisa:
git lfs track "*.psd"
git lfs track "*.mp4"
git add .gitattributes
git commit -m "Rastrear arquivos grandes de design e vídeo com Git LFS"
O arquivo .gitattributes é importante. Faça commit dele para que todos usem as mesmas regras do LFS.
Depois disso, adicione arquivos normalmente:
git add demo.mp4
git commit -m "Adicionar vídeo de demonstração do produto"
git push origin main
Um colaborador deve instalar o Git LFS antes de trabalhar com o repositório. Se ele clonar sem suporte ao LFS, pode ver arquivos de ponteiro em vez de ativos reais até instalar o LFS e executar:
git lfs pull
Verifique também a política de armazenamento e largura de banda no seu host Git. O Git LFS resolve o inchaço de objetos do Git, mas não torna ativos grandes gratuitos para armazenar ou transferir.
Migrando histórico existente
Ativar o LFS hoje não corrige automaticamente os commits de ontem. Se um arquivo de 700 MB foi commitado e depois excluído, ele ainda pode viver no histórico. Limpar isso requer reescrever o histórico.
Reescrever o histórico altera os IDs de commit. Qualquer pessoa com um clone existente deve ressincronizar com cuidado, e pull requests abertos podem precisar ser rebaseados ou recriados. Faça isso em uma janela de manutenção e faça um backup espelho primeiro:
git clone --mirror [email protected]:ORG/REPO.git repo-backup.git
Depois, trabalhe em um clone novo. Certifique-se de que a árvore de trabalho está limpa:
git status
Inspecione o que seria migrado:
git lfs migrate info --everything --above=10MB
Migre por padrão quando possível:
git lfs migrate import --everything --include="*.psd,*.mp4,*.zip"
Ou migre arquivos acima de um limite se o repositório tiver muitos arquivos grandes desconhecidos:
git lfs migrate import --everything --above=10MB
Revise o resultado antes de enviar:
git log --oneline --decorate -5
git lfs ls-files
git status
git lfs migrate info --everything --above=10MB
Se a migração fez o que você esperava, envie branches e tags reescritas deliberadamente:
git push --force-with-lease origin main
git push --force-with-lease origin --tags
Para um repositório com muitos branches ativos, decida quais branches importam. Você pode não precisar reescrever todos os branches abandonados, mas qualquer branch que ainda contenha os objetos grandes pode manter o repositório remoto pesado.
Após uma reescrita de histórico
Diga aos colegas de equipe exatamente o que mudou. A instrução mais limpa geralmente é clonar novamente. Se as pessoas têm trabalho local, elas devem salvá-lo primeiro:
git status
git branch my-work-before-lfs-migration
git fetch origin
git rebase origin/main
Para clones locais bagunçados, clonar novamente é menos arriscado do que tentar reparar cirurgicamente o histórico antigo.
O armazenamento remoto pode não encolher instantaneamente. Provedores de hospedagem mantêm objetos inacessíveis por um tempo, e alguns exigem suporte ou manutenção do repositório antes que os números de armazenamento sejam atualizados. Localmente, você pode podar objetos antigos depois de ter certeza de que a migração é boa:
git reflog expire --expire=now --all
git gc --prune=now --aggressive
Não execute comandos de limpeza como substituto para revisão. Eles tornam objetos locais antigos mais difíceis de recuperar.
Prevenindo o mesmo problema novamente
Adicione uma verificação de pre-commit ou pre-receive se arquivos grandes acidentais continuarem aparecendo. Um hook local de pre-commit pode alertar os desenvolvedores antes que eles commitem um artefato grande. Uma regra do lado do servidor é mais forte porque protege o repositório compartilhado mesmo quando alguém pula hooks locais.
Uma verificação local simples pode rejeitar arquivos acima de um tamanho escolhido, a menos que já estejam sendo rastreados pelo LFS. O limite exato depende do projeto. Um site de documentação e um projeto de jogo não devem usar o mesmo limite.
Corrija também a fonte dos arquivos. Se o CI criar dist/, target/, relatórios de cobertura, arquivos ou capturas de tela dentro do repositório, adicione as entradas corretas ao .gitignore:
dist/
target/
coverage/
*.log
*.zip
Não ignore arquivos cegamente. Certifique-se de que os caminhos ignorados são saídas geradas, não entradas de origem.
Quando o LFS não é a resposta
O Git LFS não é um armazenamento universal de artefatos. Saídas de build geralmente pertencem a um registro de pacotes, armazenamento de objetos, ativos de release ou armazenamento de artefatos de CI. Dumps de banco de dados pertencem ao armazenamento de backup. Conjuntos de dados grandes podem precisar de uma ferramenta de versionamento de dados ou um fluxo de trabalho de armazenamento separado.
O objetivo não é esconder todos os arquivos grandes do Git. O objetivo é manter o repositório rápido o suficiente para que as pessoas possam clonar, criar branches, buscar e revisar sem lutar contra a ferramenta.
Uma boa limpeza deixa três coisas para trás: regras claras de .gitattributes para arquivos que pertencem ao LFS, regras de .gitignore para arquivos que nunca devem ser commitados e uma breve nota da equipe explicando como clones existentes devem ressincronizar. É isso que impede que a correção se torne uma limpeza única que você repete no próximo trimestre.