People share AI workflows with 10 agents, 10 PRs, and absurd shipping speed.
My reaction was always: how the hell does this not constantly break?
My own parallel-agent workflow looked different:
- Different projects: no shared code, so no conflicts.
- Same project + worktrees: isolated while coding.
- Merge time: every parallel change finally collides.
The questions I couldn't shake:
- Same file: who resolves the conflict?
- Dependent tasks: how can PR #2 exist before PR #1 merges?
- First PR merges: aren't the remaining branches now stale?
- Git says “clean”: who checks that the combined code actually works?
That confusion led to this deep dive. A recent AgenticFlict preprint collected 142,000+ agent-authored PRs. Of the 107,000+ it could process, 27.67% contained textual merge conflicts. The problem is real; teams just have tools for containing it.
The whole playbook: keep changes small, integrate one at a time, and test every PR against the latest main.
Every tool below does one of two things: shrinks the overlap or shrinks the time apart. Poke the demos.
Problem 1: branches drift
Your branch is a diff against one frozen commit. Every new commit on main makes that base older—and the eventual reconciliation harder.
Rule: sync often. Keep reconciliation a two-minute chore, not a two-day dig.
Problem 2: Git can merge broken code
| Conflict | Changes | Git does | Real risk |
|---|---|---|---|
| Textual | Same lines | Stops the merge | Loud, visible |
| Semantic | Different but dependent files | Merges cleanly | Silent, dangerous |
Tiny semantic-conflict example:
- Agent A renames
sendReply(). - Agent B adds a call to
sendReply(). - Git sees no overlapping lines. Runtime sees a missing function.
Solution 1: merge queue
Several PRs can be “green” against a base that no longer exists. A merge queue processes each one against reality:
- Rebase the next PR onto the latest
main. - Include everything already ahead of it.
- Run the tests again.
- Merge or eject.
Result: a stale-green PR cannot silently poison main.
Solution 2: stack dependent work
Some work is naturally a chain:
- Snooze API
- Toolbar button using that API
- “Snoozed” results view
Your options:
- Wait: safe, but everyone sits idle.
- Pile: one giant branch; hard to review and easy to drift.
- Stack: branch each step from the one below; open all three as small PRs.
Use stacks only for real dependencies. Unrelated tasks stay on separate short branches.
Solution 3: feature flags
A large feature creates a bad choice: long-lived branch or half-finished release.
A feature flag removes that choice:
- Merge unfinished code continuously.
- Keep the flag OFF while building.
- Turn it ON when ready.
- Turn it OFF for instant rollback.
Merged ≠ released. Integration and rollout become separate decisions.
The practical playbook
- One task → one short-lived branch → one worktree.
- Fork every agent from one pinned base commit.
- Merge one PR at a time.
- Rebase the remaining branches onto the new
main. - Run the app or tests after every rebase.
- Let an agent resolve bounded conflicts.
- Add a merge queue when ready PRs keep invalidating each other.
Don't merge N things at once. Merge one thing N times—against the real current base.
Further reading: Trunk-based development, GitHub merge queue docs, Graphite on stacked PRs, and Martin Fowler on feature toggles.