I used to rebase every feature branch onto main before merging. Linear history, clean log, no merge commits. Then I started letting coding agents work on branches, and I changed my mind.
The reason is undo. When an agent does something I don't want, I want to take back that one turn and keep everything before it. So the app I build (Styx) snapshots the branch after every agent turn, as a hidden git ref that points at a commit.
A rebase rewrites every commit on the branch. The snapshots still point at the old commits, which are no longer on the branch's history. "Undo the last turn" would jump to a commit that has nothing to do with the branch you now have.
A merge doesn't rewrite anything. Main comes in as one new commit on top, the snapshots stay on the branch's history, and undo keeps working. The price is a merge commit in the log, which I've stopped minding.
The general lesson: if anything outside git points at your commits (snapshots, review comments, deploy records), rewriting history breaks it quietly. Do you rebase branches that tools or agents work on, or have you hit the same thing?
Top comments (3)
The hidden-ref snapshot is the part I'd underline. Anything outside git that holds a SHA (snapshots, review threads, deploy records) fails quietly on a rebase, and you only find out when you go to undo.
We hit the same thing with an agent. It rebased a working branch and dropped a half-finished tool change we meant to keep. The merge-main version was uglier but recoverable, so that's where we landed too.
On your question: no, we don't rebase branches agents touch anymore. Do you stamp which agent turn touched which files, or is that still manual?
Hey Wasim. Thanks for your question. Every agent stamps their diff into a project level audit log. This is immutable. I have also added an ability for agents to communicate with each other if there is more than one agant working on the repo. This allows cross agent messaging when their is a sensitve action taking place, like landing on main etc
The other place rebasing breaks external refs is dirty worktrees. If a background agent process holds uncommitted scratch files or a lock when you start an interactive rebase, the rebase aborts midway or leaves you in detached HEAD with an orphaned index. Keeping checkpoints under refs/checkpoints/* and doing an explicit merge commit preserves the full reflog lineage without touching working-tree state. Even if you squash-merge the branch into main later to keep trunk clean, the internal checkpoint DAG stays intact for rollbacks.