[BUG] git-subdir plugin install leaks sparse-checkout into the session's working repo, silently collapsing the tree
Summary
Installing or refreshing a plugin whose marketplace source is git-subdir runs git sparse-checkout set --cone <path> that is not scoped to its temp clone — it also applies to the git repository at the session's current working directory. That sets core.sparseCheckout=true plus a cone pattern for the plugin's subpath (e.g. providers/claude/plugin) on the user's own project worktree, so every file outside that (nonexistent-in-this-repo) path silently disappears from the working tree. No error is shown.
Impact
- The user's working tree collapses —
src/,.claude/, etc. vanish, with exit-0 git behavior. It looks like data loss / a broken checkout. - While sparse-checkout is active, a plain
git add <path>silently refuses to stage paths outside the cone (it's only a hint, exit stays 0), so a subsequentgit commit --amend/ push can ship incomplete content without warning. - Hits multi-worktree tooling (Conductor, plain
git worktree) hardest, because the session cwd is a real repo. It recurs on every marketplace re-sync.
Environment
- Claude Code v2.1.156
- macOS 26.3.1 (Darwin 25.3.0), Apple Silicon
- Trigger plugin:
stripe@claude-plugins-official, source:
``json``
{"source":"git-subdir","url":"https://github.com/stripe/ai.git","path":"providers/claude/plugin","ref":"main","sha":"a34795211da530a168f581122011bb5ceb2e4bd0"}
- Sessions running inside Conductor-managed git worktrees of an unrelated project.
Reproduction
- Open a project in Claude Code where the working directory is a git repo / worktree.
- Install (or let the official marketplace auto-refresh) a plugin with a
git-subdirsource that points at a subpath of an external monorepo — e.g.stripe@claude-plugins-official(github.com/stripe/ai→providers/claude/plugin). - Inspect the project repo (not the plugin cache):
git config core.sparseCheckout→true<git-dir>/info/sparse-checkoutnow contains a cone pattern forproviders/claude/plugin— a path that does not exist in the project.
- All files outside that path are gone from the working tree.
Evidence
- The polluting
<project-worktree>/.git/.../info/sparse-checkoutis byte-identical to the plugin's temp clone at~/.claude/plugins/cache/temp_subdir_*.clone/.git/info/sparse-checkout— i.e. the samegit sparse-checkoutoperation wrote both. - Only repositories that were the session cwd during a
git-subdirinstall/refresh are affected. The plugin's own temp clone is correct. Other source types never touch sparse-checkout and never leak: source: "./plugins/<name>"(a subfolder of the already-cloned marketplace repo) → no fetch, no sparse.- whole-repo
github/urlsources → plain clone, no sparse. - Reproduced across three separate worktrees of the same project; never affected the non-Conductor main checkout (which wasn't a session cwd when a
git-subdirinstall ran).
Root cause (inferred — harness is closed source)
The git-subdir fetch path's git sparse-checkout invocation runs against the inherited process working directory instead of being confined to the temp clone directory.
Suggested fix
Scope every git operation in the git-subdir fetch to the temp clone directory — e.g. git -C <tempCloneDir> sparse-checkout … (or set the child process cwd to the temp dir) — so a plugin install can never mutate the user's working repository. Optionally assert the target repo is the temp dir before running sparse-checkout.
Workaround
In the affected repo:
git sparse-checkout disable
rm -f "$(git rev-parse --git-dir)/info/sparse-checkout"
Recurs on the next marketplace refresh until fixed.
Related
- #58199 —
git-subdirinstall creates an empty destination directory. Same install path, different symptom; suggests this code path is fragile. - #40864 / #28426 — the "use sparse checkout for plugin installs" feature this mis-scopes.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗