CB-587: snapshot honours --skip-worktree by seeding the temp index from the real one #69

Closed
agent wants to merge 0 commits from worker/cb587-snapshot-index-flags-24e236-2 into main
Member

Fixes #68.

GitWorktrees.snapshot staged into a fresh, empty temporary index. --skip-worktree is an index flag, so a brand-new index carries none of the worker's real skip-worktree/assume-unchanged bits, and add -A staged those files' local on-disk content anyway -- even though git status --porcelain correctly hides them. Measured on the live daemon: a worktree reporting 2 changed paths produced a snapshot with 15, including .mcp.json (marked never-commit).

Fix: resolve the worktree's real index path via git -C rev-parse --git-path index (never assume /.git/index -- a linked worktree's real index lives under the main repo's worktrees// directory), copy it into the temp index before add -A. Copying preserves every skip-worktree/assume-unchanged bit, so add -A then skips exactly what git status skips. The worker's real index is still never opened for writing; temp index is still removed in a finally; commit is still parented on the worktree's HEAD; ref still under refs/wip/.

If the real index cannot be resolved (e.g. the worktree's .git pointer is broken), resolveRealIndex throws WorktreeException just like every other exec() failure in this class -- SessionManager.trySnapshot already catches and WARNs on any exception from snapshot(), so that existing failure contract (WARN, worktree preserved, pane still stops, nothing propagates out of release()) is unchanged.

Tests added to GitWorktreesTest:

  • dirtySnapshotHonoursARealSkipWorktreeBit -- sets a real --skip-worktree bit via git update-index, diverges the file's on-disk content, and asserts the snapshot's diff against its parent matches git status --porcelain exactly (criteria 1 and 2).
  • snapshotThrowsWhenTheWorktreesRealIndexCannotBeResolved -- breaks the linked worktree's .git pointer and asserts snapshot() throws WorktreeException rather than silently snapshotting from an empty index (criterion 6).

Build: mvn -f bridged/pom.xml clean install, unpiped -- BUILD SUCCESS, Tests run: 766, Failures: 0, Errors: 0, Skipped: 0 (GitWorktreesTest: 15, up from 13).

Fixes #68. GitWorktrees.snapshot staged into a fresh, empty temporary index. --skip-worktree is an index flag, so a brand-new index carries none of the worker's real skip-worktree/assume-unchanged bits, and add -A staged those files' local on-disk content anyway -- even though git status --porcelain correctly hides them. Measured on the live daemon: a worktree reporting 2 changed paths produced a snapshot with 15, including .mcp.json (marked never-commit). Fix: resolve the worktree's real index path via git -C <worktree> rev-parse --git-path index (never assume <worktree>/.git/index -- a linked worktree's real index lives under the main repo's worktrees/<name>/ directory), copy it into the temp index before add -A. Copying preserves every skip-worktree/assume-unchanged bit, so add -A then skips exactly what git status skips. The worker's real index is still never opened for writing; temp index is still removed in a finally; commit is still parented on the worktree's HEAD; ref still under refs/wip/<branch>. If the real index cannot be resolved (e.g. the worktree's .git pointer is broken), resolveRealIndex throws WorktreeException just like every other exec() failure in this class -- SessionManager.trySnapshot already catches and WARNs on any exception from snapshot(), so that existing failure contract (WARN, worktree preserved, pane still stops, nothing propagates out of release()) is unchanged. Tests added to GitWorktreesTest: - dirtySnapshotHonoursARealSkipWorktreeBit -- sets a real --skip-worktree bit via git update-index, diverges the file's on-disk content, and asserts the snapshot's diff against its parent matches git status --porcelain exactly (criteria 1 and 2). - snapshotThrowsWhenTheWorktreesRealIndexCannotBeResolved -- breaks the linked worktree's .git pointer and asserts snapshot() throws WorktreeException rather than silently snapshotting from an empty index (criterion 6). Build: mvn -f bridged/pom.xml clean install, unpiped -- BUILD SUCCESS, Tests run: 766, Failures: 0, Errors: 0, Skipped: 0 (GitWorktreesTest: 15, up from 13).
agent added 1 commit 2026-08-15 15:36:20 +02:00
CB-587: seed the snapshot's temp index from the worktree's real index
CI / build (pull_request) Successful in 1m1s
CI / contract (pull_request) Successful in 1m24s
2db7189067
--skip-worktree is an index flag. GitWorktrees.snapshot staged into a fresh
empty temp index, which carried none of the real index's skip-worktree bits,
so add -A staged local on-disk content for files git status correctly hides
(e.g. .mcp.json). Copy the real index (resolved via git rev-parse --git-path
index, correct for linked worktrees) into the temp index before staging, so
add -A skips exactly what git status skips.
ltms closed this pull request 2026-08-15 16:01:04 +02:00
ltms deleted branch worker/cb587-snapshot-index-flags-24e236-2 2026-08-15 16:01:04 +02:00
Some checks are pending
CI / build (pull_request) Successful in 1m1s
CI / contract (pull_request) Successful in 1m24s

Pull request closed

Sign in to join this conversation.