Skip to content

chore(upstream): auto-resolve conflicts with mergiraf + zdiff3 markers - #9624

Merged
markijbema merged 6 commits into
mainfrom
mark/upstream-mergiraf
Apr 28, 2026
Merged

chore(upstream): auto-resolve conflicts with mergiraf + zdiff3 markers#9624
markijbema merged 6 commits into
mainfrom
mark/upstream-mergiraf

Conversation

@markijbema

@markijbema markijbema commented Apr 28, 2026

Copy link
Copy Markdown
Contributor

Summary

Automates most of the conflict-resolution grunt work during upstream merges and makes the leftovers dramatically easier to resolve by hand.

  • Mergiraf (syntax-aware resolver): call mergiraf solve on each conflicted file before the kilocode-specific transform cascade in script/upstream/merge.ts. Auto-resolves the common pattern of neighbouring import additions around kilocode_change markers plus most JSON/YAML/TOML structural conflicts, so the existing i18n/branding/etc. transforms only see what's genuinely ambiguous. On a v1.14.28 merge run this resolved 45 of 74 conflicts.
  • zdiff3 markers for the whole merge: pass merge.conflictStyle=zdiff3 to git merge in utils/git.ts, so every conflicted file carries base (|||||||) markers from the start — not just the ones mergiraf happens to touch. Manual resolution then shows what both sides changed relative to the common ancestor, which is much easier than reverse-engineering that from a 2-way marker.
  • Never stage partial resolutions: mergiraf exit 2 means it reduced but didn't fully close the conflicts. The working tree keeps the reduced content (fewer markers to review), but the file is left unstaged so nothing half-resolved is auto-committed — you still see it in git status as needing attention.
  • Resilient to per-file failures: every subprocess in runMergiraf uses .nothrow() and logs at debug level on non-zero exit, so a single problem file can't abort the entire merge mid-run.
  • mergiraf required at startup: if missing the script aborts at step 1 with install instructions (brew / cargo / nix) rather than failing mid-merge.
  • No .orig pile-up: pass --keep-backup=false to mergiraf solve so the working tree isn't littered with backup files afterwards.

Mergiraf is actively maintained (v0.16.3, 2026-01-26) and supports all the file types we hit during upstream merges (TS/TSX, JSON, YAML, TOML, etc.). Docs: https://mergiraf.org/.

Test plan

Run bun run script/upstream/merge.ts against an upstream version known to produce import-shuffle conflicts (e.g. anything recent where upstream moved imports around CrossSpawnSpawner / Config / Global). Verify:

  1. Without mergiraf installed: script exits at step 1 with install instructions.
  2. With mergiraf installed:
    • files with purely-additive import conflicts are auto-resolved and staged before the kilocode transform cascade runs;
    • the log reports both a full-resolution count (mergiraf auto-resolved N conflict(s)) and a partial-resolution count (mergiraf partially resolved M file(s) — remaining markers left unstaged for manual review);
    • files with real semantic conflicts still fall through to manual review — with zdiff3 markers showing the base version alongside ours/theirs.

Before:

image

After:

CleanShot 2026-04-28 at 14 55 49

Invokes `mergiraf solve` (syntax-aware git merge tool) on each conflicted
file before the kilocode-specific transform cascade, re-materializing the
file with diff3 markers first so mergiraf can reconstruct the base
revision. This auto-resolves the common pattern of neighbouring import
additions around kilocode_change markers plus most JSON/YAML/TOML and
other structural conflicts, leaving the existing transforms to handle
only what's genuinely ambiguous.

mergiraf is required at startup; if missing the script aborts early with
install instructions (brew / cargo / nix) rather than failing mid-merge.
Comment thread script/upstream/merge.ts Outdated
@kilo-code-bot

kilo-code-bot Bot commented Apr 28, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Files Reviewed (2 files)
  • script/upstream/merge.ts
  • script/upstream/utils/git.ts

Reviewed by gpt-5.5-20260423 · 718,407 tokens

Mark IJbema added 4 commits April 28, 2026 14:11
Previously git add and mergiraf solve could bubble up exit 128 (e.g. on
files missing the base version) and abort the entire merge. Wrap every
shell call in .nothrow() and skip to the next transform pass on failure.
mergiraf exit 2 means it reduced conflicts but didn't fully close them.
Previously we bailed on any non-zero exit, throwing away the useful
partial reduction in the working tree. Now we always read the file after
mergiraf runs: if no conflict markers remain we stage, if markers remain
we keep the reduced content in the working tree for manual review but
leave the file unstaged so nothing half-resolved is auto-committed. Also
clean up the debug wording and surface a partial-resolution count in the
normal log output.
mergiraf defaults to writing a .orig sibling file for every file it
touches. Pass --keep-backup=false so the merge script doesn't leave a
pile of .orig files across the working tree after running.
Pass merge.conflictStyle=zdiff3 on the git merge invocation so every
conflicted file gets base-aware (|||||||) markers from the start, not
just the ones runMergiraf happens to touch. Benefits:

- Mergiraf always has a base section to work from, so its structural
  heuristics apply uniformly.
- Remaining manual conflicts show both sides relative to the common
  ancestor, which is dramatically easier to resolve than a 2-way marker.

Since the working tree already carries diff3 markers after the merge,
drop the per-file `git checkout --conflict=diff3` in runMergiraf.
@markijbema markijbema changed the title chore(upstream): run mergiraf on conflicted files during upstream merge chore(upstream): auto-resolve conflicts with mergiraf + zdiff3 markers Apr 28, 2026
…, binary)

Files in UD/DU/binary/etc. conflict states have no <<<<<<< markers in
the working tree. My earlier simplification that removed the
`git checkout --conflict=diff3` pre-check caused mergiraf to run on
them: it would exit 0 (nothing to solve), after which the unconditional
`git add` silently staged our side as resolved, losing the signal that
upstream deleted the file (or that we deleted what upstream modified).

Guard runMergiraf by inspecting the file before calling mergiraf: if
there are no conflict markers, skip the file entirely so it falls
through to manual review. Surface a skipped-count line in the normal
log output so the operator can see how many non-textual conflicts were
left alone.
@markijbema
markijbema merged commit 2c7a3e6 into main Apr 28, 2026
17 checks passed
@markijbema
markijbema deleted the mark/upstream-mergiraf branch April 28, 2026 12:58
jliounis pushed a commit to jliounis/kilocode that referenced this pull request May 18, 2026
chore(upstream): auto-resolve conflicts with mergiraf + zdiff3 markers
t7tran pushed a commit to t7tran/kilocode that referenced this pull request Aug 14, 2026
chore(upstream): auto-resolve conflicts with mergiraf + zdiff3 markers
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants