<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>git — jd:/dev/blog</title><description>Posts tagged &quot;git&quot; on jd:/dev/blog.</description><link>https://julien.danjou.info/</link><item><title>Merge Queues Were Built for Humans. Agents Don&apos;t Wait.</title><link>https://julien.danjou.info/blog/merge-queues-built-for-humans/</link><guid isPermaLink="true">https://julien.danjou.info/blog/merge-queues-built-for-humans/</guid><description>Mitchell Hashimoto says merge queues fall apart under AI agents. I run a merge-queue company, and he&apos;s half right. The queue isn&apos;t the thing that breaks.</description><pubDate>Tue, 30 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Mitchell Hashimoto thinks merge queues stop working once you point a swarm of AI agents at your repository. I sell merge queues for a living. He&apos;s half right, and the dishonest move would be to pretend he isn&apos;t.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://julien.danjou.info/images/blog/merge-queues-built-for-humans.webp&quot; alt=&quot;Thousands of glowing parallel git branches racing down a dark background and converging into a single bright trunk, the contention of many changes funneling onto one main branch.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;He said it on the &lt;a href=&quot;https://youtu.be/WjckELpzLOU&quot;&gt;Pragmatic Engineer podcast&lt;/a&gt;, in a stretch about &lt;a href=&quot;https://youtu.be/WjckELpzLOU?t=5549&quot;&gt;Git and monorepos&lt;/a&gt;. The setup is a line I&apos;ve been repeating for years: hitting the merge button is the easiest step. Everything expensive happens around the merge, not at it. Getting the code reviewed, keeping main coherent, maintaining forever what you just shipped. Undergraduates can hit the button, as he puts it. The rest is the job.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://julien.danjou.info/images/blog/merge-queues-built-for-humans-hashimoto.jpg&quot; alt=&quot;Pragmatic Engineer podcast title card: &apos;Mitchell Hashimoto&apos;s new way of writing code&apos;, creator of Ghostty, founder and former CEO of HashiCorp.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Then he gets to the queue:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You constantly rebase. Merge queues solves that to a certain extent. I think merge queues works for humans at a certain scale, but merge queues could get quite deep. But then if you sort of 10x that, conservatively, I think 10x that, and then if you buy into hype cycles and you 100 or 1,000x that, I think it gets completely untenable.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;(That&apos;s the transcript, grammar and all.)&lt;/p&gt;
&lt;p&gt;He&apos;s right about the naive version. A merge queue that exists to serialize rebases (take one PR, rebase it on main, run CI, merge, repeat) was built around human throughput. Humans open a few pull requests a day. The queue could be deep and still drain by lunch. Multiply the inflow by ten, then by a hundred, and a queue that only knows how to go one at a time becomes the exact bottleneck it was supposed to remove.&lt;/p&gt;
&lt;p&gt;So yes. The human-scale queue strains under agent churn. Grant it and move on, because the interesting part is what you conclude from there.&lt;/p&gt;
&lt;h2&gt;What actually breaks&lt;/h2&gt;
&lt;p&gt;Hashimoto lists &quot;a confluence of problems&quot;: the merge queue, disk space, and branching/review. I&apos;d pull them apart. Disk space is real (Git clones the world) and it&apos;s a separate fight. The one I care about is the queue, and the thing that breaks there isn&apos;t the queue. It&apos;s the loop the queue sits inside.&lt;/p&gt;
&lt;p&gt;He names the failure mode exactly:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Every time you pull, you can&apos;t push, because every time you pull there&apos;s another chain. Every time you push it&apos;s rejected.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The host adds the obvious: there&apos;s a lot of parallel work happening at once.&lt;/p&gt;
&lt;p&gt;That&apos;s not a queue failing. That&apos;s contention. Between the moment you decide to integrate a change and the moment main accepts it, the tree moved underneath you. With humans the window was minutes and the traffic was light, so a serial queue could absorb it. With agents the window is unchanged but the traffic isn&apos;t, and the one place every change has to pass through, main, is saturated. (The 100x and 1,000x numbers are his hype-cycle hypotheticals, not measurements. The direction is the point.)&lt;/p&gt;
&lt;p&gt;People look at that and conclude the chokepoint is the problem, so rip it out. I&apos;d argue the opposite. Serialization is a throughput constraint, not a law of physics, and the chokepoint is the only place left where you still get to decide what &quot;main&quot; means under that load. You don&apos;t beat contention by deleting your one point of coordination. You beat it by making that point fast, cheap, and parallel. What actually broke is everything that assumed the loop around it was cheap: one PR, one CI run, one human looking at it, merge, move on. &lt;a href=&quot;https://julien.danjou.info/blog/your-ci-pipeline-wasnt-built-for-this/&quot;&gt;Your CI pipeline&lt;/a&gt; was never sized for that.&lt;/p&gt;
&lt;h2&gt;A queue that goes one at a time is the toy version&lt;/h2&gt;
&lt;p&gt;Talking about a stealth company he advises, Hashimoto names the real shape:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The amount of churn that these agents is causing is so much greater than humans. And it&apos;s not an AI review problem. It&apos;s really just like a release problem, like managing the merge queues, humans getting access to the right set of data in the repository.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A release problem. That&apos;s exactly it, and release engineering already has answers for &quot;serial doesn&apos;t scale.&quot; We&apos;ve just never had to point them at ordinary feature work, because ordinary feature work never moved this fast.&lt;/p&gt;
&lt;p&gt;A queue that takes PRs one at a time and rebases each on the last is the toy. The version that survives agent load does what every high-throughput build system already does:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;It speculates.&lt;/strong&gt; Don&apos;t wait for #1 to land before testing #2. Build the optimistic chain and test #1+#2+#3 in parallel as if they&apos;ll all pass, falling back only when one doesn&apos;t. Zuul has done this for OpenStack for over a decade; GitHub&apos;s own merge queue and Bors do a version of it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It batches.&lt;/strong&gt; Merge a run of green PRs as one unit and run CI once for the batch instead of once per PR.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It bisects on failure.&lt;/strong&gt; When a batch goes red you don&apos;t drop all of it. You find the offender and let the rest through. Uber&apos;s SubmitQueue and Google&apos;s TAP are built around exactly this.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It treats CI cost and latency as the real constraint.&lt;/strong&gt; Under agent load the binding limit isn&apos;t &quot;can the queue order things.&quot; It&apos;s whether you can afford to run the suite hundreds of times a day, and how fast each run comes back. Speculation and batching pull against that directly: optimistic chains multiply CI spend, and a failure high in the chain throws away everything below it. Flaky tests, which explode under agent churn, wreck the bisection you were counting on. This is the unglamorous core of it, and it has no clever Git answer.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&apos;s the honest tension, and the thing Hashimoto&apos;s stealth company is really selling against. These techniques are known. Running them without Google&apos;s build infrastructure and Google&apos;s CI budget is not. That gap is the actual frontier, and it&apos;s why the problem lands on tooling rather than on a team of five wiring up speculative pipelines by hand. (Disclosure, if it wasn&apos;t obvious: I run Mergify, which builds this kind of thing. Discount me accordingly.)&lt;/p&gt;
&lt;h2&gt;What the queue does not fix&lt;/h2&gt;
&lt;p&gt;I&apos;m not going to pretend the queue solves all of it. Green is not coherent. Ten agent PRs can each pass CI alone, pass again as a batch, and still be a mess together: three flavors of the same helper, two designs pulling in opposite directions, a thousand lines no human read. A merge queue keeps main buildable. It does not keep main &lt;em&gt;good&lt;/em&gt;. That half of Hashimoto&apos;s worry survives untouched, and it isn&apos;t a release problem, it&apos;s a &lt;a href=&quot;https://julien.danjou.info/blog/the-code-review-bottleneck-is-you/&quot;&gt;review problem&lt;/a&gt;, and review is exactly the thing agents have made scarcest.&lt;/p&gt;
&lt;p&gt;There&apos;s also a future where I lose this bet outright. If someone ships an optimistic, eventually-coherent model of main with no single serialization point to defend, the queue as we know it goes with it. I don&apos;t think that&apos;s where this lands. I think &lt;a href=&quot;https://julien.danjou.info/blog/github-wont-work-for-ai-agents/&quot;&gt;the forge itself&lt;/a&gt; bends first.&lt;/p&gt;
&lt;h2&gt;The most interesting release problem in fifteen years&lt;/h2&gt;
&lt;p&gt;The line that stuck with me wasn&apos;t about queues at all. Asked whether Git survives the agent era, Hashimoto said this is the first time in twelve to fifteen years anyone asks the question without laughing.&lt;/p&gt;
&lt;p&gt;That&apos;s the signal. The primitives we treated as settled (Git, branches, the pull request, the merge queue) are load-bearing again, and some of them will bend. The merge queue is the one I&apos;d bet on. Not because I sell it, but because the job it does, keeping a shared main coherent while many actors race to change it, gets harder under agents, not easier. You answer more contention by making coordination faster, not by deleting it.&lt;/p&gt;
&lt;p&gt;Hitting the merge button is still the easiest step. Agents just turned everything around it into the most interesting problem on the board.&lt;/p&gt;
</content:encoded><category>ai</category><category>git</category><category>engineering</category></item><item><title>Twenty Years of Stacking Commits</title><link>https://julien.danjou.info/blog/twenty-years-of-stacking-commits/</link><guid isPermaLink="true">https://julien.danjou.info/blog/twenty-years-of-stacking-commits/</guid><description>Every code review tool I&apos;ve used in twenty years has tried to answer the same question. AI just made the answer unavoidable.</description><pubDate>Tue, 28 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In twenty years, I&apos;ve used four different code review tools. Each was supposed to fix the previous one. None of them changed the fundamental question they were trying to answer: what is the right unit to review?&lt;/p&gt;
&lt;p&gt;The answer hasn&apos;t moved. The world around it has.&lt;/p&gt;
&lt;p&gt;I started on &lt;code&gt;git format-patch&lt;/code&gt; and &lt;code&gt;git send-email&lt;/code&gt; in 2006, threading patches into mailing lists the way the &lt;a href=&quot;https://www.kernel.org/&quot;&gt;Linux kernel&lt;/a&gt; did. I moved to &lt;a href=&quot;https://www.gerritcodereview.com/&quot;&gt;Gerrit&lt;/a&gt; at &lt;a href=&quot;https://www.openstack.org/&quot;&gt;OpenStack&lt;/a&gt; when it arrived. I tried to bring its workflow to GitHub myself, and failed. I watched GitHub turn every branch into a wall. And now I&apos;m watching agents push code faster than humans can read it. Each era taught me the same thing: the unit of review is the commit. We just spent a decade pretending otherwise.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://julien.danjou.info/images/blog/twenty-years-of-stacking-commits-format-patch.png&quot; alt=&quot;A 2010 patch email titled &apos;[PATCH 2/5] Update test suite for xcb &amp;gt;= 1.6&apos; on the XCB mailing list, signed by Julien Danjou, with a unified diff inline.&quot; /&gt;
&lt;em&gt;[PATCH 2/5] from a patch series I sent to the XCB mailing list in 2010. Each patch was its own review unit. Stacking has been here the whole time.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Gerrit got it right&lt;/h2&gt;
&lt;p&gt;OpenStack ran on Gerrit. Google had built it in 2008 for Android, the brainchild of Shawn Pearce as a fork of Guido van Rossum&apos;s &lt;a href=&quot;https://en.wikipedia.org/wiki/Rietveld_(software)&quot;&gt;Rietveld&lt;/a&gt;. Projects looking for serious code review followed.&lt;/p&gt;
&lt;p&gt;Every commit you pushed got a Change-Id, a SHA-like footer Gerrit used to track that commit across rebases. One Change-Id was one review. Push six commits, get six review threads. Amend one and the others stayed untouched. Reviewers commented on the commit they cared about and ignored the rest.&lt;/p&gt;
&lt;p&gt;The UX was hostile. You pushed code with &lt;code&gt;git push HEAD:refs/for/master&lt;/code&gt;, a syntax that felt designed to keep newcomers out. Discussions happened in a web UI that loaded slowly even on fiber, or over a JSON-over-SSH API for the brave. You clicked through three screens to leave a comment. Senior contributors had Vim macros to make it bearable. Newcomers gave up.&lt;/p&gt;
&lt;p&gt;But the model underneath was right. Each commit was a thought, and each thought got reviewed on its own terms. When you submitted a five-commit feature, reviewers could approve the refactoring commits while still arguing about the new abstraction in the last one. The work moved forward in pieces. Nobody waited for everything to be perfect before anything could land.&lt;/p&gt;
&lt;p&gt;Compare this to what most teams do now. A reviewer opens a 1,500-line PR, scrolls for a while, picks a few things to comment on, and either approves or sends it back as a single block. There&apos;s no granularity because the unit doesn&apos;t allow it.&lt;/p&gt;
&lt;p&gt;Gerrit knew this in 2008. It just didn&apos;t know how to make people enjoy it.&lt;/p&gt;
&lt;h2&gt;git-review proved the UX was the wall&lt;/h2&gt;
&lt;p&gt;OpenStack built &lt;code&gt;git-review&lt;/code&gt; to wrap Gerrit&apos;s six-step push ritual in one command. &lt;code&gt;git review&lt;/code&gt; did the right things in the right order. Fetch the latest target branch, rebase your commits on top, validate Change-Ids were present, push to the magic ref, print the URLs of the resulting reviews. That was it.&lt;/p&gt;
&lt;p&gt;It got adopted across OpenStack within months. Within a year it was the default step in every contributor tutorial. Not because the tool was clever (it wasn&apos;t), but because the friction it removed was the difference between people contributing and people giving up after their first push.&lt;/p&gt;
&lt;p&gt;That was the lesson I carried out of OpenStack. A tool can have the right semantics and still lose if the UX is hostile. UX isn&apos;t decoration. It&apos;s part of correctness. The model that wins is the one a tired developer at 6pm can use without thinking. Gerrit&apos;s model was right, but its surface area pushed everyone toward GitHub the moment GitHub got good enough.&lt;/p&gt;
&lt;h2&gt;GitHub turned every branch into a wall&lt;/h2&gt;
&lt;p&gt;GitHub got good enough around 2014. Faster UI, easier setup, and a model anyone could understand: one branch, one pull request. That model worked for solo contributions and small features. It collapsed the moment you tried to ship anything in pieces.&lt;/p&gt;
&lt;p&gt;The problem is structural. GitHub&apos;s PR is anchored to a branch. If you want five reviewable units, you need five branches. Each one rebased on the previous. Each one&apos;s PR retargeted when the one below it lands. If the bottom of the stack changes, you rebase the world. Nobody does this. People give up and ship one giant PR instead, or they ship one PR per day for a week and pretend it&apos;s fine.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://julien.danjou.info/blog/rant-about-github-pull-request-workflow-implementation/&quot;&gt;I ranted about exactly this in 2013&lt;/a&gt;, back when most of the industry was busy convincing itself GitHub had solved code review. The argument hasn&apos;t aged. GitHub&apos;s PR model fights you the moment you try to ship more than one thought at a time.&lt;/p&gt;
&lt;p&gt;I tried to fix it myself in 2016 with &lt;a href=&quot;https://pypi.org/project/git-pull-request/&quot;&gt;&lt;code&gt;git-pull-request&lt;/code&gt;&lt;/a&gt;, a small Python CLI that turned commits on a single branch into chained GitHub PRs. It worked for me. It didn&apos;t go anywhere. A one-person CLI can&apos;t paper over a structural mismatch. The branching, the chaining, the dependency tracking, the smart updates when you amend a commit mid-stack, all of that has to live somewhere both halves of the workflow agree on. Client-side scripts work on your machine and break on someone else&apos;s.&lt;/p&gt;
&lt;p&gt;Years later we built &lt;a href=&quot;https://mergify.com/product/stacks/&quot;&gt;Mergify Stack&lt;/a&gt; because the problem hadn&apos;t gone away and the team was bigger than just me. One local branch, every commit becomes its own PR, the tool handles the chaining so amending mid-stack only updates the affected reviews.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://julien.danjou.info/images/blog/twenty-years-of-stacking-commits-mergify-stack.png&quot; alt=&quot;A Mergify Stack comment in a GitHub pull request, showing a 9-row table where each row is a chained PR in the stack, with PR numbers and titles for a Rust port project.&quot; /&gt;
&lt;em&gt;A nine-PR stack from our ongoing Rust port, posted as a comment on every PR in the chain. Each row is one commit, one PR, one review unit. The arrow points at the PR you&apos;re currently looking at.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;We weren&apos;t the only ones who noticed the gap. &lt;a href=&quot;https://graphite.dev&quot;&gt;Graphite&lt;/a&gt; bet a whole company on it, building an IDE around stacked diffs that effectively replaces GitHub&apos;s review surface. Meta open-sourced &lt;a href=&quot;https://sapling-scm.com/&quot;&gt;Sapling&lt;/a&gt;&apos;s &lt;code&gt;ghstack&lt;/code&gt;. Google open-sourced &lt;a href=&quot;https://docs.jj-vcs.dev/latest/&quot;&gt;&lt;code&gt;jj&lt;/code&gt;&lt;/a&gt;, a Git-compatible VCS where stacks are first-class. There&apos;s &lt;code&gt;spr&lt;/code&gt;, &lt;code&gt;stack-pr&lt;/code&gt;, half a dozen others. Different shapes, same admission: GitHub&apos;s PR model doesn&apos;t fit how serious teams ship.&lt;/p&gt;
&lt;p&gt;My day-to-day hasn&apos;t really changed since I was patching Xorg, or &lt;a href=&quot;https://awesomewm.org&quot;&gt;awesome&lt;/a&gt;, or filing bugs against &lt;a href=&quot;https://www.debian.org&quot;&gt;Debian&lt;/a&gt; packages I maintained. One branch. Commit small. Interactive rebase to fix something three commits down. &lt;code&gt;mergify stack push&lt;/code&gt; to send the whole stack up. The only difference is GitHub showing seven separate review threads instead of a mailing list showing six.&lt;/p&gt;
&lt;p&gt;This was the missing layer. Stack semantics, GitHub surface. For a while, that was enough.&lt;/p&gt;
&lt;h2&gt;And then the agents arrived&lt;/h2&gt;
&lt;p&gt;Until last year, the bottleneck on a software team was the human writing the code. A senior engineer could ship maybe two or three thoughtful PRs in a day. Junior engineers shipped less. Reviewers mostly kept up. The whole pipeline was sized for human output.&lt;/p&gt;
&lt;p&gt;That bottleneck is gone. With Claude Code in front of me, I can produce in an afternoon what used to take a week. Not because I&apos;m typing faster. Because I&apos;m not typing at all. I&apos;m planning, briefing, reviewing, redirecting. The agents do the typing. They don&apos;t get tired.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://julien.danjou.info/blog/the-code-review-bottleneck-is-you/&quot;&gt;I&apos;ve written about how this shifts the bottleneck downstream&lt;/a&gt;. The reviewer is now the choke point, and the reviewer&apos;s tools haven&apos;t kept up. They&apos;re still being asked to read 1,500-line PRs the way they did when those PRs took someone a week to write. They skim. They miss things. They approve and hope.&lt;/p&gt;
&lt;p&gt;Stacks don&apos;t shrink the work. They make partial progress possible. A reviewer who can&apos;t approve all of it can still approve half of it. Two reviewers can split the stack and work in parallel. A bug found in PR five doesn&apos;t roll back PR one. The total volume is unchanged. The blast radius and the cognitive load per review are not.&lt;/p&gt;
&lt;p&gt;A couple of weeks ago I shipped an API surface refactor across our backend and frontend. I had a plan with seven steps: add a new &lt;code&gt;/merge-queue/branches&lt;/code&gt; endpoint, remove a deprecated old one, migrate the web app&apos;s branch selector, drop a dead related surface, add a sister &lt;code&gt;/stats/branches&lt;/code&gt; endpoint, migrate the stats filter, deprecate the old union endpoint. I briefed the agents. I reviewed the work. Six seconds after I ran &lt;code&gt;mergify stack push&lt;/code&gt;, GitHub had seven open pull requests linked in dependency order.&lt;/p&gt;
&lt;p&gt;Combined, those PRs touched roughly seven thousand lines across seventy-five file changes. As a single PR, no human would have read it carefully. As a stack, each one was a single logical move. The first landed two days later, when the lowest-risk piece (deleting the deprecated endpoint) was approved. One contested API addition cycled through a couple of rounds of dismissed reviews before landing. The last merged nine days after the push. Five different reviewers touched the stack across that window, picking up whichever links they had context for. Nobody had to load the whole refactor into their head.&lt;/p&gt;
&lt;p&gt;Try that as one PR and tell me what happens. Seven thousand lines mixing four backend moves with two frontend migrations. A reviewer who needs to understand all of it before approving any of it. Anything wrong anywhere triggers a full revert. The work either ships as a brick or it doesn&apos;t ship at all.&lt;/p&gt;
&lt;p&gt;Stacks aren&apos;t free and they aren&apos;t universal. Exploratory work that changes shape mid-stream wants a single branch, not seven. Tightly coupled changes where commit five only makes sense once you&apos;ve read commit four don&apos;t decompose neatly. Bug fixes are usually one PR. The skill is knowing which kind of work you&apos;re doing before you start. If your team can&apos;t write atomic commits or doesn&apos;t trust interactive rebase, stacks make things worse, not better. The model demands discipline. The bet is that AI removes enough of the writing tax that the discipline becomes affordable.&lt;/p&gt;
&lt;p&gt;Gerrit knew this in 2008. The unit of review is the commit. The PR was always a workaround for tooling that couldn&apos;t track commits properly. It took agents writing code faster than humans can read it for the rest of the industry to admit it.&lt;/p&gt;
&lt;p&gt;In January, GitHub stopped denying it. They &lt;a href=&quot;https://github.com/github/roadmap/issues/1218&quot;&gt;announced native Stacked PRs&lt;/a&gt; in private preview, with the &lt;a href=&quot;https://github.github.com/gh-stack/&quot;&gt;&lt;code&gt;gh stack&lt;/code&gt;&lt;/a&gt; CLI and an AI agent integration shipped as a skill.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://julien.danjou.info/images/blog/twenty-years-of-stacking-commits-gh-stack.webp&quot; alt=&quot;GitHub&apos;s stack navigator UI: a vertical sidebar listing the PRs in a stack with their statuses, attached to a pull request page.&quot; /&gt;
&lt;em&gt;GitHub&apos;s own stack-navigator preview from the gh-stack landing page. The PR map on the right is what reviewers have been asking for since 2014.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The PR model GitHub spent a decade enforcing as the right unit of review is being quietly retrofitted to admit it wasn&apos;t. They couldn&apos;t say so until everyone else had already built the layer they should have shipped in 2014.&lt;/p&gt;
&lt;p&gt;The tools change every five years. Gerrit. git-review. Mergify Stack. Graphite. GitHub Stacked PRs. Whatever ships next. Each generation looks like a step forward and most of them are.&lt;/p&gt;
&lt;p&gt;The unit of review hasn&apos;t moved in twenty years. It&apos;s the commit. It always was. We just had to wait for the rest of the pipeline to break before we noticed.&lt;/p&gt;
</content:encoded><category>engineering</category><category>ai</category><category>git</category></item><item><title>How Entire Works Under the Hood</title><link>https://julien.danjou.info/blog/how-entire-works-under-the-hood/</link><guid isPermaLink="true">https://julien.danjou.info/blog/how-entire-works-under-the-hood/</guid><description>I dug into Entire&apos;s open source Checkpoints CLI. It&apos;s a clever abuse of git internals — shadow branches, orphan metadata, and a session state machine. Here&apos;s how it works.</description><pubDate>Thu, 12 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In &lt;a href=&quot;https://julien.danjou.info/blog/github-wont-work-for-ai-agents/&quot;&gt;part 1&lt;/a&gt;, I covered why Entire raised $60M and what problem they&apos;re solving. Now let&apos;s look at the actual code.&lt;/p&gt;
&lt;p&gt;I pointed Claude Code at &lt;a href=&quot;https://github.com/entireio/cli&quot;&gt;Entire&apos;s open source CLI&lt;/a&gt; and asked it to explain how things work. The architecture is more interesting than I expected — they&apos;ve essentially built a session-aware metadata layer on top of git using nothing but git&apos;s own primitives.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://julien.danjou.info/images/blog/entire/repo.png&quot; alt=&quot;The Entire CLI repository on GitHub&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;The Big Picture&lt;/h2&gt;
&lt;p&gt;Entire hooks into two things: your AI agent (Claude Code, Gemini CLI) and git itself. The agent hooks capture what&apos;s happening during a session. The git hooks capture what the developer commits.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Agent hooks (Claude Code)         Git hooks
  SessionStart                     prepare-commit-msg
  UserPromptSubmit                 post-commit
  Stop                             pre-push
  PreToolUse / PostToolUse
         │                              │
         └──────────┬───────────────────┘
                    │
            ┌───────▼────────┐
            │   Strategy     │
            │                │
            │ SaveChanges()  │
            │ Rewind()       │
            │ Condense()     │
            └───────┬────────┘
                    │
         ┌──────────┴──────────┐
         │                     │
    Shadow branches      Metadata branch
    (local, temp)        (shared, permanent)
    entire/&amp;lt;hash&amp;gt;        entire/checkpoints/v1
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;How Agent Hooks Get Installed&lt;/h2&gt;
&lt;p&gt;Running &lt;code&gt;entire enable&lt;/code&gt; writes hook entries into &lt;code&gt;.claude/settings.json&lt;/code&gt;. Seven hooks, covering the full session lifecycle:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SessionStart/SessionEnd&lt;/strong&gt; — track session boundaries&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;UserPromptSubmit&lt;/strong&gt; — fires before the agent starts working (captures human edits)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stop&lt;/strong&gt; — fires after the agent finishes a turn (triggers checkpoint save)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PreToolUse/PostToolUse[Task]&lt;/strong&gt; — track subagent spawning&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PostToolUse[TodoWrite]&lt;/strong&gt; — capture task state&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each hook is just a shell command: &lt;code&gt;entire hooks claude-code stop&lt;/code&gt;. The CLI parses the agent&apos;s transcript to extract everything it needs.&lt;/p&gt;
&lt;h2&gt;The Transcript Is the Source of Truth&lt;/h2&gt;
&lt;p&gt;This is the key insight. When the Stop hook fires, Claude Code passes two things via stdin: a &lt;code&gt;session_id&lt;/code&gt; and a &lt;code&gt;transcript_path&lt;/code&gt;. That transcript — the JSONL file where Claude logs every message, tool call, and response — is the single source of truth.&lt;/p&gt;
&lt;p&gt;The CLI mines it for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Modified files&lt;/strong&gt; — scans for &lt;code&gt;tool_use&lt;/code&gt; blocks where the tool is &lt;code&gt;Write&lt;/code&gt;, &lt;code&gt;Edit&lt;/code&gt;, etc., and extracts the &lt;code&gt;file_path&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;User prompts&lt;/strong&gt; — finds &lt;code&gt;type: &quot;user&quot;&lt;/code&gt; entries&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Token usage&lt;/strong&gt; — sums &lt;code&gt;input_tokens&lt;/code&gt;, &lt;code&gt;output_tokens&lt;/code&gt; from response metadata&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Summary&lt;/strong&gt; — grabs the last assistant message&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;No magic, no APIs. It just reads the same JSONL file that Claude Code writes to disk.&lt;/p&gt;
&lt;h2&gt;Shadow Branches: Snapshots Without Commits&lt;/h2&gt;
&lt;p&gt;Here&apos;s where it gets clever. When the agent finishes a turn, Entire needs to save a snapshot of the working tree. But it can&apos;t commit to your branch — that would mess up your history.&lt;/p&gt;
&lt;p&gt;So it creates &lt;strong&gt;shadow branches&lt;/strong&gt;: refs like &lt;code&gt;entire/2b4c177-a5e3f2&lt;/code&gt; that live in your local repo but never touch your working branch.&lt;/p&gt;
&lt;p&gt;The name encodes two things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;2b4c177&lt;/code&gt; — first 7 chars of HEAD when the session started&lt;/li&gt;
&lt;li&gt;&lt;code&gt;a5e3f2&lt;/code&gt; — hash of the worktree ID (to support &lt;code&gt;git worktree&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The snapshot is built entirely in memory using go-git&apos;s plumbing APIs:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Take HEAD&apos;s tree (the full repo structure)&lt;/li&gt;
&lt;li&gt;Apply the agent&apos;s changes (add/remove/modify blobs)&lt;/li&gt;
&lt;li&gt;Attach the metadata directory (&lt;code&gt;.entire/metadata/&amp;lt;session-id&amp;gt;/&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Create a commit on the shadow branch&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;No checkout, no stash, no visible side effects. The user and agent don&apos;t even know it happened.&lt;/p&gt;
&lt;p&gt;Deduplication is automatic: if the tree hash matches the previous checkpoint, it skips the commit. Git&apos;s content-addressable storage means identical files share blobs across checkpoints.&lt;/p&gt;
&lt;h2&gt;The Condensation Model&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://julien.danjou.info/images/blog/entire/branch.png&quot; alt=&quot;The entire/checkpoints/v1 orphan branch stores all metadata&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Shadow branches are local scratch space. The real metadata lives on &lt;code&gt;entire/checkpoints/v1&lt;/code&gt; — an orphan branch (no common ancestor with your code) that&apos;s pushed alongside your regular branches.&lt;/p&gt;
&lt;p&gt;The flow:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Agent works → checkpoints saved on shadow branch (local)&lt;/li&gt;
&lt;li&gt;You commit → &lt;code&gt;post-commit&lt;/code&gt; hook fires&lt;/li&gt;
&lt;li&gt;&lt;code&gt;prepare-commit-msg&lt;/code&gt; adds a trailer: &lt;code&gt;Entire-Checkpoint: a3b2c4d5e6f7&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Shadow branch data gets &lt;strong&gt;condensed&lt;/strong&gt; — copied into the metadata branch&lt;/li&gt;
&lt;li&gt;Shadow branch gets cleaned up&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The checkpoint ID (&lt;code&gt;a3b2c4d5e6f7&lt;/code&gt;) is 6 random bytes, not a git SHA. It&apos;s sharded into a directory path on the metadata branch:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;entire/checkpoints/v1  (orphan branch)
└── a3/b2c4d5e6f7/
    ├── metadata.json          # summary, attribution, token usage
    ├── 0/
    │   ├── full.jsonl         # complete session transcript
    │   ├── prompt.txt         # user prompts
    │   └── context.md         # generated context
    └── 1/                     # additional sessions if any
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That one-line trailer in your commit — &lt;code&gt;Entire-Checkpoint: a3b2c4d5e6f7&lt;/code&gt; — is the bidirectional link. From the commit you find metadata via the sharded path. From the metadata you find the commit by searching for the trailer.&lt;/p&gt;
&lt;h2&gt;Attribution: Who Wrote What?&lt;/h2&gt;
&lt;p&gt;This is the piece that matters for engineering leads. Entire tracks line-level code attribution: what percentage was agent-written vs. human-written.&lt;/p&gt;
&lt;p&gt;The trick is the &lt;strong&gt;UserPromptSubmit&lt;/strong&gt; hook. Every time you type a new prompt — &lt;em&gt;before&lt;/em&gt; the agent starts working — the CLI snapshots the worktree diff against the last checkpoint. This captures exactly what you changed between agent turns.&lt;/p&gt;
&lt;p&gt;By commit time, it has:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Agent lines&lt;/strong&gt;: changes from the last checkpoint&apos;s tree&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Human added&lt;/strong&gt;: lines you added between prompts&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Human modified&lt;/strong&gt;: lines you edited in agent-written code&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Agent percentage&lt;/strong&gt;: the ratio&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The result is stored in &lt;code&gt;initial_attribution&lt;/code&gt; in the metadata:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;agent_lines&quot;: 150,
  &quot;human_added&quot;: 25,
  &quot;human_modified&quot;: 10,
  &quot;agent_percentage&quot;: 85.7
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It even uses a LIFO heuristic for self-modifications — if you add lines then remove lines from the same file, it assumes you&apos;re removing your own first, not penalizing the agent&apos;s contribution.&lt;/p&gt;
&lt;h2&gt;Multi-Developer: Conflict-Free by Design&lt;/h2&gt;
&lt;p&gt;The metadata branch gets pushed during &lt;code&gt;git push&lt;/code&gt; (via the &lt;code&gt;pre-push&lt;/code&gt; hook). Multiple developers push to the same &lt;code&gt;entire/checkpoints/v1&lt;/code&gt; branch.&lt;/p&gt;
&lt;p&gt;This works because checkpoint IDs are random — two developers will essentially never produce the same 12-hex-char ID. Merging is just a tree union: flatten both trees, combine entries, done. No merge conflicts possible.&lt;/p&gt;
&lt;p&gt;If a normal push fails (non-fast-forward), the CLI fetches the remote, merges trees, creates a merge commit, and retries.&lt;/p&gt;
&lt;h2&gt;What&apos;s Missing&lt;/h2&gt;
&lt;p&gt;The architecture is solid engineering, but a few things stood out:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Transcript privacy.&lt;/strong&gt; Session transcripts (full agent conversations) get pushed to a branch anyone with repo access can read. For private repos, maybe fine. For orgs with varying access levels — that&apos;s a problem.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Squash merges break links.&lt;/strong&gt; If a PR with 5 commits (each with &lt;code&gt;Entire-Checkpoint&lt;/code&gt; trailers) gets squash-merged, those trailers disappear. The metadata exists but the bidirectional link from the merged commit is broken.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The metadata branch grows forever.&lt;/strong&gt; Every session from every developer, including abandoned PRs and throwaway experiments, accumulates on &lt;code&gt;entire/checkpoints/v1&lt;/code&gt;. There&apos;s an &lt;code&gt;entire clean&lt;/code&gt; command for local shadow branches, but no retention policy for the permanent metadata. For a large team over months, that&apos;ll bloat.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;No PR linkage.&lt;/strong&gt; The branch name is stored, but there&apos;s no PR number or URL. You can&apos;t easily ask &quot;show me all sessions related to PR #42.&quot;&lt;/p&gt;
&lt;h2&gt;The Smart Parts&lt;/h2&gt;
&lt;p&gt;What I genuinely admire:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Git as a free database.&lt;/strong&gt; Shadow branches store full repo snapshots, but git&apos;s content-addressable storage means only changed blobs cost anything. You get atomic snapshots, deduplication, and transport for free.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In-memory tree building.&lt;/strong&gt; Checkpoints are created through go-git plumbing APIs — no worktree checkout, no stash, nothing visible. Zero disruption to the developer&apos;s flow.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Attribution at prompt boundaries.&lt;/strong&gt; Capturing human edits &lt;em&gt;before&lt;/em&gt; the agent contaminates the worktree is the cleanest measurement point possible.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shadow branch migration.&lt;/strong&gt; If you rebase or pull (HEAD changes), the shadow branch name automatically updates. Your session continues seamlessly. This handles a common workflow that would otherwise silently break.&lt;/p&gt;
&lt;h2&gt;So What?&lt;/h2&gt;
&lt;p&gt;Entire doesn&apos;t solve a burning problem today. Most of us are fine with agent-written code landing in our repos without detailed provenance. But the trajectory is clear: as agents write more code, the audit trail becomes essential.&lt;/p&gt;
&lt;p&gt;The approach of storing session context alongside code in git — rather than in a separate system — is the right architectural bet. Git is already where your code lives, where your CI runs, where your reviews happen. Adding a metadata layer inside git itself (instead of a SaaS dashboard somewhere) means the context travels with the code.&lt;/p&gt;
&lt;p&gt;Whether Entire is the company that turns this into a platform worth $300M is above my pay grade. But the engineering is genuine, the problem is real, and the timing feels right.&lt;/p&gt;
&lt;p&gt;I&apos;ll be watching.&lt;/p&gt;
</content:encoded><category>ai</category><category>git</category><category>developer-experience</category></item><item><title>Agent-Written Code Needs More Than Git</title><link>https://julien.danjou.info/blog/github-wont-work-for-ai-agents/</link><guid isPermaLink="true">https://julien.danjou.info/blog/github-wont-work-for-ai-agents/</guid><description>The former GitHub CEO just raised $60M to rebuild developer tooling for the agentic era. He might be right that git needs a rethink — I&apos;ve been hacking around the same problems.</description><pubDate>Wed, 11 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The former GitHub CEO just raised $60M at a $300M valuation for a seed round. For a CLI tool. Let that sink in.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://julien.danjou.info/images/blog/entire/entire-io.png&quot; alt=&quot;Entire.io — a new developer platform for the agentic era&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Thomas Dohmke left GitHub and launched &lt;a href=&quot;https://entire.io/blog/hello-entire-world&quot;&gt;Entire&lt;/a&gt;, a developer platform built from scratch for the age of AI coding agents. It&apos;s the largest seed round in dev tools history.&lt;/p&gt;
&lt;p&gt;My first reaction was &quot;that&apos;s insane.&quot; My second reaction was &quot;wait, I&apos;ve been solving the same problem with duct tape and hooks.&quot;&lt;/p&gt;
&lt;h2&gt;The Problem Is Real&lt;/h2&gt;
&lt;p&gt;If you&apos;re using AI agents like Claude Code or Gemini CLI daily — and I am — you&apos;ve already felt it. Git was built for humans writing code. It assumes you know what you changed and why. It assumes your commit messages mean something. It assumes the person who wrote the code will remember what they were thinking.&lt;/p&gt;
&lt;p&gt;AI agents break all of that.&lt;/p&gt;
&lt;p&gt;When Claude Code rewrites a module for me, the commit message says what happened, but not &lt;em&gt;why&lt;/em&gt;. There&apos;s no trace of the conversation that led there. No record of the three approaches the agent considered and rejected. No way to know if the prompt was &quot;refactor this for clarity&quot; or &quot;make this 10x faster and I don&apos;t care about readability.&quot;&lt;/p&gt;
&lt;p&gt;The transcript — the actual reasoning behind the code — lives in a terminal session that vanishes when you close the tab.&lt;/p&gt;
&lt;h2&gt;My Duct Tape Solution&lt;/h2&gt;
&lt;p&gt;I ran into this a few weeks ago when I wanted to resume a Claude Code session after a reboot. The session was gone, and I had no idea what context the agent had when it made certain decisions.&lt;/p&gt;
&lt;p&gt;So I did what any engineer would do: I wrote a hook. A simple Claude Code hook that links each commit to its session ID via a git trailer. Nothing fancy — just enough that I can trace a commit back to the conversation that produced it.&lt;/p&gt;
&lt;p&gt;Combined with &lt;a href=&quot;https://github.com/Mergify/mergify-cli&quot;&gt;Mergify&apos;s CLI&lt;/a&gt; for stacking PRs, it made my workflow usable. But it&apos;s duct tape. It doesn&apos;t capture the transcript, doesn&apos;t track attribution, doesn&apos;t handle multi-session work.&lt;/p&gt;
&lt;p&gt;Which is exactly the gap Entire is going after.&lt;/p&gt;
&lt;h2&gt;What Entire Actually Claims to Be&lt;/h2&gt;
&lt;p&gt;Beyond the buzzwords in the press release, Entire is shipping three things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Checkpoints&lt;/strong&gt; — an open source CLI that captures session context (prompts, transcripts, reasoning) alongside every commit, stored in git without polluting your history&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A semantic reasoning layer&lt;/strong&gt; — meant to let multiple AI agents collaborate on the same codebase with shared context&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;An AI-native UI&lt;/strong&gt; — designed for agent-to-human collaboration rather than human-to-human&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;They&apos;re not claiming to have a finished product — and they&apos;re upfront about it. The Checkpoints CLI is the first concrete thing they&apos;ve shipped, and it&apos;s open source. The rest is where the $60M goes. Fair enough — let&apos;s look at what actually exists.&lt;/p&gt;
&lt;h2&gt;Why $60M for This?&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://julien.danjou.info/images/blog/entire/techcrunch.png&quot; alt=&quot;TechCrunch: Former GitHub CEO raises record $60M dev tool seed round&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The bet isn&apos;t that the current CLI is worth $300M. The bet is that the developer tooling stack needs to be rebuilt for a world where most code is written by agents, and the first company to nail the foundation wins.&lt;/p&gt;
&lt;p&gt;Think about it: if 99% of code is agent-written in two years (which is where things are heading), then the code review, debugging, and understanding workflow we have today is fundamentally broken. You can&apos;t review AI-written code the same way you review human-written code. You need the &lt;em&gt;context&lt;/em&gt; — what was the agent trying to do, what constraints did it have, what alternatives did it consider.&lt;/p&gt;
&lt;p&gt;That&apos;s a platform opportunity, and $60M is the price of a credible attempt at it. Whether Entire is the one to build it is a different question — but the problem is real and urgent.&lt;/p&gt;
&lt;h2&gt;My Take&lt;/h2&gt;
&lt;p&gt;Dohmke knows exactly where GitHub&apos;s limits are (he ran it). The investor list — Felicis, Madrona, Olivier Pomel — signals real conviction. And the core insight, that agent context is as important as the code itself, is something I believe in my bones because I&apos;ve been hacking around it myself.&lt;/p&gt;
&lt;p&gt;Their long-term ambition seems to involve moving beyond git. I&apos;m more dubious about that part. Git is unkillable. My bet is that the reality will be hooks and duct tape around git for the next few years — and honestly, that&apos;s probably enough. Git&apos;s data model bends a lot further than people think before it breaks.&lt;/p&gt;
&lt;p&gt;There&apos;s a deeper tension, though. Entire&apos;s model assumes humans are still in the loop — driving agents, reviewing output, caring about attribution. But that&apos;s already not quite how it works. I haven&apos;t written a line of code in months. I describe what I want, the agent writes it, I tell it to fix its mistakes, and it does. I&apos;m not a developer anymore — I&apos;m a director.&lt;/p&gt;
&lt;p&gt;And the trajectory is obvious: agents won&apos;t need directors much longer either. If agents are fully autonomous, who&apos;s the audience for commit context and session transcripts? The agent doesn&apos;t need to remember what it was thinking — it can just re-derive it. The human who never touched the code doesn&apos;t need line-level attribution.&lt;/p&gt;
&lt;p&gt;That could go either way for Entire. Maybe full autonomy makes provenance &lt;em&gt;more&lt;/em&gt; critical — precisely because no human was involved, you need a machine-readable audit trail. Or maybe it makes the whole problem vanish — agents that manage their own context don&apos;t need git hacks to preserve it.&lt;/p&gt;
&lt;p&gt;Either way, if you&apos;re leading an engineering team right now, you should be thinking about how you&apos;ll audit, understand, and trust the code your agents produce — whether there&apos;s a human in the loop or not.&lt;/p&gt;
&lt;p&gt;Next up, I&apos;ll dig into the actual source code and show you &lt;a href=&quot;https://julien.danjou.info/blog/how-entire-works-under-the-hood/&quot;&gt;how Entire&apos;s Checkpoints CLI works under the hood&lt;/a&gt;. It&apos;s a clever piece of engineering that abuses git internals in ways I genuinely admire.&lt;/p&gt;
</content:encoded><category>ai</category><category>git</category><category>developer-experience</category></item></channel></rss>