Skip to content

fix(core): non_overlapping no longer duplicates lines both branches added - #259

Merged
devlint merged 2 commits into
mainfrom
fix/core-non-overlapping-duplicate-lines
Oct 13, 2026
Merged

devlint merged 2 commits into
mainfrom
fix/core-non-overlapping-duplicate-lines

Conversation

@devlint

@devlint devlint commented Oct 13, 2026

Copy link
Copy Markdown
Owner

Problem

Found while checking the blog article on conflict markers. When both branches add the same lines, a conflict written in diff3 style was classified non_overlapping (score 80) and auto-applied with those lines twice. The same conflict in zdiff3 resolved correctly.

<<<<<<< HEAD                 ||||||| base          =======
  timeout: 5000,               timeout: 3000,        timeout: 3000,
  retries: 3,                  retries: 3,           retries: 5,
  region: "eu-west-1",                               region: "eu-west-1",
  verbose: true,                                     verbose: true,

Result on main: timeout: 5000, retries: 5, region, verbose, region, verbose.

This matters beyond hand-written markers: git merge-file --diff3 (desktop merge preview, base reconstruction) and the benchmark replay all produce diff3 markers. I reproduced it on git merge-file -p --diff3 output too.

Cause

In mergeNonOverlapping (packages/core/src/diff/shared.ts), ours is a pure insertion of region/verbose at base index 2, and theirs is a replacement of [1, 2) that also adds them. editsOverlap treats an insertion at the other edit's baseEnd as disjoint (2 < 2 is false), so both copies are kept.

Fix

  • Lines identical at the start and end of ours and theirs are taken out of the merge and put back around the result, as zdiff3 does. The part the base shares is trimmed from the base too, as unchanged context.
  • A pure insertion placed right after an edit from the other branch that adds some of the same lines now counts as an overlap. When the shared lines are not at the hunk edge (ours x5 y3 R V E1, theirs x3 y5 R V E2), main produced R V E2 R V E1; that hunk is now left for review.

Verification

  • pnpm test (core): 1284/1284, including 4 new regression tests (diff3, zdiff3, shared base context, ambiguous insertion).
  • Merge benchmark, local cached corpus, main vs this branch under identical conditions: agreement with the human merge 65.69% → 66.76% (672 → 683 of 1023 files), no repo down, coverage unchanged. 26 merges failed merge-tree on both local runs (sandbox blocked blob fetches); the CI gate replays the full corpus.
  • pnpm bench: within noise.
  • Not checked: the desktop merge-preview UI end to end.

…dded

In a diff3 hunk, lines added identically by both branches sit inside the
markers on each side. mergeNonOverlapping saw them as two separate edits
(ours: a pure insertion at the end of the base; theirs: part of a
replacement ending at the same index), found no overlap, and kept both
copies. The hunk was classified non_overlapping (80) and auto-applied.
The same conflict in zdiff3 resolved correctly, because Git had already
taken the common lines out of the hunk. git merge-file --diff3, used by
the desktop merge preview and base reconstruction, and the benchmark all
produce diff3 markers.

- Lines identical at the start and end of ours and theirs are taken out
  of the merge, as zdiff3 does; the part the base shares is trimmed from
  the base too, as unchanged context.
- A pure insertion placed right after an edit from the other branch that
  adds some of the same lines is now treated as an overlap: order and
  deduplication are ambiguous there, so it is left for review.

Benchmark (same local corpus, same 26 merge-tree errors on both runs):
agreement with the human merge 65.69% -> 66.76% (672 -> 683 of 1023
files), no repo down, coverage unchanged. pnpm bench: within noise.
@devlint
devlint merged commit 072c075 into main Oct 13, 2026
10 checks passed
@devlint
devlint deleted the fix/core-non-overlapping-duplicate-lines branch October 13, 2026 13:54
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.

1 participant