# Merge conflicts

> When two branches changed the same lines. zev shows each conflict with your side, the base and theirs, settles them with one command instead of an editor, and lets you commit them now and resolve later. Every step is data for scripts and AI agents.

Source: https://zaryn.xyz/docs/en/conflicts

A conflict happens when two branches changed the same lines and zev can't know which version you want. In Git a conflict blocks you: until every file is settled you can't commit, switch branches or put the work aside. In zev it's something you can look at, settle one piece at a time without opening an editor, or commit as it is and come back to later.

```diagram
type: flow
title: A conflict, from start to finish
---
Start | `zev merge main --resolve` puts every conflict in place | warn | ⚠️
~ zev conflicts
See | Each one with your side, the base and theirs | | 👀
~ zev resolve
Settle | Pick a side per file or per conflict, or edit by hand | | ✏️
~ zev merge --continue
Done | Recorded, or recorded now with --keep-conflicts and settled later | good | ✓
? Changed your mind? `zev merge --abort` puts everything back
```

## Start: zev merge --resolve

`zev merge` never leaves you halfway. When both sides changed the same lines it stops before changing anything and says so. `zev merge <branch> --resolve` then combines everything that can be combined and marks the rest:

```bash
zev merge main --resolve
  both changed  app.py
  both changed  logo.png (not text: yours is in place; zev resolve logo.png --theirs takes 'main''s)
```

Each marked place shows three versions, not two: yours, what the line was before either of you changed it (the **base**), and theirs. The base is often what tells you which change to keep.

```text
<<<<<<< feature
price = total * 0.9
||||||| base
price = total
=======
price = round(total, 2)
>>>>>>> main
```

## See every conflict: zev conflicts

```bash
$ zev conflicts
Merging main into feature
  ✗ app.py  1 conflict(s)
    #1 line 12
      feature  price = total * 0.9
      base     price = total
      main     price = round(total, 2)
  ✗ logo.png  not text: both changed it (yours is in place)
```

The numbers (`#1`, `#2`…) are what `--hunk` takes below. `zev status` lists the conflicted files too.

## Settle them: zev resolve

Pick a side, for a whole file or for single conflicts, with no editor:

```bash
zev resolve app.py --theirs            # every conflict in app.py: main's version
zev resolve app.py --ours --hunk 2     # only conflict #2: your version
zev resolve app.py --both              # yours, then theirs
zev resolve logo.png --theirs          # files that aren't text: pick a version
zev resolve --ours                     # every conflict left, everywhere
```

`--base` keeps the line as it was before either change. Or open the file and edit it yourself, as you would in Git: keep what you want and delete the marker lines. Once a file has no markers left it's settled.

When everything is settled:

```bash
zev merge --continue
```

## Commit now, resolve later

Sometimes a conflict is in a file you don't own, or in a part someone else should decide, and the rest of the merge shouldn't wait. Record it as it is:

```bash
zev merge --continue --keep-conflicts
  kept as a conflict  app.py  (1 left)
```

The commit carries the list of files it was recorded with conflicts in. You can switch branches, keep working and push. Nothing is hidden: `zev log` marks the commit, `zev conflicts` keeps listing what's left, and every later commit carries the list forward until the markers are gone:

```bash
$ zev log --oneline
9c1d2e4a Use the new price rule [1 conflict(s)]

$ zev resolve app.py --theirs      # settled and staged for you
$ zev commit -m "Settle the price rule"
Resolved: app.py
```

On Zaryn the commit shows the same mark, and **a pull request whose last commit still has conflicts can't be merged**, so they never reach `main` by accident. Files that aren't text can't hold both versions, so `--keep-conflicts` asks you to pick one for them first.

## For scripts and AI agents

Every step answers as data. `zev conflicts --json` gives each file and each conflict with all three sides; `--brief` gives the same in a few lines, `<` for yours, `|` for the base and `>` for theirs:

```bash
$ zev conflicts --brief
# merging main into feature
app.py #1 L12
< price = total * 0.9
| price = total
> price = round(total, 2)
binary logo.png
```

```json
{"merging":{"branch":"feature","with":"main"},"committed_in":null,"open":2,
 "files":[{"path":"app.py","kind":"text","resolved":false,
   "hunks":[{"n":1,"line":12,"lines":7,"ours_label":"feature","theirs_label":"main",
     "ours":"price = total * 0.9\n","base":"price = total\n","theirs":"price = round(total, 2)\n"}]},
  {"path":"logo.png","kind":"binary","resolved":false,"hunks":[]}]}
```

An agent reads the conflicts without opening each file, decides with the base in front of it, and settles each one with `zev resolve <file> --ours|--theirs|--both --hunk N` instead of rewriting whole files. `zev status --brief` marks conflicted files `UU`, as `git status --porcelain` does, and `zev status --json`, `zev log --json` and `zev brief` say what's open. `zev undo` takes back a recorded merge like any other commit.

## How this differs from Git

| | Git | zev |
|---|---|---|
| **During a conflict** | You can't commit, switch branches or stash until every file is settled | Commit now with `--keep-conflicts`; switch, push and resolve later |
| **What a conflict shows** | Two sides; the base only if you set `merge.conflictStyle diff3` | Yours, the base and theirs, always |
| **Settling** | An editor or a merge tool; `checkout --ours` only for a whole file | `zev resolve` per file or per conflict (`--hunk`), including `--both` and `--base` |
| **Listing them** | `git diff --name-only --diff-filter=U`, then reading each file | `zev conflicts`: every conflict with its sides, as text, `--json` or `--brief` |
| **After a commit** | Markers committed by mistake look like any other text | The commit records its conflicts; `zev log` marks it and Zaryn won't merge it |

See also: [Branches and merging](/docs/en/branches), [Undo anything](/docs/en/undo), [Scripting and AI agents](/docs/en/automation-and-agents).
