Resolve git merge conflicts with AI, safely

Resolve merge conflicts with AI without losing work: zdiff3 markers, a prompt for your coding agent, tests before git add, rerere, rebase vs merge and prevention.

Solviera Teknoloji 11 min read

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.json and 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 --ours or --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 rebase and git pull --rebase, --ours is the branch you are rebasing onto and --theirs is 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 flagWhat it usually means
One side’s change is simply goneThe agent picked a side instead of combining them
A test or assertion changedThe resolution broke behaviour and the test was bent to fit
Files outside the conflict list changedScope creep: reformatting or “fixes” that need their own review
Code appears twiceBoth sides were kept verbatim, not merged
Markers or a stray ======= left in a non-code fileNobody 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.

MergeRebase
Where you resolveOnce, in the merge commitCommit by commit, as each one is replayed
Same conflict twiceNoPossible, in several replayed commits
--ours / --theirsYour branch / the other branchSwapped: the target / your own work
HistoryKeeps a merge commitLinear, rewrites the branch’s commits
Safe on shared branchesYesOnly 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 fetch in 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 add and --continue. Keep the final step for after git diff --check and 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.

Questions

Can an AI coding agent resolve git merge conflicts?

Yes, and it is often good at it, as long as it sees the common ancestor (zdiff3 style), knows what each branch was meant to do and has a test suite to prove the result. Without those, it tends to keep one side and quietly drop the other.

What is the zdiff3 conflict style?

A value of merge.conflictStyle that adds a ||||||| section with the original text from the common ancestor, like diff3, but moves lines that both sides changed the same way out of the conflict region. Git added it in version 2.35.

Why are ours and theirs swapped during a rebase?

Git’s docs explain that during git rebase and git pull --rebase, --ours is the branch you are rebasing onto and --theirs is your own work being replayed. Blanket --ours or --theirs is risky for that reason alone.

What does git rerere do?

With rerere.enabled set, Git records how you resolved a conflict and reapplies that resolution when the same conflict shows up again, for example in a repeated rebase. It leaves the index alone, so you still check the result and git add it.

How do I check for conflicts before merging?

Run git merge-tree --write-tree --name-only main feature. It performs the merge without touching your working tree or index, exits with 1 when there are conflicts and lists the conflicted files. It needs Git 2.38 or later.

Bring your agents to one desk.

Download AgentVera for free; your installed CLIs are ready to go.

More posts