- Vários gerenciadores de pacotes usaram o Git como se fosse um banco de dados pela conveniência do versionamento e da colaboração, mas, à medida que a escala aumenta, acabam esbarrando em problemas de desempenho e manutenção
- Cargo, Homebrew e CocoaPods, entre outros, acabaram migrando para índices baseados em HTTP ou CDN devido ao crescimento do índice em Git, à lentidão nas atualizações e à ineficiência em ambientes de CI
- O vcpkg ainda funciona com base em hashes de árvore do Git, e em ambientes com shallow clone surgem falhas de build e soluções alternativas complexas
- O sistema de módulos do Go introduziu o GOPROXY e o banco de dados de checksums (sumdb) para remover a dependência de Git e melhorar segurança e velocidade
- O Git é excelente para colaboração em código, mas volta a se mostrar inadequado para consultas de metadados de pacotes ou para gerenciar registries em grande escala
O fracasso recorrente das tentativas de usar Git como banco de dados
- O Git é atraente por vantagens como histórico de versões, estrutura distribuída e hospedagem gratuita, mas, quando usado como banco de dados, esbarra em limites de escalabilidade
- Vários gerenciadores de pacotes adotaram o Git como índice, mas com o tempo os problemas de desempenho e a carga de infraestrutura se agravaram
Cargo
- O índice do crates.io começou como um repositório Git, e todos os clientes faziam clone completo do conteúdo
- À medida que o repositório cresceu, surgiu um gargalo de desempenho no libgit2 durante a etapa de resolução de deltas
- Em ambientes de CI, baixar o índice inteiro a cada build gerava um desperdício enorme
- Com a RFC 2789, foi introduzido o protocolo sparse HTTP, melhorando o processo para buscar apenas os metadados necessários via HTTPS
- Em abril de 2025, 99% das requisições já usam o modo sparse
- O índice em Git ainda existe, mas a maioria dos usuários já não o acessa
Homebrew
- O GitHub pediu ao Homebrew que parasse de usar shallow clone, apontando que as atualizações eram uma “operação extremamente cara”
- A pasta
.git do homebrew-core chegava perto de 1 GB, e as atualizações sofriam atrasos por causa da resolução de deltas
- Em fevereiro de 2023, o Homebrew 4.0.0 mudou as atualizações de tap para um modelo de download em JSON
- Com a remoção do
git fetch, a velocidade de atualização melhorou, e o ciclo de atualização automática também mudou de 5 minutos para 24 horas
CocoaPods
- O CocoaPods, gerenciador de pacotes para iOS/macOS, viu seu repositório Specs, composto por centenas de milhares de podspecs, ficar grande demais
- Clonar e atualizar levava minutos, e a maior parte do tempo de CI era consumida por operações de Git
- O GitHub aplicou CPU rate limit, apontando o shallow clone como causa da carga no servidor
- A equipe adotou medidas temporárias como interromper fetch automático, migrar para clone completo e particionar o repositório
- A partir da versão 1.8, migrou para distribuição HTTP baseada em CDN, economizando cerca de 1 GB de espaço em disco por usuário e acelerando bastante a instalação
Nixpkgs
- O Nix já evita clones de Git no lado do cliente ao usar channels baseados em tarball
- As expressões de pacote são fornecidas por HTTP a partir de S3 e CDN
- Mesmo assim, a infraestrutura do GitHub sofre com um repositório de 83 GB e 20.000 forks
- Em novembro de 2025, o GitHub relatou falhas de consenso entre réplicas e erros em tarefas de manutenção
- O clone local tem 2,5 GB, mas toda a rede de forks pressiona o armazenamento do GitHub
vcpkg
- O vcpkg, gerenciador de pacotes C++ da Microsoft, controla versões com hashes de árvore do Git
- Para reproduzir as portas de um commit específico via
builtin-baseline, é necessário ter todo o histórico
- Em ambientes com shallow clone (GitHub Actions, DevContainers), ocorrem falhas de build
- Como solução, é preciso definir
fetch-depth: 0, exigindo o download do histórico completo
- Pela própria estrutura dos hashes de árvore do Git, não é possível rastrear commits, o que torna o problema impossível de corrigir dentro desse modelo
- Ele ainda só oferece suporte a registries baseados em repositório Git, sem alternativa em HTTP ou CDN
Sistema de módulos do Go
- A equipe de engenharia da Grab reduziu o tempo de
go get de 18 minutos para 12 segundos após introduzir um proxy de módulos
- No modelo anterior, era preciso clonar o repositório inteiro de cada dependência para ler o
go.mod
- A equipe do Go se preocupava com a dependência de ferramentas VCS e vulnerabilidades de segurança
- Desde o Go 1.13, o GOPROXY é o padrão, fornecendo o código-fonte dos módulos e o
go.mod via HTTP
- O sumdb (banco de dados de checksums) garante integridade e persistência dos módulos
Problemas gerais ao usar Git como banco de dados
- A wiki baseada em Git (Gollum) fica lenta para navegar por diretórios e carregar páginas em repositórios grandes
- O GitLab planeja descontinuar o uso do Gollum
- O CMS baseado em Git (Decap) esbarra no limite de 5.000 requisições da API do GitHub
- Acima de cerca de 10.000 itens, o desempenho cai, e usuários novos com cache vazio podem provocar uma avalanche de requisições
- A ferramenta GitOps (ArgoCD) enfrenta problemas de estouro de espaço em disco ao clonar repositórios
- Um único commit invalida todo o cache, e monorepos grandes exigem escalonamento separado
Motivos estruturais pelos quais o Git é inadequado como banco de dados
- Limite de diretórios: quanto maior o número de arquivos, mais lento tudo fica
- O CocoaPods gerava objetos de árvore enormes por causa de 16.000 diretórios, e resolveu isso com particionamento baseado em hash
- Problema de diferenciação entre maiúsculas e minúsculas: o Git diferencia, mas macOS e Windows não
- O Azure DevOps adicionou um bloqueio no lado do servidor para evitar conflitos
- Limite de tamanho de caminho: no Windows, o limite de 260 caracteres gera erros em
git status
- Ausência de recursos de banco de dados:
- Não há restrições CHECK/UNIQUE, bloqueios, índices nem mecanismos de migração
- Cada gerenciador de pacotes precisa construir seu próprio sistema de validação e indexação
Conclusão
- O Git é excelente para colaboração em código-fonte, mas inadequado para consultas de metadados de pacotes ou gerenciamento de registries em larga escala
- A maioria dos gerenciadores de pacotes acaba migrando para índices baseados em HTTP ou bancos de dados
- As vantagens do Git (histórico de versões, workflow com PRs) são atraentes, mas ele falha como substituto de banco de dados
- Ao projetar um novo gerenciador de pacotes, mesmo que um índice em Git pareça atraente, ele acaba chegando às mesmas limitações vistas nos casos de Cargo, Homebrew, CocoaPods, vcpkg e Go
2 comentários
Em vez de criar um sistema separado para receber contribuições dos colaboradores, usam o git porque é mais simples. Dizem que isso é uma limitação, mas eu particularmente não concordo muito, e também não vejo nenhuma alternativa para os problemas práticos.
Comentários do Hacker News
Isso parece uma espécie de tragédia dos comuns. O GitHub é gratuito e tem muitos recursos excelentes, então todo mundo quer usar. Mas esse tipo de decisão sempre acontece quando há externalidades
A externalidade que considero mais importante é o tempo do usuário. A maioria das empresas de software só se preocupa com o custo do tempo de engenharia e ignora o tempo do usuário. Focam em desenvolver funcionalidades, mas não otimizam o tempo de interação do usuário. Por exemplo, se eu gastar 1 hora para deixar um app 1 segundo mais rápido, um milhão de usuários economizam 277 horas por ano. Mas como o tempo do usuário é uma externalidade, esse tipo de otimização quase nunca acontece
No fim, o usuário baixa mais dados à toa e fica esperando, e o desenvolvedor não se responsabiliza por esse desperdício
Estou criando um Cargo/UV para C. Excelente texto, me identifiquei bastante.
No começo, operar um registro é realmente muito difícil. Além de escrever código, garantir a qualidade da ferramenta e difundir a comunidade, ainda é preciso pensar em uma infraestrutura que aguente tráfego global. Nessa situação, uma solução baseada em git é atraente
Mas o problema é o sparse checkout. Quero versionar manifestos de pacote com git, mas é preciso rastrear commits arbitrários, o que é ineficiente. No fim, a estrutura exige empurrar dois commits, então na prática fica inviável
Acho que a abordagem do Conan é a mais prática. Em vez de reprodutibilidade perfeita, coloca lógica condicional no manifesto. Também permite mapear manifestos por intervalo de versões. Não é perfeito, mas é um compromisso prático e útil.
Claro, a solução de verdade é usar um banco de dados, mas como ninguém vai pagar a conta do servidor e da manutenção por você, isso é difícil na prática
Se o problema for dinheiro e independência, um modelo P2P também é possível. Só que, sem cache de CI, o tráfego pode explodir
A estrutura de espelhos de distribuições Linux como Debian, Fedora e openSUSE também é uma boa referência
Este texto está confundindo dois problemas. Um é usar git como banco de dados do índice de pacotes, o outro é buscar o código de cada pacote com git. São coisas separadas.
O índice pode estar em git e os pacotes em zip/tar, ou o contrário. No caso do Go, a estrutura nem tem índice
Discussões sobre o backend do GitHub ou sobre 20 mil forks não têm relação com a essência do problema. Dá para fazer consultas eficientes de chave-valor sem árvore de trabalho do git.
A afirmação de que “reescrever o histórico do git é como uma migração de banco” também é estranha. Não seria melhor simplesmente rodar um Postgres?
A abordagem de “usar o jeito fácil enquanto funciona, e consertar quando deixar de funcionar” é realista.
Julia também usa esse método e, como tem cerca de 1/7 da quantidade de pacotes do Rust, ainda não sofre com isso.
Dá para melhorar baixando apenas o arquivo Registry.toml do topo e depois só os pacotes necessários. Não é um grande problema
A cultura de “Move fast and break things” produziu o software lento e cheio de bugs de hoje
Concordo com a conclusão de que “Git é um excelente banco de dados para começar um gerenciador de pacotes”
A visão de “no fim deu certo” também faz sentido. No começo, ajudou bastante na operação, e os problemas de escala puderam ser resolvidos depois
Há viés do sobrevivente(survivorship bias) aqui. O índice em git do Cargo virou um problema porque o Cargo deu certo.
A maioria dos projetos pequenos usa git muito bem como protocolo de distribuição de dados.
Quando a escala ainda é incerta no início, faz sentido usar git e GitHub para focar no problema principal
Sempre fico mais humilde quando vejo na primeira página do HN um texto dizendo “o que você está fazendo agora está errado”.
Já passei por isso algumas vezes. Desta vez foi com um texto sobre PG Notify.
Mas no momento estou desenvolvendo sozinho e nem sei se o projeto vai dar certo, então distribuir plugins com git é a opção mais realista.
Ainda assim, se surgirem problemas de escala depois, pretendo voltar a este texto
Eu pessoalmente hospedo meu código com Forgejo. Ele fica protegido por mTLS, sem exposição externa.
Mas os módulos Go exigem certificado e, por isso, não reconhecem minha instância do Forgejo.
Mesmo usando SSH, disseram que ainda seria necessário acesso por HTTPS, então acabei usando uma cópia local com replace directive. É bem incômodo
.gitno fim do caminho do módulo e configurar$GOPRIVATE, dá para usar autenticação de comando git sem requisições HTTPS. Veja a documentação oficialNão são só gerenciadores de pacotes: muitos projetos pequenos também fazem crowdsourcing de dados em repositórios git.
A maioria é pequena e não chega a bater nos limites técnicos.
Mas essa estrutura aumenta a barreira de entrada para quem não é desenvolvedor. Gerenciadores de pacotes são exceção, mas em projetos gerais isso é um problema
Para ajudar nesse tipo de situação, criei uma biblioteca open source chamada Datatig.
Os materiais da apresentação relacionada estão aqui. Vou usar este texto como referência para acrescentar também conteúdo sobre escalabilidade no futuro