Artifact e7c1014e0b23e8fc1fbd7689346ca9fbf609250163e9b7783fe2e9d87ed7dedb:
- File
internal/merge/threeway.go
— part of check-in
[dcec15d91f]
at
2026-10-19 01:50:20
on branch feat/submanifest-reader
— fix(merge): write fossil's merge3 output byte for byte
Port fossil 2.28's merge3.c and the diff it runs on (break_into_lines, break_into_tokens, longestCommonSequence, diff_step, diff_optimize, the UTF-8/UTF-16 BOM handling) so Merge and Update align, merge and mark conflicts exactly as fossil does: line-numbered markers, the token-level suggested resolution, CRLF markers, and binary input left unmerged. HasConflictMarkers follows contains_merge_marker in skipping CR runs.
A fossil-binary comparison test checks 1237 generated and hand-written cases against "fossil 3-way-merge" and UTF-16 cases against "fossil merge"; fossil commit refuses a file holding our markers.
Tracked in #447 (user: [email protected], size: 1168) [annotate] [blame] [check-ins using] [more...]
package merge func init() { Register(&ThreeWayText{}) } // ThreeWayText is fossil's line-level three-way merge (merge3.c), byte for // byte: the same alignment, the same clean result, and on conflict the same // line-numbered markers and suggested resolution fossil writes. type ThreeWayText struct{} func (t *ThreeWayText) Name() string { return "three-way" } // Merge merges the changes from base to remote into local. Content fossil // cannot diff as text (a NUL byte, or a line over 32767 bytes) is not // merged: as fossil does, the local copy is kept and the merge is not clean. func (t *ThreeWayText) Merge(base, local, remote []byte) (*Result, error) { if base == nil { panic("merge.ThreeWayText.Merge: base must not be nil") } if local == nil { panic("merge.ThreeWayText.Merge: local must not be nil") } if remote == nil { panic("merge.ThreeWayText.Merge: remote must not be nil") } out, conflicts, n := mergeText(base, local, remote) if n < 0 { return &Result{ Content: local, Conflicts: []Conflict{{Local: local, Remote: remote, Base: base}}, }, nil } return &Result{Content: out, Conflicts: conflicts, Clean: n == 0}, nil }