7 puntos por GN⁺ 2025-12-27 | 2 comentarios | Compartir por WhatsApp
  • Varios gestores de paquetes usaron Git como si fuera una base de datos por la conveniencia del control de versiones y la colaboración, pero a medida que crecieron se toparon con problemas de rendimiento y mantenimiento
  • Cargo, Homebrew y CocoaPods, entre otros, terminaron migrando a índices basados en HTTP o CDN debido al crecimiento del índice en Git, la lentitud de las actualizaciones y la ineficiencia en entornos de CI
  • vcpkg sigue funcionando sobre hashes de árbol de Git, y en entornos con clones superficiales (shallow clone) se producen fallos de compilación y soluciones alternativas complejas
  • El sistema de módulos de Go introdujo GOPROXY y una base de datos de checksums (sumdb) para eliminar la dependencia de Git y mejorar la seguridad y la velocidad
  • Git es excelente para colaborar sobre código, pero se vuelve a demostrar que no es adecuado para consultas de metadatos de paquetes ni para administrar registros a gran escala

El fracaso repetido de intentar usar Git como base de datos

  • Git resulta atractivo por ventajas como el historial de versiones, la estructura distribuida y el hosting gratuito, pero al usarlo como base de datos se topa con límites de escalabilidad
  • Varios gestores de paquetes adoptaron Git como índice, pero con el tiempo se agravaron los problemas de rendimiento y la carga de infraestructura

Cargo

  • El índice de crates.io comenzó como un repositorio Git, y todos los clientes hacían una clonación completa (clone)
    • A medida que el repositorio creció, apareció un cuello de botella de rendimiento en libgit2 durante la fase de resolución de deltas
    • En entornos de CI, descargar el índice completo en cada build generaba un desperdicio importante
  • Con RFC 2789 se introdujo el protocolo sparse HTTP, mejorando el sistema para traer por HTTPS solo los metadatos necesarios
    • A abril de 2025, el 99% de las solicitudes usan el modo sparse
    • El índice Git sigue existiendo, pero la mayoría de los usuarios ya no accede a él

Homebrew

  • GitHub pidió a Homebrew dejar de usar clones superficiales, señalando que las actualizaciones eran “una operación extremadamente costosa”
    • La carpeta .git de homebrew-core se acerca a 1 GB, y durante la actualización se producen demoras por la resolución de deltas
  • En febrero de 2023, con Homebrew 4.0.0, las actualizaciones de taps pasaron a un método de descarga por JSON
    • Al eliminar git fetch, mejoró la velocidad de actualización y el ciclo de autoactualización cambió de 5 minutos a 24 horas

CocoaPods

  • CocoaPods, gestor de paquetes para iOS/macOS, vio crecer demasiado su repositorio Specs, compuesto por cientos de miles de podspecs
    • Clonar y actualizar tomaba varios minutos, y la mayor parte del tiempo de CI se consumía en operaciones Git
  • GitHub aplicó un CPU rate limit, señalando a los shallow clones como causa de la carga en el servidor
  • El equipo aplicó medidas temporales como detener el fetch automático, cambiar a clonación completa y fragmentar el repositorio
  • Desde la versión 1.8, migró a una distribución HTTP basada en CDN, ahorrando alrededor de 1 GB de espacio en disco para los usuarios y mejorando mucho la velocidad de instalación

Nixpkgs

  • Nix ya evita la clonación Git en el cliente usando canales basados en tarballs
    • Las expresiones de paquetes se sirven por HTTP desde S3 y una CDN
  • Sin embargo, la infraestructura de GitHub sigue cargando con un repositorio de 83 GB y 20,000 forks
    • En noviembre de 2025, GitHub reportó fallos de consenso entre réplicas y errores en tareas de mantenimiento
    • Aunque el clon local pesa 2.5 GB, toda la red de forks presiona el almacenamiento de GitHub

vcpkg

  • vcpkg, el gestor de paquetes de C++ de Microsoft, usa hashes de árbol de Git para el versionado
    • Para reproducir los ports de un commit específico mediante builtin-baseline, se necesita el historial completo
  • En entornos de clonación superficial (GitHub Actions, DevContainers) se producen fallos de compilación
    • La solución requiere configurar fetch-depth: 0, lo que obliga a descargar todo el historial
  • Por la estructura de hashes de árbol de Git, no es posible rastrear commits, una limitación estructural imposible de corregir
  • Sigue soportando solo registros basados en repositorios Git, sin alternativa por HTTP ni CDN

Sistema de módulos de Go

  • El equipo de ingeniería de Grab redujo el tiempo de go get de 18 minutos a 12 segundos después de introducir un proxy de módulos
  • El método anterior exigía clonar el repositorio completo de cada dependencia para poder leer go.mod
  • El equipo de Go expresó preocupación por la dependencia de herramientas VCS y las vulnerabilidades de seguridad
  • Desde Go 1.13, GOPROXY es el valor predeterminado y entrega por HTTP el código fuente del módulo y go.mod
    • sumdb (base de datos de checksums) garantiza la integridad y persistencia de los módulos

Problemas generales al usar Git como base de datos

  • Las wikis basadas en Git (Gollum) se vuelven lentas al explorar directorios y cargar páginas en repositorios grandes
    • GitLab planea dejar de usar Gollum
  • Los CMS basados en Git (Decap) chocan con el límite de 5,000 solicitudes de la API de GitHub
    • A partir de unos 10,000 elementos el rendimiento cae, y los usuarios nuevos con caché vacía disparan una avalancha de solicitudes
  • Las herramientas GitOps (ArgoCD) presentan problemas de espacio en disco al clonar repositorios
    • Un solo commit invalida toda la caché, y los monorepos grandes requieren escalado por separado

Razones estructurales por las que Git no sirve como base de datos

  • Límite de directorios: mientras más archivos hay, más lento se vuelve
    • CocoaPods generaba enormes objetos de árbol por culpa de 16,000 directorios, y lo resolvió con fragmentación basada en hashes
  • Problemas de distinción entre mayúsculas y minúsculas: Git sí distingue, pero macOS y Windows no
    • Azure DevOps agregó una función de bloqueo del lado del servidor para evitar conflictos
  • Límite de longitud de ruta: el tope de 260 caracteres en Windows provoca errores en git status
  • Ausencia de funciones de base de datos:
    • No tiene restricciones CHECK/UNIQUE, bloqueos, índices ni migraciones
    • Cada gestor de paquetes debe construir su propio sistema de validación e indexación

Conclusión

  • Git es excelente para la colaboración sobre código fuente, pero no sirve para consultas de metadatos de paquetes ni para administrar registros a gran escala
  • La mayoría de los gestores de paquetes terminaron migrando a índices basados en HTTP o bases de datos
  • Las ventajas de Git (historial de versiones, flujo de trabajo con PR) resultan atractivas, pero como reemplazo de una base de datos fracasa
  • Al diseñar un nuevo gestor de paquetes, aunque un índice en Git parezca atractivo, se llega a las mismas limitaciones que muestran los casos de Cargo, Homebrew, CocoaPods, vcpkg y Go

2 comentarios

 
lamanus 2025-12-28

Se usa Git porque es más práctico que crear un sistema aparte para recibir aportes de los contribuidores. Dicen que es una limitación, pero no me genera mucha empatía ese argumento, y tampoco se ve ninguna alternativa realista para los problemas del mundo real.

 
GN⁺ 2025-12-27
Opiniones en Hacker News
  • Esto parece una especie de tragedia de los comunes. GitHub es gratis y tiene muchas funciones excelentes, así que todos quieren usarlo. Pero este tipo de decisión siempre ocurre cuando hay externalidades
    La externalidad que considero más importante es el tiempo del usuario. La mayoría de las empresas de software solo se preocupan por el costo del tiempo de ingeniería e ignoran el tiempo del usuario. Se entusiasman con desarrollar funciones, pero no optimizan el tiempo de interacción del usuario. Por ejemplo, si gasto 1 hora en hacer que una app sea 1 segundo más rápida, un millón de usuarios ahorran en conjunto 277 horas al año. Pero como el tiempo del usuario es una externalidad, este tipo de optimización casi nunca ocurre
    Al final, los usuarios terminan descargando más datos de lo necesario y esperando sin sentido, y los desarrolladores no asumen responsabilidad por ese desperdicio

    • No sé exactamente qué significa la expresión “software house”, pero la mayoría de los productos de software para consumidores en los que trabajé sí seguían de cerca métricas como velocidad de arranque o latencia. Esto ha sido sentido común desde hace décadas. Por ejemplo, se hablaba mucho de que Amazon perdía millones de dólares por diferencias de apenas unos milisegundos en la carga de páginas
    • Esto va en la misma línea de decir que “la velocidad también es una función(feature)”. Solo que el tiempo del usuario depende mucho no solo del rendimiento, sino también del diseño de UI
    • No creo que esto sea una “tragedia de los comunes”. GitHub es propiedad de Microsoft, así que ellos decidieron que podían absorber ese costo. Un bien común real tendría que ser algo que nadie posee y del que todos se benefician
    • Si uno piensa a fondo en este problema, viene a la mente una frase de Alan Kay: “si de verdad te importa el software, también deberías hacer tu propio hardware”. Cargar cosas por red es, por naturaleza, una mala experiencia de usuario. Si realmente respetas al usuario, deberías crear aplicaciones local-first (native-first). Pero son poquísimas las empresas que respetan la experiencia de usuario hasta ese punto
    • El texto “Saving Lives” de Andy Hertzfeld es interesante — incluye una anécdota de “el arranque de Macintosh es demasiado lento. ¡Hay que hacerlo más rápido!”
  • Estoy haciendo Cargo/UV para C. Me identifiqué mucho con el artículo; es muy bueno.
    Cuando uno empieza, operar un registro es realmente difícil. No solo hay que escribir código, asegurar la calidad de las herramientas y hacer crecer la comunidad, sino también pensar en la infraestructura capaz de soportar tráfico global. En ese contexto, una solución basada en git resulta atractiva
    Pero el problema está en el sparse checkout. Quieres versionar los manifiestos de paquetes con git, pero como tienes que seguir commits arbitrarios, termina siendo ineficiente. Al final queda una estructura en la que hay que hacer push de dos commits, así que en la práctica no es viable
    Creo que el enfoque de Conan es el más práctico. En vez de buscar reproducibilidad perfecta, mete lógica condicional dentro del manifiesto. También permite mapear manifiestos por rangos de versiones. No es perfecto, pero es un compromiso práctico y útil.
    Claro, la solución real sería usar una base de datos, pero como nadie va a pagar por ti los servidores ni el mantenimiento, en la práctica es difícil

    • Viéndolo desde otro ángulo, la mayoría de los gestores de paquetes exitosos empezaron al principio basados en Git y luego migraron a una estructura más eficiente cuando fue necesario
    • También vale la pena considerar el modelo de Arch Linux AUR. Cada paquete tiene su propio repositorio git independiente y solo contiene el manifiesto. Así se evitan el problema del monorepo y las pesadillas de referencias
    • También resulta atractiva la idea de operar el registro con un backend HTTP simple como S3. Al principio puedes arrancar con un solo servidor y, si gana popularidad, buscar patrocinadores y moverlo a la nube.
      Si el problema es el dinero y la independencia, también se podría usar un modelo P2P. Eso sí, si no hay caché de CI, el tráfico puede dispararse
    • Si todavía no tienes muchos usuarios, preparar desde ya infraestructura global es prematuro
    • Tampoco hace falta mostrarle al usuario todos los datos históricos. Con un post-commit hook se puede renderizar solo el estado de HEAD como archivos estáticos y servirlo al estilo de GitHub Pages.
      También vale la pena mirar la estructura de mirrors de distribuciones Linux como Debian, Fedora y openSUSE
  • Este artículo está mezclando dos problemas. Uno es usar git como base de datos del índice de paquetes, y otro es traer el código de cada paquete con git. Son cosas distintas.
    Puedes tener el índice en git y los paquetes en zip/tar, o al revés. En el caso de Go, de hecho, ni siquiera hay índice

    • El autor parece un poco confundido. Estoy de acuerdo con la idea de “no hagas que todos los usuarios repliquen la base de datos”, pero eso no significa que no puedas usar el grafo de git para codificar datos.
      Las historias sobre el backend de GitHub o sobre 20 mil forks no tienen relación con lo esencial. Incluso sin working tree de git, se pueden hacer consultas key-value eficientes.
      También es rara la afirmación de que “reescribir el historial de git es como una migración de DB”. ¿No sería mejor simplemente levantar un Postgres?
    • El punto central del artículo no es el código en sí, sino el proceso de obtener el archivo go.mod. Por eso la solución fue alojar go.mod por separado
    • En git también es posible traer solo un archivo cuando hace falta, pero aun así estructuralmente se siente raro
  • El enfoque de “usemos la solución fácil mientras funcione, y si no, luego la arreglamos” es realista.
    Julia usa el mismo enfoque, y como tiene una cantidad de paquetes equivalente a 1/7 de Rust, todavía no hay problema.
    Se podría mejorar descargando solo el archivo superior Registry.toml y luego solo los paquetes necesarios. No es un gran problema

    • Julia usa el registro git solo como ledger oficial, y los clientes reales usan Pkg Protocol
    • A este enfoque también se le podría llamar la mentalidad de FAFO(veamos qué pasa y luego nos estrellamos). Es práctico, pero personalmente no me gusta
    • Creo que esa actitud es antiética. La idea de “hagámoslo fácil primero y luego lo arreglamos” al final solo agranda la deuda técnica.
      La cultura de “Move fast and break things” es lo que produjo el software lento y lleno de bugs que tenemos hoy
    • Si arreglas el problema después, el costo crece exponencialmente. Al final se llega a la conclusión de “déjalo medio roto y ya”. El caso de vcpkg en el artículo es justo un ejemplo de eso
    • Hay un ejemplo que parece mostrar a alguien manipulando UUIDs intencionalmente, y me preocupa un poco que eso sea posible
  • Coincido con la conclusión de que “Git es una excelente base de datos para iniciar un gestor de paquetes”

    • Eso sí, el cliente no debería bajar todo el repositorio, sino tener una capa de caché o DB. En entornos de CI/CD la eficiencia es especialmente importante
    • Nixpkgs también tuvo éxito gracias a Git. Los problemas de escala son un lujo para preocuparse después
    • Pero antes de elogiar tanto a Git, convendría leer хотя sea un poco de investigación sobre bases de datos
    • Git también puede provocar pesadillas de cadena de suministro. El caso Leftpad podría repetirse cada semana
    • Git es malísimo como DB para un gestor de paquetes. La única razón por la que todos lo usan es porque GitHub lo hospeda gratis
  • Mi postura es “al final salió bien, ¿no?”. Para la operación inicial fue más que suficiente y los problemas de escala se podían resolver después

    • Pero algunos proyectos no pueden salir de git por limitaciones arquitectónicas
    • Si empiezas con un store basado en sistema de archivos como git, luego cambiar el protocolo se vuelve casi imposible. Hay que ir con un diseño centrado en API desde el principio
    • De hecho, todavía hay margen para aprovechar git de forma más eficiente. Decir simplemente “abandonemos git” sin proponer una alternativa es una conclusión a medias
    • También hubo un chiste sarcástico del tipo “como no escaló de 0 a un billón de usuarios, entonces es basura”
  • Aquí hay sesgo de supervivencia (survivorship bias). Cargo tuvo éxito, por eso el índice git creció hasta volverse un problema.
    La mayoría de los proyectos pequeños usan git sin problema como protocolo de distribución de datos.
    Cuando al inicio no está claro si algo va a escalar, es razonable usar git y GitHub para concentrarse en el problema central

    • Hay que cuidarse de la optimización demasiado temprana. Cargo y Homebrew también tomaron el camino fácil para crecer, y los problemas de escala después fueron de esos “buenos problemas”
  • Cada vez que veo en la portada de HN un artículo que dice “lo que estás haciendo ahora está mal”, me vuelvo más humilde.
    Ya me pasó varias veces. Esta vez fue con un artículo sobre PG Notify.
    Pero por ahora estoy desarrollando solo, y ni siquiera sé si el proyecto va a tener éxito, así que distribuir plugins con git es lo más realista.
    Aun así, si más adelante aparecen problemas de escala, pienso volver a este artículo

    • Incluso ahora se pueden evitar algunas trampas. La dependencia de GitHub y el vendor lock-in podrían ser un problema todavía mayor
  • En lo personal hospedo mi código en Forgejo. Lo protejo con mTLS sin exponerlo al exterior.
    Pero los módulos de Go exigen certificados, así que no reconocen mi instancia de Forgejo.
    Aunque use SSH, me dicen que igual hace falta acceso por HTTPS, así que terminé usando una copia local mediante la directiva replace. Es bastante molesto

    • Si agregas .git al final de la ruta del módulo y configuras $GOPRIVATE, puedes usar autenticación de comandos git sin hacer solicitudes HTTPS. Revisa la documentación oficial
    • Si agregas el certificado TLS (CA) de la instancia al almacén de confianza, también se puede descargar por HTTPS
    • No es cierto que “se necesite acceso HTTP”. Se puede resolver con un proxy local
    • Si usas DNS y certificados de Tailscale, puedes obtener certificados de Let’s Encrypt sin exponerlo al exterior
  • No solo los gestores de paquetes; muchos proyectos pequeños también hacen crowdsourcing de datos en repositorios git.
    La mayoría son pequeños, así que no chocan con límites técnicos.
    Pero esta estructura sí eleva la barrera de participación para gente no desarrolladora. En gestores de paquetes es una excepción, pero en proyectos generales sí es un problema
    Para ayudar con ese tipo de problemas hice una librería open source llamada Datatig.
    El material de la charla relacionada está aquí. Más adelante planeo usar este artículo como referencia para agregar también contenido sobre escalado