Command Palette

Search for a command to run…

ZarynZaryn
Code hosting and version control·4 min read·

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.

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).