Skip to content

fix(opencode): evict gitignored files from shadow snapshot index#24059

Closed
autopilotgrowth wants to merge 1 commit intoanomalyco:devfrom
autopilotgrowth:fix/snapshot-gitignore
Closed

fix(opencode): evict gitignored files from shadow snapshot index#24059
autopilotgrowth wants to merge 1 commit intoanomalyco:devfrom
autopilotgrowth:fix/snapshot-gitignore

Conversation

@autopilotgrowth
Copy link
Copy Markdown

Refs #20695 (memory megathread — the "files staged before being added to .gitignore stay forever" case described by @thdxr).

Problem

add() only ran check-ignore against files that were in the current source candidate set (diff-files + ls-files --others --exclude-standard). Once a file was staged in the shadow repo on an early turn, then added to .gitignore but not modified afterwards, it fell out of both candidate lists — so the existing ignore() / drop() path never saw it.

It stayed in the shadow index forever, got rehashed into every write-tree, and bloated memory when sessions with large ex-untracked directories (node_modules, .android-sdk, .venv, …) were resumed.

Fix

Also list the shadow repo's currently-cached paths with git ls-files --cached, union them into the ignore() check, and let the existing drop() call evict anything that now matches. One extra git call per track(), negligible for sane repos, and it finally lets the user recover memory by just adding the offender to .gitignore without needing to wipe ~/.local/share/opencode/snapshot.

Verification

New test "untracked files retroactively gitignored are evicted from shadow index" reproduces the bug: cache/big.bin and cache/other.bin get staged in the first track(), cache/ is added to .gitignore, the files are not touched, and the second track() ought to drop them. I confirmed the test fails against dev and passes with this change. It inspects the shadow tree directly via git ls-tree -r because diffFull (correctly) filters gitignored paths from the user-facing diff, hiding the very rows we need to assert on.

Full snapshot suite still passes (52 pass, 1 skip, 1 pre-existing chmod-not-found failure on Windows that also fails on clean dev).

add() only ran check-ignore against files that were in the current source
candidate set (diff-files + ls-files --others --exclude-standard). Once a
file was staged and later added to .gitignore but not modified, it fell
out of both candidate lists, so the existing ignore()/drop() path never
saw it. It stayed in the shadow index forever, got rehashed on every
write-tree, and bloated memory when sessions with large ex-untracked
directories (node_modules, .android-sdk, .venv, etc.) were resumed.

Union the shadow repo's cached paths into the ignore check so any file
that matches current .gitignore or info/exclude is dropped regardless of
whether it also appears in the source repo's candidate set.

Refs anomalyco#20695 (memory megathread)
@github-actions github-actions Bot added needs:issue needs:compliance This means the issue will auto-close after 2 hours. labels Apr 23, 2026
@github-actions
Copy link
Copy Markdown
Contributor

Thanks for your contribution!

This PR doesn't have a linked issue. All PRs must reference an existing issue.

Please:

  1. Open an issue describing the bug/feature (if one doesn't exist)
  2. Add Fixes #<number> or Closes #<number> to this PR description

See CONTRIBUTING.md for details.

@github-actions
Copy link
Copy Markdown
Contributor

This PR doesn't fully meet our contributing guidelines and PR template.

What needs to be fixed:

  • PR description is missing required template sections. Please use the PR template.

Please edit this PR description to address the above within 2 hours, or it will be automatically closed.

If you believe this was flagged incorrectly, please let a maintainer know.

@github-actions
Copy link
Copy Markdown
Contributor

This pull request has been automatically closed because it was not updated to meet our contributing guidelines within the 2-hour window.

Feel free to open a new pull request that follows our guidelines.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant