Everyone expects the story about AI agents and Git to be about merge conflicts. The more interesting story is about the write rate. A repository that used to see a burst of a few dozen pushes per second now has to survive thousands of agents pushing at once, each one triggering CI, deploys and other agents to read what it just wrote.
GitHub published its answer on November 5. The headline numbers are 5,000 concurrent agents and 7,200 pushes per second against a single repository, in internal tests. The part worth your time is not the number. It is the sentence the design rests on: "Only reference updates need agreement."
That sentence is the thesis of this issue. When a write path is slow, the usual instinct is to buy a faster consensus system. GitHub did something more useful: it shrank what has to be agreed on until consensus stopped being the bottleneck. You can apply the same move to your own queue, your own event store, your own anything.
Why the old shape breaks
According to GitHub's engineering post, the busiest repositories today see at most dozens of writes per second, in short bursts. They expect sustained agent-driven rates within about a year. The reads are worse than the writes, because each push fans out into reads from CI, deployment systems and more agents. One repository's daily requests grew roughly 4x between March and May 2026, from an average of 44 million to 181 million a day.
The project, called Rubicon, started in May and had to ship while the platform kept running. GitHub's stated target was at least two orders of magnitude more scale for a single repository.
Notice what kind of problem that is. It is not "make Git faster." It is "stop making unrelated writers wait for each other." A push to a feature branch and a push to another feature branch have nothing to say to one another, yet a design with one writer per repository forces them into the same line.
Split the push in two
Git already gives you the cut line. In Pro Git's words, Git is a content-addressable filesystem: you insert content, you get back a key derived from that content, and the same bytes always produce the same key. A changed file becomes a new object. Nothing gets edited in place.
That property is a gift to anyone designing for concurrency. Two writers storing the same object are not in conflict, they are agreeing by construction. Two writers storing different objects never touch the same key. Objects need no vote.
References are the opposite. A branch name is a mutable pointer, and two pushes to main really do disagree about what main should be. That is the one place a decision has to be made. Git itself exposes this as a compare-and-swap. The git update-ref documentation says it "stores the <new-oid> in the <ref>, possibly dereferencing the symbolic refs, after verifying that the current value of the <ref> matches <old-oid>."
GitHub's architecture is that sentence scaled out. Objects and packs go to Azure Blob Storage, written once to distinct keys. A dedicated service called Ref-CAS, a replicated log, holds only the references and the manifest of which packs make up the repo. In GitHub's words, "Ref-CAS never holds or validates object data. It only stores pointers to it."
The write path follows from that split. A replica indexes the incoming pack, uploads it to blob storage, then commits a single Ref-CAS transaction that adds the pack to the manifest and moves the refs. The ordering is the whole safety argument: "A reference only ever points at objects that are already durable." If the upload succeeds and the ref update loses, you have an orphan pack that compaction will clean up. If the ref update succeeds, the data is already there. There is no window where a ref points at nothing.
Per-reference locking is where the scale comes from
The second move is smaller and does more work. A Ref-CAS transaction locks only the references it touches. Each update commits by quorum, a majority of the log's replicas, and each commit gets a log sequence number. Pushes to different branches do not contend and replicate in parallel. When two pushes target the same reference, "only one will append to the log."
I wanted to see how much that choice is worth on its own, so I wrote a toy. It has a write-once object store keyed by hash, and a ref table with a compare-and-swap. Each CAS sleeps 0.5 ms inside its lock to stand in for one quorum round trip. 64 writer threads each push 20 commits. The only thing that changes between runs is the lock scope and whether writers share a branch.
class Refs:
def cas(self, name, old, new, work=0.0005):
lk = self.g if self.global_lock else self._lock(name)
with lk:
time.sleep(work) # one quorum round trip
if self.refs.get(name) != old: return False
self.refs[name] = new; return True
I ran it locally on Python 3. The results:
one global lock, 64 branches 1582 pushes/s retries=0
per-ref lock, 64 branches 30169 pushes/s retries=0
per-ref lock, 64 writers on ONE ref 49 pushes/s retries=40228
Read these as a shape, not a benchmark. It is a thread-based toy with a sleep standing in for the network, and the absolute figures will move with your machine. But the ratios are the point. Going from one global lock to per-ref locks was roughly a 19x improvement with the same code and the same writers. And the third line is the cost GitHub is quietly betting against: when everyone fights over one reference, throughput collapses and retries explode, 40,228 of them for 1,280 successful pushes.
What GitHub did not build
The post is explicit about two designs that lost, and they are instructive because both are what most of us would try first.
A single-blob write-ahead log was correct and cheap to read, but writes were capped at the mid-hundreds per second, because each one needed a conditional write and a round trip to a single blob. Segmenting the ref data into several blobs raised the write ceiling but made every read check every segment. You traded write latency for read latency and ended up roughly where you started.
Ref-CAS as its own replicated log sidesteps both. Its throughput is reported as tens of thousands of operations per second for reference state alone, because it holds almost nothing: pointers, not objects.
Reads get the same treatment. A replica sends its known version to Ref-CAS. If it is current, the reply carries no refs and the whole check is a single comparison. If it is behind, it receives the current refs and pack pointers and pulls what it needs. Because each replica's local disk is "a cache that can be rebuilt at any time," losing one costs you warm-up time and nothing else.
The yes, but
The honest objection is that this is a vendor describing its own system. The 5,000 agents and 7,200 pushes per second are internal test results. The post does not disclose hardware, cluster sizes or test durations, and its "flat latency curve as writes climb" for compaction comes with no latency figures. The feature is in limited private preview, with broader rollout "early next year." Several pieces that would matter to you, such as partial replicas, global replicas with bounded staleness, and the details of garbage collection, are listed as planned or deferred.
There is a second objection, and it is a real one. My toy's third line is the awkward truth: the design makes branches independent, but it does nothing for the case where thousands of agents all push to the same branch. Per-reference locking cannot help when everyone wants the same reference. GitHub lists an atomic commit API and clone-free work as still in progress, and I suspect the next hard problem is not storage at all but how agents are told to organize their branches.
So the right reading is narrower than the headline. The design removes the storage layer as the reason a repository cannot absorb agent traffic. It does not remove contention that your workflow creates.
What to do on Monday
Take your busiest write path and ask one question: what is the smallest thing in it that genuinely requires agreement? In most systems the answer is a counter, a pointer, a status field, a single row. Everything else, the payloads, the blobs, the documents, can be written once under a content-derived key and left alone.
Then check your lock scope. If unrelated writers share a lock because it was convenient, my toy suggests you may be paying an order of magnitude for convenience. And if you hand agents a repository, give each one its own branch. The architecture can run thousands of those in parallel. It cannot make them agree about main.
One more check worth doing is the retry path. A compare-and-swap that fails is information, not an error: it means someone else moved the pointer first. If your clients respond by retrying instantly in a tight loop, you rebuild the third line of my results on purpose. Back off, re-read the current value, and rebase the change. The cheapest consensus protocol is the one your callers rarely have to use.

