To resolve merge conflicts with AI safely, make the conflict readable first, then give a coding agent both sides’ intent and strict rules, and only accept the result after git confirms no conflict markers are left and your tests pass. Agents like Claude Code and Codex are genuinely useful here: they read both versions, the common ancestor and the surrounding code faster than you can, and they can combine two changes instead of picking one. Their typical failure is just as clear: when the intent of one side is unclear, they keep the side that compiles and drop the other without saying so.
This guide covers why conflicts happen (and why parallel agents make them more frequent), a step-by-step workflow from git status to git merge --continue, a prompt template, rebase vs merge, git rerere, a pre-merge check, and how to prevent most conflicts in the first place. Git commands are checked against the official documentation on git-scm.com as of October 2026.
Why merge conflicts happen
When Git merges two branches, it compares both against their common ancestor. Changes to different areas of a file are combined automatically. When both sides changed the same area, Git can’t pick one, so it stops and writes both versions into the file between conflict markers. That is a textual conflict.
The common kinds you’ll meet:
- Content conflict: both branches edited the same lines of the same file.
- Modify/delete: one branch changed a file, the other deleted or moved it.
- Generated files: lockfiles, snapshots, compiled output or translation bundles that both branches regenerated.
There is also a conflict Git can’t see: a semantic conflict. Two branches touch different files, merge cleanly and still break each other, for example when one changes a function signature and the other adds a new caller. Only tests on the merged result catch that; the merge queue post walks through an example.
Why parallel agents make conflicts more common
Running several agents at once, each in its own git worktree, keeps them from overwriting each other’s files while they work. It doesn’t stop the conflict; it moves it to merge time. Each agent works from the base it started on and never sees what the others changed. A few files attract conflicts again and again:
- route tables, dependency injection setups and other registries where every feature adds one line,
- barrel files (
index.ts) and shared types, package.jsonand its lockfile,- translation files, changelogs and config files.
Agents are also thorough in ways that hurt here: they reformat a file they only meant to touch, rename a helper “while they’re at it”, or fix an unrelated lint warning. Each of those widens the area two branches have both changed.
Step 1: stop and look before anything else
When a merge or rebase stops, find out where you are before asking anyone, human or agent, to fix it:
git status # which operation, which files are "both modified"
git diff --name-only --diff-filter=U # only the unmerged files
--diff-filter=U selects unmerged paths, which gives you a clean list to hand to an agent. Remember the exits too. If the conflict is bigger than you expected, nothing is lost yet:
git merge --abort # back to the state before the merge
git rebase --abort # back to where the branch was before the rebase
Git’s docs recommend committing or stashing your own changes before running git merge, because --abort can’t always reconstruct uncommitted work. The same goes for an agent’s worktree: let it commit before you merge anything into it.
Step 2: switch to zdiff3 so the base is visible
By default Git shows only the two sides:
<<<<<<< HEAD
const timeout = config.timeout ?? 30_000;
=======
const timeout = getTimeout(config);
>>>>>>> feature/retry
You can’t tell from this what the original line was, so you can’t tell what each side intended. Set the conflict style to zdiff3 (added in Git 2.35; use diff3 on older versions):
git config --global merge.conflictStyle zdiff3
Now the conflict includes the common ancestor after a ||||||| marker:
<<<<<<< HEAD
const timeout = config.timeout ?? 30_000;
||||||| base
const timeout = config.timeout;
=======
const timeout = getTimeout(config);
>>>>>>> feature/retry
Now it’s readable: one side added a default, the other moved the lookup into a function. The right resolution probably keeps both, for example by putting the default inside getTimeout. According to the git-config docs, zdiff3 is like diff3 but moves matching lines at the start and end of a conflict out of the conflict region, so the hunks stay small.
For a merge that is already in progress, recreate the markers of one file in the new style:
git checkout --conflict=zdiff3 src/http/client.ts
This matters even more for an agent than for you. Without the base, the model has to guess which side changed what, and guessing is where silent data loss starts.
Step 3: give the agent the context it needs
The conflict markers show the lines. The agent also needs to know why each side changed them. Git can show the history of both sides for a file:
git log --merge -p src/http/client.ts # diffs from HEAD first, then from MERGE_HEAD
git show :1:src/http/client.ts # common ancestor
git show :2:src/http/client.ts # HEAD (ours)
git show :3:src/http/client.ts # MERGE_HEAD (theirs)
Add the human context: the task or pull request description of each branch. Then use a prompt like this one:
We are in the middle of a git merge of feature/retry into main. These files
have conflicts (merge.conflictStyle is zdiff3, so the base is shown):
<output of git diff --name-only --diff-filter=U>
Intent of main: <one or two sentences, or the PR description>
Intent of feature/retry: <one or two sentences, or the PR description>
For each conflicted file:
1. Read the ours, base and theirs sections and say in one line what each
side changed relative to the base.
2. Write a resolution that keeps both intents. If they truly contradict,
stop and ask me instead of choosing.
3. Edit only the conflicted hunks. No reformatting, renames or unrelated fixes.
4. Do not edit tests to make them pass, and do not delete code you
don't understand.
For package-lock.json / pnpm-lock.yaml: resolve package.json only, then
regenerate the lockfile with the package manager.
When done: no conflict markers left, run the type check and tests, and give
me a per-file summary of what you kept from each side. Do not run git add,
git commit or git merge --continue.
The last line keeps the final step with you. The per-file summary is what makes review fast: you compare each claim with the diff instead of reading every line cold.
Step 4: resolve one file at a time, by hand-checked rules
A few rules make the difference between a clean merge and a quiet regression:
- No blanket
--oursor--theirs.git checkout --ours <path>takes one whole side of a file and discards the other. Use it only for a file where you know one side should win, such as a generated file you will regenerate anyway. - Mind the swap during rebase. Git’s docs note that during
git rebaseandgit pull --rebase,--oursis the branch you are rebasing onto and--theirsis your own work being replayed. Agents get this wrong surprisingly often, so tell them which branch is which by name. - Regenerate, don’t merge, generated files. Lockfiles, snapshots and build output should come from the tool that generates them, after the source files are resolved.
- Modify/delete needs a decision. If one branch deleted a file the other changed, the agent should report it and ask, not restore or delete it on its own.
- Big conflicts get split. If one file has dozens of hunks, ask the agent to resolve and explain it in parts, or step back and rethink the merge order.
Step 5: verify before you continue
An agent saying “resolved” is a claim, not proof. Check it:
git diff --check # warns about leftover conflict markers (and whitespace errors)
git diff # review the resolution
pnpm typecheck && pnpm test # or your project's own check
git diff --check exits non-zero when changes introduce conflict markers, so it is a cheap gate to run every time. On recent Git versions, git diff AUTO_MERGE shows only the changes made so far to resolve the textual conflicts, which is a focused view of exactly what the agent wrote.
Then finish the operation yourself:
git add src/http/client.ts
git merge --continue # or: git rebase --continue
Never accept blindly: red flags in a resolution
| Red flag | What it usually means |
|---|---|
| One side’s change is simply gone | The agent picked a side instead of combining them |
| A test or assertion changed | The resolution broke behaviour and the test was bent to fit |
| Files outside the conflict list changed | Scope creep: reformatting or “fixes” that need their own review |
| Code appears twice | Both sides were kept verbatim, not merged |
Markers or a stray ======= left in a non-code file | Nobody ran git diff --check |
If you see any of these, ask the agent to explain that hunk, or redo the file by hand. An AI code review of the merge result is a useful second pair of eyes, but it doesn’t replace running the tests.
Rebase vs merge when conflicts are likely
Both work; they fail differently.
| Merge | Rebase | |
|---|---|---|
| Where you resolve | Once, in the merge commit | Commit by commit, as each one is replayed |
| Same conflict twice | No | Possible, in several replayed commits |
--ours / --theirs | Your branch / the other branch | Swapped: the target / your own work |
| History | Keeps a merge commit | Linear, rewrites the branch’s commits |
| Safe on shared branches | Yes | Only if nobody else builds on that branch |
For short-lived agent branches that only you use, rebasing onto main often is the easier habit: conflicts show up early, while they’re small. For long-lived or shared branches, merge. During a rebase, git rebase --skip drops the current commit entirely, so only use it when you’re sure that commit isn’t needed.
Let Git remember: rerere
If you rebase the same branch again and again, you’ll resolve the same conflict more than once. git rerere (“reuse recorded resolution”) records how you resolved a conflict and replays it when the same conflict appears again:
git config --global rerere.enabled true
Once enabled, git merge and git commit run it automatically. Useful commands:
git rerere status # paths whose resolution will be recorded
git rerere diff # what the current resolution looks like
git rerere remaining # conflicts rerere could not resolve
git rerere forget src/http/client.ts # drop a wrong recorded resolution
Two things to know. rerere leaves the index alone, so you still check the result and git add it, which is good, because a wrong resolution gets replayed just as faithfully as a right one. And old records are pruned by git rerere gc: by default unresolved records after 15 days and resolved ones after 60.
Check for conflicts before you merge
You don’t have to start a merge to find out whether it will conflict. Since Git 2.38, git merge-tree --write-tree performs the merge without touching your working tree or index:
git merge-tree --write-tree --name-only main feature/retry
echo $? # 0 = clean, 1 = conflicts
With --name-only, the conflicted section lists just the file names. Git’s docs advise relying on the exit status rather than an empty file list. This is a handy step to give an agent before it touches anything: “check whether feature/retry merges cleanly into main, and if not, list the conflicted files and what each side changed.”
Prevention: fewer conflicts with parallel agents
The cheapest conflict is the one that never happens:
- Small tasks. An agent that changes five files conflicts less than one that changes fifty. Split big jobs by area.
- One owner per area. Decide which agent may change the router, the schema, the shared types. Say it in each agent’s instructions.
- Merge or rebase often. A branch that lives for an hour rarely conflicts; a branch that lives for a week almost always does.
- No drive-by edits. Tell agents not to reformat, rename or fix things outside their task.
- One lockfile change at a time. Let a single branch add dependencies, or regenerate the lockfile after each merge.
- A merge queue. Branches land one by one on the latest tip, with tests on the merged result, so semantic conflicts are caught too.
For the setup side of running agents in separate folders, see git worktrees for parallel agents.
How AgentVera helps
AgentVera is a desktop app that runs coding-agent CLIs such as Claude Code and Codex side by side, with git built in. These features touch the workflow above:
- Worktrees and the Git panel. Create a worktree per feature and start an agent in it; stage per file, commit, fetch, pull and push, and read diffs GitHub-style, unified or split.
- Early warnings. By default AgentVera runs
git fetchin the background every 5 minutes. When new commits reach your branch, a banner lets you fast-forward in one click, or rebase when both sides have commits. When two agents in the same project edit the same file, agent coordination warns you; for agents in different worktrees it notes that merging may conflict. - File ownership. With file ownership you give an agent paths or globs like
src/api/**. While it runs, Claude Code agents are stopped before editing those files and told to ask the owner; Codex and other CLIs get the rules in their instructions. - Parallel team. A parallel team (Pro) splits a job into parts that each run in their own worktree and merge into an integration branch. If a merge conflicts or the final check fails, an integration agent steps in.
- Merge queue. The merge queue (Pro) merges branches one at a time onto the latest target. A Claude agent resolves conflicts, the check runs on the merged result with up to 2 fix rounds, and a branch that can’t be fixed is returned. Landing waits for your approval by default.
If you work alone on one branch at a time, plain git with zdiff3 and rerere is all you need. These tools pay off once several agents produce branches at the same time.
Common mistakes
- Resolving without the base. The default conflict style hides what the code looked like before; turn on
zdiff3. - “Fix the conflicts” as the whole prompt. Without each branch’s intent, the agent picks the side that looks more complete.
- Letting the agent run
git addand--continue. Keep the final step for aftergit diff --checkand the tests. - Hand-merging lockfiles. Resolve the manifest, then regenerate.
- Rebasing a shared branch. Everyone who built on it now has to untangle rewritten commits.
Wrapping up
Resolving merge conflicts with AI works when the agent sees the full picture and you keep the proof: zdiff3 markers that show the base, a prompt that states both intents and forbids shortcuts, git diff --check and the test suite before git add, and rerere for conflicts that keep coming back. Prevention does the rest: small tasks, clear file ownership and branches that land one at a time.
To try it with your own agents, download AgentVera.