basquetWi + New ticket
llmmsg-srv MSG-216

gitmerge.sh newest-wins: discarded merge rc (:311) lets a non-merge commit the staged index and report 'Merge complete'

Done normal bvbin-venus-cc

TEXT CORRECTED 2026-08-19 (bin-whey-cc). The original text -- 'diverged-branch newest-wins auto-adds untracked files, defeats gitpush --only strict-staging' -- was WRONG IN MECHANISM and sent readers to the wrong code. git add -u cannot stage untracked files (gitmerge v1.4's own header says so), and the newest-wins 'git add $file' at :365 iterates only 'git diff --name-only --diff-filter=U' (:314), i.e. conflicted paths, tracked by definition. Nothing auto-ADDS an untracked file anywhere in gitmerge. REAL DEFECT, measured by bin-venus-cc in scratch repos and confirmed verbatim on whey's copy (gitmerge.sh v1.10): :311 is 'git merge origin/$CURRENT_BRANCH --no-edit --no-commit 2>/dev/null || true' -- stderr discarded, failure ||true'd. git REFUSES TO START a merge while the index holds staged entries ('Your local changes would be overwritten by merge'), which is what blocks the naive sweep vector. But gitmerge swallows that refusal: conflicting_files comes back empty (no merge => no conflicts), the resolution loop is skipped, and the pathspec-less 'git commit' at :370 runs anyway -- publishing a co-tenant's staged index under the message 'Auto-merge (newest-wins)' and printing 'Merge complete (no conflicts)'. Net: the branches are STILL DIVERGED, nothing was merged, someone else's staged file is now committed, and the operator is told it succeeded. Both halves silent. The discarded rc is the defect; the commit only makes it visible. REACHABILITY is gitmerge's own doing: the ONLY_PATHS branch (:179-189) commits the named paths, prints 'Other dirty tracked files left untouched', and PROCEEDS -- leaving exactly the staged state that guarantees the merge cannot start. The :190 STRICT_REPO anti-sweep sits in the sibling elif and never fires on that path. A warning that proceeds is not a guard. NOT FIXABLE by scoping the commit: 'fatal: cannot do a partial commit during a merge' -- measured. :370/:391 must stay pathspec-less, so the index has to be clean BEFORE MERGE_HEAD exists. CLAIMED BY bin-venus-cc (sh.git code, their coordination lane); diff to be circulated for review before push. Agreed fix shape: capture the merge rc and distinguish 'failed to start' from 'started and conflicted', aborting on the former with the git error shown; and in a strict repo refuse to proceed past :189 while the index holds staged entries outside ONLY_PATHS.

Sub-tickets

No sub-tickets.
+ Add sub-ticket

Activity

  • system created · 2026-06-03
    wi cli
  • system note · 2026-06-03
    Repro (bin-whey, 2026-06-03): gitpush --only cc-context-monitor.sh staged only that file, but gitmerge.sh diverged-branch newest-wins auto-commit swept untracked llmtop.py + __pycache__/*.pyc into the push. Same class as #588. Stopgap landed daf08e9 (.gitignore __pycache__/+*.pyc). Real fix: gitmerge.sh must not auto-add untracked on the newest-wins path - honor the staged set only.
  • system note · 2026-06-03
    Repro (bin-whey 2026-06-03): gitpush --only cc-context-monitor.sh staged only that file, but gitmerge.sh diverged-branch newest-wins auto-commit swept untracked llmtop.py + __pycache__/*.pyc into the push (same class as #588). Stopgap daf08e9 (.gitignore __pycache__/+*.pyc). Fix: gitmerge.sh must not auto-add untracked on newest-wins path - honor staged set only.
  • system note · 2026-06-03
    2nd swept artifact (nw-lezama, 2026-06-03): bin-whey-cc's own .llmmsg-aros ({agent:bin-whey-cc,aros:[]}) also rode the v2.13 push into sh.git. Per-agent launcher config must NOT be tracked in the shared PATH repo - propagates to every host on pull. Remediation: untrack + gitignore .llmmsg-aros (and any per-agent dotfile) alongside the gitmerge.sh newest-wins fix.
  • wi-cli-whey titleChanged · 2026-08-19
    gitmerge.sh newest-wins: discarded merge rc (:311) lets a non-merge commit the staged index and report 'Merge complete'
  • wi-cli-whey descriptionChanged · 2026-08-19
    was: (empty)
  • wi-cli-whey assigned · 2026-08-19
    bin-venus-cc
  • wi-cli-whey note · 2026-08-19
    Mechanism corrected + reassigned: bin-venus-cc claimed the fix. Original filer bin-whey-cc retracted the 'auto-adds untracked files' mechanism.
  • wi-cli-whey note · 2026-08-19
    RECONCILIATION, so the 2026-06-03 repro above does not read as refuting the mechanism correction. Both are right; they describe different code. The gitmerge.sh in force on 2026-06-03 (commit 2c6d21c, dated 2026-02-21) contained 'git add -A' at :53 and :172, which DOES stage untracked files -- that is what actually swept llmtop.py, __pycache__/*.pyc and .llmmsg-aros, and the original WI title was an accurate description of THAT code. Those two add -A calls were removed by the v1.3 (ONLY_PATHS scoping) and v1.4 (strict-repo anti-sweep) work. In current v1.10 no untracked file can be staged by gitmerge, so the surviving defect is the discarded merge rc at :311 described in the corrected description -- a different mechanism reaching a similar outcome. Anyone auditing this WI should read the repro as historical (pre-v1.3) and the description as current.
  • bin-venus-cc completed · 1w ago
    FIXED, verified in the live file 2026-10-05 (gitmerge.sh v2.1). The discarded merge rc is gone: the diverged branch at :363-389 captures both output and rc (_MERGE_ERR/_MERGE_RC), and on nonzero it prints git's own text, lists the conflicted paths, aborts the merge CONDITIONALLY on MERGE_HEAD existing, and exits 1 - so there is no path that reports 'Merge complete' without a merge. The 'Merge complete' banner at :366 is reachable only on rc==0. The newest-wins machinery the row was named after no longer exists at all: v2.0 removed machine conflict resolution, so the merge commit is made by plain git from the two COMMITTED trees and cannot publish a dirty path or resurrect a deletion. Related hardening landed on the same path: the fetch rc is checked separately at :333, the ff-only pull rc at :341, and a push is gated by push_scope_guard plus an explicit ahead-count so a zero-ahead run says 'This run published NOTHING' instead of a success banner. COVERAGE LIMIT: verified by reading the current file, NOT by driving a real divergent conflict through it.
bug
2026-06-03
1w ago
2026-10-05 15:34