# sgit-ai 0.26.5: line-level merge, opt-in, cli.sgit.ai

> Dev build of 28 October 2026, from the CLI's dev at 43e1889c. sgit pull --merge lines and sgit branch merge --merge lines merge a file both sides changed line by line, as Git does, with Git's conflict markers in the file and --conflict diff3 for the base too. The default does not change: whole-file .conflict copies. Reviewed by cli.build. 5,030 tests pass and the four end-to-end checks hold. In 18,000 random merges against git merge-file, all 8,925 with unique lines were byte-identical. Where lines repeat, 2 of 4,544 code-like merges came out clean where Git reports a conflict (BR-2), and 0.9% placed conflict blocks differently (BR-3). Maturity good for an opt-in feature: review line-merged files before pushing.

*Source: <https://cli.sgit.ai/builds/0-26-5.html> · generated from the same content as the page, so the two cannot drift.*

---
# sgit-ai 0.26.5

```text
┌─ sgit-ai 0.26.5 ── dev build ── 28 Oct 2026, 11:25 UTC ─────────────────────────
│ tag v0.26.5 = 43e1889c (dev) · PyPI package == tag
│ new     pull --merge lines · branch merge --merge lines · --conflict diff3
│ tests   5,030 unit+security ✓ · X1–X4 ✓ · 18,000 merges vs git merge-file
│ open    BR-2 (medium, opt-in) · BR-3 (low) · BR-1 (all builds) · R3-1
│ maturity  #######---  good for an opt-in: read line-merged files before a push
└──────────────────────────────────────────────────────────────────────────────────
```

## What is new {#new}

Git-parity item 2.1, from [design 01](../research/git-parity-design-line-merge.md).

```text
$ sgit pull --merge lines                         # line by line, for files both sides changed
$ sgit pull --merge lines --conflict diff3        # markers carry the base version too
$ sgit branch merge feature --merge lines
$ export SGIT_MERGE_STYLE=lines                   # per session; or merge_style in .sg_vault/local/config.json
```

- **How a file both sides changed is merged:**
  - changes to different lines merge cleanly;
  - lines both sides changed get Git's markers in the file: `<<<<<<< ours (this clone …)`, `=======`, `>>>>>>> theirs (current …)`.
- **Only files both sides changed are line-merged,** so work in separate folders costs nothing more.
- **Fall back to the whole-file `.conflict`, and the pull says why:**
  - binary files;
  - files over 8 MiB;
  - versions this clone does not hold.
- **Resolving a conflict:**
  - edit the markers out and `sgit commit`; commit refuses while a marker block remains;
  - `sgit resolve <file> --ours` or `--theirs` takes one side;
  - `sgit resolve <file>` marks a hand edit as resolved.
- **The default is unchanged:** without the flag, a pull keeps yours and writes theirs to `<file>.conflict`, as before and as the web UI does. The flag wins over the session and the clone setting.
- **Safety:**
  - an uncommitted edit to a file that would get markers refuses the pull before anything is written;
  - marker labels come from vault data and can never start a line;
  - marker files are written through the path guard.

## Compatibility {#compat}

No format change and no gate. A line-merged result is an ordinary commit, which every client reads.

## Review by cli.build {#review}

**Verdict: good for an opt-in feature.**
- On unique lines, the engine is Git's: every one of 8,925 random merges was byte-identical to `git merge-file -p`, in both styles.
- Where lines repeat, as `}`, blank lines and `return x;` do in code, it can occasionally disagree with Git about whether two changes touch.
- In 2 of 4,544 code-like merges, that turned a Git conflict into a silent clean merge (BR-2).
- **Agents using `--merge lines` should read the merged files before pushing,** as they would review any merge.

```text
┌─ line merge vs git merge-file · 18,000 random three-way merges, 4 seeds ─────────────
│ verdict                          unique     code-like   3-letter alphabet
│ byte-identical                    8,925        4,501         4,209
│ both conflict, blocks differ          0           41           258    ── BR-3
│ sgit conflict, git clean              0            0            36
│ sgit clean, git conflict              0            2            23    ── BR-2
│ both clean, bytes differ              0            0             5
├──────────────────────────────────────────────────────────────────────────────────────
│ ✓ X1 different lines merge   ✓ X2 markers; commit refuses   ✓ X3 default unchanged
│ ✓ X4 an edit that would get markers refuses the pull, edit kept
└──────────────────────────────────────────────────────────────────────────────────────
  code-like: 60% of lines from {"}", "", "{", "    return x;", "    i++;", "else", …}
  3-letter: every line is a, b or c, the worst case for any line differ
```

### BR-2 (medium, opt-in): a clean merge where Git reports a conflict, when lines repeat {#br-2}

**Why it happens:**
- The engine is a port of xdiff's merge, run on sgit's own Myers differ, plus Git's change compaction.
- When the changed region is surrounded by repeated lines, the two differs can place a change one line apart.
- Changes that touch in Git's placement then do not touch in sgit's, so sgit merges where Git asks.
- The CHANGELOG's claim is scoped correctly ("byte-identical … on random merges of unique lines"). The property agents care about is different: "sgit never merges silently what Git would ask about". That one does not hold.

**One of the two code-like cases,** seed 4, diff3:

```text
base                ours                       theirs
line 34408          line 34413                 line 34408
{                   line 34412                 {
end                 {                          end
if (a) {            if (a) {                   if (a) {
line 34409          line 34408
                    {
                    end
                    line 34409
                    line 34414
                    if (a) {

git merge-file: a conflict around "line 34409"; theirs deleted it, ours moved "if (a) {" past it
sgit:           clean, = ours, so "line 34409", which theirs deleted, is still there
```

Either reading is a valid alignment. Git's is the one users expect.

**For the CLI team's agent,** in order of cost:
1. **Conservative rule.** Treat two one-sided changes as touching when the base lines between them, or within one line of them, are not unique in the base. A clean result then needs unambiguous context. It costs a few more conflicts and no silent merges. Re-run [`fuzz_line_merge.py`](https://github.com/SGit-AI/SGit-AI__Website__Cli/tree/dev/admin/research/builds-0-26-x-2026-10-28/scripts): the target is 0 in the "sgit clean, git conflict" row.
2. **Exact placement.** Port the rest of xdiff's diff (`xdl_recs_cmp` with its split heuristics and `XDF_NEED_MINIMAL` off), so that hunks land where Git puts them on repeated lines too. More work, and it also closes BR-3.
3. **Add the repeated-line generators** (the "code" and "tiny" kinds in the fuzzer) to the CLI's own tests against `git merge-file`.

### BR-3 (low): conflict blocks drawn differently from Git's {#br-3}

Where both report a conflict, the blocks differ in 41 of 4,544 code-like merges (0.9%): where a block starts and ends, or how many blocks there are. The content is not lost either way. Exact placement (BR-2, option 2) fixes this too.

*Scripts: `fuzz_line_merge.py <seed> <cases> [merge|diff3]`, `check_build.py`. Results: `results/lm_*.json` with up to three samples per verdict, and `results/check_0.26.5.json`. All builds: [the builds page](../builds/index.md).*

---

*[Site index for agents](../llms.txt) · [HTML version](https://cli.sgit.ai/builds/0-26-5.html)*
