How does GitHub's new Git storage handle 7,200 pushes per second?
GitHub has built a new way to store Git repositories. It lets thousands of automated agents push code to the same project at the same time.
The problem that forced a rewrite
Agents changed what a busy repository looks like. Today the busiest repositories on GitHub.com receive at most dozens of writes in a single second, typically in short bursts. As more work shifts to agents running in parallel and around the clock, those bursts become a sustained rate. Each push triggers more reads: CI runs, deployment systems pull the new commit, other agents fetch it for context. This read fan-out creates a large amplification effect that scales with writes. One repository on GitHub saw daily requests grow about 4x from March to May and has continued on an exponential trajectory since then. The team set a target of at least two orders of magnitude more scale.
Virtual replicas and the Ref-CAS log
The new architecture separates compute from durable state. Spokes still handles routing and load balancing. Underneath it sits a fleet of virtual replicas — disposable compute that serves reads, writes, or both. A virtual replica's local disk is a cache that can be rebuilt at any time. Spokes routes a repository's traffic to the same virtual replicas when possible to keep caches warm, but correctness does not depend on any particular replica. When a replica goes away the others keep serving and a replacement fills its cache as traffic arrives. When a repository gets busy more virtual replicas are added.
Durable state lives in two places. Git objects — packs, indexes, reachability bitmaps, multi-pack indexes, cached fetch responses, and checkpoints — live in Azure Blob Storage. References and the pack manifest live in a replicated log service called Ref-CAS, short for Reference Compare-and-Swap. Ref-CAS is the small consensus group the previous post hinted at. Each reference update is a compare-and-swap committed by a quorum. A transaction locks only the references it touches, checks that each still has the expected value, and becomes visible once a majority of replicas record it. Agents mostly push to their own branches so most updates do not contend and replicate in parallel. When two pushes update the same reference only one appends to the log. Each commit receives a log sequence number. The repository's version is the LSN of its latest commit.
How a write becomes visible
The incoming pack gets indexed and uploaded to Blob Storage by a virtual replica. Then it commits one transaction to Ref-CAS that lists the pack in the manifest and updates the references. The pack is already durable before the reference points to it. Later a compaction node merges that pack with others to keep reads fast. This design allows tens of thousands of reference operations per second. The virtual replica never validates object data inside Ref-CAS. It only stores pointers.
How a read stays cheap
A virtual replica checks its reference version with Ref-CAS. If the version it holds is still current the reply carries no references at all. An unchanged repository costs a single comparison. If the replica is behind it receives the current references and version along with pointers to pack data and anything else needed such as when the last garbage collection cycle occurred. The replica then pulls the packs it needs from Blob Storage into its cache and serves the read from there. Reads outnumber writes by orders of magnitude so this fast path matters.
Compaction runs on its own fleet
Every push adds a pack to Blob Storage. Git can serve a repository from many packs but each additional pack makes lookups slightly more expensive so the pack count cannot grow without bound. In the legacy architecture compaction ran on the same replicas that serve traffic and had to run on every replica. In the new architecture it runs entirely in the background on separate compaction nodes directly against durable storage using Ref-CAS to notify virtual replicas of the evolving state.
Each compaction node claims ownership over a subset of the repository's data via a lease so only one node compacts a shard at a time. Meanwhile virtual replicas keep uploading packs and listing them in the manifest. The node reads the manifest to find new packs and collects them into an open segment. When the segment reaches a defined limit based on pack count size or age it seals the segment so it accepts no new packs then combines its packs into fewer larger ones. While compaction happens the next segment for the shard can begin capturing its input packs. Before anything is published the node checks that the new packs contain exactly the same objects as the inputs. It then uploads the new packs and adds them to the manifest. A second transaction removes the inputs from the manifest and cleanup deletes them later. This process runs independently for many shards at once. Each pack's hash maps to a shard so adding shards and nodes adds compaction throughput. A compacted pack still under the size limit goes back into a shard by its own hash and merges again so packs grow in tiers until they reach the limit. The net result is an effectively flat pack count while pushes climb.
Garbage collection follows the same pattern
Garbage collection removes objects nothing references anymore such as those left behind by deleted branches and force-pushes. It works very similarly to compaction by using dedicated workers to handle the compute-heavy portion. It also has a few special behaviors for safely removing data. The team says those behaviors are worthy of their own discussion. Using these approaches they have consistently demonstrated a flat latency curve as writes climb and have other planned optimizations to make compaction and garbage collection more performant.
What the architecture enables
The two starting principles let each part scale on its own. Reads and writes scale by adding virtual replicas. Ref-CAS orders each reference independently instead of the whole repository. Maintenance scales by adding compaction nodes. The goal is for every repository from a side project to the busiest monorepo to run on the same architecture with no special handling for the busy ones. Repositories d
The sources this article was written from
- "GitHub Blog
https://github.blog/engineering/architecture-optimization/inside-githubs-new-git-storage-architecture/"