Cuando Git se rompe: lecciones de un monorepo a gran escala
Git para monorepos falla de forma predecible con merges masivos. Lecciones sobre clientes siempre en línea y commits del lado del servidor.

Si mantienes un monorepo de git, hay un número en tu futuro en el que todo se viene abajo. En Anthropic ese número fueron unos 30.000 merges al día, un historial de 100 GB en la rama principal y del orden de 25 millones de checkouts de CI diarios, que, si se descargan de forma ingenua, equivalen a más de 600 petabytes de tráfico de git. Cada día. Su respuesta fue escribir su propio sistema de control de versiones en cinco meses. La tuya no debería ser esa. Pero los errores que cometieron por el camino son los mismos que veo cometer a equipos con una décima parte de esa escala, así que vamos a repasarlos.
Error uno: tratar un flujo de trabajo centralizado como si fuera distribuido
La apuesta de diseño central de git es la descentralización. Cada clon es un repositorio completo: todo el historial, todo el almacén de objetos y plenamente funcional sin conexión. Esa apuesta le dio el mundo a git y, en la mayoría de los repos, sigue siendo correcta. Pero hay algo que casi nadie admite: casi nadie usa git de esa manera. Tu organización tiene un remoto autoritativo en GitHub o GitLab. Tus desarrolladores hacen push y pull constantemente. Tus runners de CI están, por definición, en línea. Estás ejecutando un sistema centralizado con disfraz distribuido, y pagando los costes de un sistema distribuido: cada trabajo de CI arrastrando historial que nunca va a leer, cada sandbox de agente materializando packfiles que no necesita.
Esta es la primera lección real del rediseño de Anthropic. Cuando dieron un paso atrás, notaron que sus clientes eran «agentes y trabajos que están en línea por definición», así que diseñaron en torno a un servidor siempre accesible. El cliente se volvió deliberadamente tonto: una caché local acotada, un directorio de trabajo en disco y un observador del sistema de archivos. El servidor responde a blame, calcula diffs y realiza merges. Es la misma conclusión a la que llegó Google con Piper y Meta con Sapling, y no es una postura anti-git: es el reconocimiento de que la arquitectura debe coincidir con la carga de trabajo real, no con la que tenía la herramienta hace veinte años. He visto este patrón también en herramientas de seguridad: los equipos despliegan una arquitectura de agente con capacidad offline y luego la ejecutan en un entorno donde el modo offline literalmente nunca ocurre, y se preguntan por qué su capa de sincronización es una pesadilla.
La conclusión para tu equipo no es «construye un VCS». Es: audita tus suposiciones. Escribe qué propiedades de git realmente necesitas. ¿Trabajo sin conexión? ¿Forks reales? ¿Firma criptográfica de commits? Si la respuesta honesta es «un solo remoto, siempre en línea, CI hace todo», deja de optimizar para un flujo distribuido que no tienes y empieza a optimizar los costes de checkout y de consultas.
Error dos: tapar la escala con espejos y semillas
Todo equipo con repos grandes pasa por las mismas etapas de frustración. Primero los clones superficiales. Después los checkouts dispersos y los remotos promisor. Luego los espejos internos de git, y después «semillas» de snapshots en almacenamiento de objetos para que los jobs de CI puedan arrancar desde algo cercano a la punta de main. Anthropic usó todos estos, con varios cientos de espejos internos en el pico. Y el modo de fallo siempre es el mismo: las soluciones alternativas no fallan con estruendo, se pudren. Las semillas se alejan más de la punta entre refrescos. Los clones parciales rompen git blame y git log --follow de maneras confusas. El bisect de alguien devuelve resultados incorrectos en silencio porque el historial está truncado. Nadie se da cuenta hasta la revisión posterior al incidente.
Ese último punto es el que me quita el sueño. Los errores de corrección en historial parcial son exactamente el tipo de incorrección sutil que vive en la brecha entre lo que crees que el sistema garantiza y lo que realmente hace. Un clon superficial no da error cuando pides blame más allá de su profundidad; simplemente te da una respuesta parcial. Si tu pipeline automático de reversiones confía en esa respuesta, has construido una máquina que revierte con toda confianza el cambio equivocado.
- Los clones superficiales rompen las herramientas que dependen del historial (blame, bisect, merge-base) de forma silenciosa, no ruidosa.
- Las semillas de snapshot se alejan de la punta de main; cuanto mayor es tu tasa de merges, más rápido se alejan, así que la solución alternativa se degrada justo cuando sube la carga.
- Las flotas de espejos multiplican la superficie operativa: cientos de copias con estado que pueden retrasarse, corromperse o quedarse sin disco de forma independiente.
- Cada solución alternativa que toque la semántica del historial necesita una prueba de regresión, o te morderá durante un incidente.
La solución a la escala de Anthropic fue estructural: no existe en ningún lugar una copia totalmente materializada del repo, ni siquiera en el servidor, y todo está direccionado por contenido y es cacheable horizontalmente. A tu escala, la solución es más modesta: mide cuántas máquinas guardan copias completas o casi completas de tu repo, y sé honesto sobre la deriva y los modos de fallo de cada una.
Error tres: hacer que cada job de CI mantenga su propia copia del repo
Aquí hay una pregunta que vale la pena hacerse sobre tu flota de CI: ¿cuántos de esos jobs necesitan una copia de trabajo? La respuesta de Anthropic, tras construir su sistema, fue «bastantes menos de lo que suponíamos». Un job que necesita el diff entre un commit y su merge base, o el blame de un archivo, o la lista de commits que tocan una ruta, puede pedírselo directamente al servidor a través de una API. Sin clon, sin fetch, sin disco. Sus pipelines automáticos de bisect y reversión «no serían prácticos a escala» sin ese acceso programático barato, y lo creo, porque he visto a equipos intentar ejecutar esos mismos pipelines sobre clones locales y ahogarse en tiempos de fetch.
Este principio se generaliza mucho más allá del control de código fuente. Trata el checkout como la excepción costosa, no como el valor por defecto. Cuando un job sí necesita archivos, los checkouts dispersos y virtualizados, que materializan solo los directorios solicitados o incluso solo los archivos realmente leídos, reducen el coste en órdenes de magnitud. El protocolo de fetch de Anthropic eliminó por completo la negociación de git: el cliente pide árboles y blobs inmutables concretos, cualquier caché puede responder, y todo se comporta como una CDN por niveles en lugar de un servidor inteligente que calcula packfiles por cliente. Si alguna vez has perfilado un servidor de git derritiéndose bajo carga de CI, reconocerás por qué importa: generar packfiles consume mucha CPU precisamente porque el protocolo obliga al servidor a calcular un delta contra lo que cada cliente ya tiene.
Si tus clientes están siempre en línea y hay una única copia autoritativa, cada clon local que mantienes es una caché por la que pagas precio completo y que, de todos modos, se comporta como caché.
Error cuatro: dejar que el coste de un commit crezca con el tamaño del repo
La decisión de ingeniería más interesante de su diseño es el changeset. Un commit de git apunta a un árbol que representa todo el estado del repositorio; su changeset registra solo la lista de archivos que cambiaron respecto a su primer padre, más punteros direccionados por contenido hacia el almacenamiento de blobs, añadidos a un write-ahead log. Sin packfiles que aceptar, sin bloqueos, sin coordinación entre servidores. Las refs (ramas, etiquetas) están deliberadamente minimizadas porque «el estado global en el que todos los servidores tienen que ponerse de acuerdo es un problema de escalado inminente». Mover una ref es un compare-and-swap sobre una única fila de Spanner, desacoplado de la creación del commit.

La idea complementaria son los «datos derivados»: índices de blame, historial de rutas, listas de salto del grafo de commits, todos calculados recursivamente a partir de los padres de cada changeset, mediante un único mecanismo genérico. Calcúlalos de forma anticipada o perezosa según el tipo. Añade nuevos tipos de índice sin tocar el cliente. Es un patrón realmente bueno para cualquier sistema basado en eventos: yo he recomendado la misma forma para pipelines de logs de auditoría, donde el log de solo escritura es la verdad y cada estructura de consulta es una proyección reconstruible. En el momento en que alguien mantiene a mano una proyección fuera de ese mecanismo, tienes deriva.
Una advertencia desde el punto de vista de la seguridad: los comentaristas preocupados por la centralización tienen un punto que merece tomarse en serio. Un único sistema del lado del servidor donde viven commits, merges y consultas de historial es un objetivo de alto valor, y los agentes de IA con permisos de escritura sobre «el único repo que gobierna a todos» concentran el riesgo de forma muy mala. Anthropic construyó junto a todo esto un «sistema de IAM de control de código fuente enriquecido», y los detalles importan más que las estructuras de datos. Si centralizas, tus cálculos de radio de impacto cambian: presupuesta aislamiento, credenciales por agente y auditoría desde el primer día, no en el tercer trimestre. Los equipos que ejecutan agentes con estado sobre infraestructura compartida ya conocen este dolor.
Error cinco: suponer que 30.000 merges al día significan 30.000 buenas decisiones al día
La ingeniería es impresionante. La pregunta abierta es qué fluye a través de ella. Un practicante lo dijo sin rodeos: cada vez que dejan de revisar el código generado por IA, «después encuentro porquerías chapuceras. No toda revisión encuentra porquerías, pero lo bastante a menudo como para que no pueda dejar de revisarlo todo». Multiplica esa tasa de aciertos por 30.000 merges al día y entenderás por qué Anthropic también tuvo que construir «formas novedosas de gestionar y aterrizar grandes volúmenes de código revisado»: la superficie de revisión, la cola de aterrizaje, los pipelines automáticos de reversión. El VCS no era el producto. El pipeline de aterrizaje sí lo era. El control de versiones se convirtió en el cuello de botella solo después de que la capacidad de revisión lo fuera antes.
También hay un detalle sincero escondido en sus historias de guerra: los ingenieros del proyecto describieron gran parte de su papel como decirle al agente de programación «no». El prototipo de pipeline de ingesta que escribieron a mano estaba bien hasta que un modelo más nuevo lo reescribió con 20 veces menos memoria y 4 veces más rápido, pero llegar ahí requirió humanos con criterio decidiendo qué aceptar. Eso coincide con todo lo que he visto: la IA desplaza el trabajo del ingeniero de escribir a revisar, y el rendimiento de la revisión es ahora el recurso escaso. Ya hemos escrito sobre cómo cada capa de revisión hace más lento a un equipo; lo difícil es que, con código generado por agentes, eliminar capas de revisión tampoco es seguro. Necesitas mejores herramientas de revisión, no menos revisión.
Qué deberías hacer realmente
No eres Anthropic. No tienes su presupuesto de tokens, como ellos mismos admiten, ni 25 millones de checkouts diarios. Pero las herramientas de programación con IA están empujando al alza la tasa de merges de todos, y los puntos de presión llegan en un orden predecible. Este es el orden de operaciones que seguiría, en la ley de Priya del menor arrepentimiento:
- Mide primero. Cuenta los checkouts diarios, los bytes descargados por job de CI y cuántas máquinas guardan copias completas del repo. Probablemente tengas un problema de desperdicio antes que un problema de escala.
- Elimina los checkouts innecesarios. Pasa las preguntas sobre metadatos (diffs, blame, ascendencia) a APIs —las APIs de GitHub/GitLab o un servicio interno ligero— antes de comprar cualquier infraestructura.
- Haz que los clones dispersos y parciales sean seguros. Prueba tus herramientas de bisect, blame y reversión explícitamente contra clones superficiales, o prohíbelos en la automatización.
- Haz que el CI use por defecto descargas del lado del servidor de objetos inmutables siempre que puedas, y trata las flotas de espejos como deuda técnica con un tipo de interés compuesto.
- Invierte en el pipeline de aterrizaje, no en el formato del repo. La capacidad de revisión, las colas de merge y la reversión automática son donde el desarrollo a escala de agentes se rompe primero.
- Solo entonces considera arquitecturas de VCS alternativas: Sapling es de código abierto y te da la mayoría de los beneficios cliente-servidor sin tener que escribir el tuyo.
La lección más profunda aquí no tiene nada que ver con git. Es que cada herramienta codifica suposiciones sobre su carga de trabajo —humanos sin conexión, un commit a la vez, código escrito más lento de lo que se revisa— y esas suposiciones están siendo violadas por los agentes ahora mismo, en la infraestructura, en la revisión y en los límites de seguridad. Los equipos que salgan adelante no serán los que reconstruyan todo desde cero. Serán los que noten qué suposiciones se rompieron primero y arreglen exactamente esas.


