Git Becomes Load-Bearing Infrastructure When You Add Coding Agents
Source: simonwillison
Most developers treat git as a logging tool: you write code, then you commit to record what you did. Coding agents invert that relationship. With an agent in the loop, you commit before anything happens, and git diff becomes your primary review interface rather than a passive audit trail. Simon Willison’s guide on agentic engineering patterns covers this shift clearly, and the deeper you go with agents the more you understand why this reorientation matters.
This isn’t about being cautious. It’s about the structure of agent output. A coding agent given a reasonably complex task will touch files you didn’t anticipate, make decisions you wouldn’t have made, and occasionally produce changes that are subtly wrong in ways that only become visible when you review the diff. The commit graph is how you stay oriented.
The Pre-Flight Commit
The baseline practice is simple: commit your current state before invoking an agent, every time. This gives you a clean restoration point and a clear before/after comparison.
git add -A && git commit -m "checkpoint: before agent run"
This seems obvious until you’ve done a dozen agent sessions and realize how often you want to review git diff HEAD~1 to understand exactly what the agent changed versus what you changed afterward. Without that commit, the diff is contaminated with your own edits and the agent’s edits mixed together.
Aider, one of the more established open-source coding agents, automates this with its --auto-commits flag and prefixes all agent-generated commits with aider: in the commit message. This creates a machine-readable record of which commits were agent-assisted versus human-written. When something breaks two weeks later, git log --oneline | grep aider: tells you exactly where to look. That’s a convention worth adopting even if you’re using a different tool.
Worktrees Are the Underrated Feature
Git worktrees are one of those features that most developers know exists but rarely use. The concept: git worktree add checks out a branch into a separate directory, sharing the .git object store but maintaining independent working trees and HEAD pointers. It’s not cloning the repository; it’s a second window into the same repository.
git worktree add ../repo-feature-a -b agent/feature-a
git worktree add ../repo-feature-b -b agent/feature-b
For coding agents, this is transformative. You can run two agent tasks in parallel without any branch conflicts, without stashing and unstashing, and without the agents interfering with each other’s file states. Each agent process works in its own directory; the git object store handles deduplication behind the scenes.
Claude Code is worktree-aware by design. Running claude from inside a worktree directory scopes all file operations to that worktree. Combined with something like:
git worktree add /tmp/agent-task-$(date +%s) -b agent/task-description
cd /tmp/agent-task-...
claude # or whatever agent invocation
git push origin agent/task-description
gh pr create --fill
git worktree remove /tmp/agent-task-...
…you get a clean per-task lifecycle. The branch is the deliverable, the worktree is temporary scaffolding. GitHub Copilot Workspace implements something structurally similar at the infrastructure level: every task gets an isolated environment, and the PR is the output. The worktree pattern is how you replicate that locally.
Branch Naming as Metadata
The agent/ prefix convention for branches carries real information. When you look at your remote branches and see agent/add-auth-middleware, agent/refactor-database-layer, and agent/fix-rate-limiting, you know those are agent-generated deliverables waiting for human review. When you see those branches in a PR queue, reviewers know to approach them with the right frame of mind.
This kind of naming convention is lightweight process that pays for itself quickly, especially on small teams where not everyone was present for every agent session. The branch name is the first line of documentation for work that a human didn’t write directly.
The Review Interface Problem
Reviewing agent-generated code is harder than reviewing human-generated code, and not because agents write worse code. The difficulty is volume and coherence. An agent asked to “add rate limiting to the API” might touch the router, the middleware stack, a config file, tests, and the README, all in a single pass. The human who asked for this has to evaluate whether each of those changes is correct in isolation and whether they’re collectively consistent.
git diff HEAD before committing is the mandatory step. Not optional, not something you do when you’re suspicious. Every time. The patterns to watch for:
- Scope creep: changes to files you didn’t expect. Sometimes these are correct and valuable; sometimes they’re the agent following a path that seemed logical but introduces unintended coupling.
- Stub completion: the agent filled in a TODO or placeholder with something plausible but wrong for your specific context.
- Dependency changes: package.json, go.mod, requirements.txt getting new dependencies. These are often correct but warrant explicit review.
- Test changes: an agent that modifies tests to make them pass rather than fixing the underlying code. This is the classic failure mode.
Frequent small commits make git bisect viable. If every agent task is a single commit, and you’ve written a test that catches the regression, bisect will pinpoint the exact agent run that introduced the problem. A single 200-file agent commit makes bisect nearly useless.
What Agents Should and Shouldn’t Control
There’s a practical question about which git operations to give an agent versus which to keep under human control. The pattern that works:
Read-only operations, freely available:
git log --oneline,git log --follow -p -- path/to/filegit diff,git show,git blamegit status
These give the agent essential context about codebase history and current state without any write risk.
Write operations, human-confirmed or scoped:
git commitinside a worktree or feature branch: acceptablegit pushto a remote: human reviews firstgit checkoutor branch operations onmain/master: off limitsgit reset --hard,git clean -fd: never
The push boundary is the one that matters most. An agent that can push directly to a shared branch can affect other developers before any review happens. Keeping push as a human action, or limiting agents to branches with required PR review, enforces a review gate that branch protection rules alone don’t fully cover.
Devin and SWE-agent both treat branch creation and PR opening as first-class outputs of their task execution. The branch is the deliverable. This is the right framing: agent work produces a branch, human review produces a merge.
Credential Exposure
One thing the git integration discussion often underweights: if an agent has filesystem access to your working directory and you have a .env file with credentials in that directory, the agent can read it. Agents that include context from nearby files in their prompts may inadvertently include secrets. The agent logs on whatever service you’re using may store that context.
Before running agents in a repository, audit what’s in the working tree. .env files should be in .gitignore and not present in working directories where agents operate. Secrets belong in environment variables or secret managers, not files. This is standard practice anyway, but the agent use case makes the failure mode more concrete and more immediate.
Commit Trailers for Traceability
Git commit trailers are a structured way to embed metadata in commits without polluting the message body. Several teams have converged on using trailers to mark agent-assisted commits:
Add rate limiting middleware
Implemented token bucket algorithm with configurable limits per endpoint.
Limits are stored in Redis with automatic expiry.
Co-Authored-By: claude-sonnet-4-6 <noreply@anthropic.com>
Agent: claude-sonnet-4-6
The Co-Authored-By trailer is already recognized by GitHub and displayed in the PR UI. Adding an explicit Agent: trailer creates a queryable field for tooling. git log --grep='Agent:' --oneline gives you a history of agent-assisted commits across the repository.
This is worth standardizing early if you’re doing significant agent-assisted development. Retrofitting it across a large commit history is tedious; starting with the convention from the beginning costs almost nothing.
The Underlying Reason This Works
Git’s data model is a directed acyclic graph of immutable content-addressed snapshots. Every commit is a complete description of the repository state at a point in time, and every object in that graph is identified by a hash of its content. Reverting to any prior state is always possible and always correct.
For agentic workflows, this immutability is the safety property you’re relying on. No matter what an agent does to the working tree, the commit graph records what the state was before, and git checkout or git reset can restore it precisely. The agent operates in the mutable working tree; the git object store is your invariant.
That’s why Simon Willison’s framing, and the broader community consensus, converges on git as the first tool to configure correctly when adding agents to a workflow. The version control tool becomes the containment layer.