chat.useCustomizationsInParentRepositories does not discover customizations through Git worktree .git files
- Dominant language
- TypeScript
- Stars
- 193k
- Forks
- 42.4k
- PR merge metrics
- PR metrics pending
Description
Does this issue occur when all extensions are disabled?: No — this is specific to the GitHub Copilot Chat extension's `chat.useCustomizationsInParentRepositories` setting.
- VS Code Version: 1.136.1
- OS Version: Windows 11 Enterprise 10.0.26200
- Copilot Chat Extension Version: 0.64.1
## Summary
`chat.useCustomizationsInParentRepositories` fails to discover `.github/agents`, `.github/instructions`, `AGENTS.md`, etc. from the enclosing repository when the workspace folder is inside a **git worktree**. This is a related-but-distinct case from the submodule scenario (issue #329169, fixed by PR #332893) — the fix for submodules (continue traversal past a `.git` file) does not generalize to worktrees, because a worktree's real `.git` directory is not an ancestor of the worktree path at all.
## Root Cause
In `findParentRepoFolders()` ([`src/vs/workbench/contrib/chat/common/promptSyntax/utils/promptFilesLocator.ts`](https://github.com/microsoft/vscode/blob/55066f633a1243f528d13076137b7db073dda9cf/src/vs/workbench/contrib/chat/common/promptSyntax/utils/promptFilesLocator.ts), mirrored in [`extensions/copilot/src/platform/promptFiles/vscode-node/agentInstructionsLocator.ts`](https://github.com/microsoft/vscode/blob/55066f633a1243f528d13076137b7db073dda9cf/extensions/copilot/src/platform/promptFiles/vscode-node/agentInstructionsLocator.ts)), a repository root is only recognized when `.git` is a **directory**:
```ts
const gitStat = await this.fileService.stat(joinPath(current, '.git')).then(stat => stat, () => undefined);
const isRepoRoot = gitStat?.isDirectory === true;
```
When `isRepoRoot` is `false`, the walk continues to the parent folder (this is the behavior added by #332893 to support submodules).
For a **submodule**, this works because the real `.git` directory is a direct ancestor:
```
superproject/.git/ ← real directory, 1 level up
superproject/submodule/.git ← file (gitlink)
```
For a **worktree**, the real `.git` directory is *not* an ancestor — it lives in a completely separate location (the original clone), pointed to sideways via the `gitdir:` pointer:
```
C:\repo\.git ← real directory, NOT an ancestor of the worktree path
C:\repo.worktrees\my-branch\.git ← file: "gitdir: C:/repo/.git/worktrees/my-branch"
```
No amount of walking up parent directories from the worktree folder will ever reach `C:\repo\.git`, so `findParentRepoFolders` returns `[]`, and the setting silently contributes nothing for workspaces opened inside a worktree.
Interestingly, the codebase already contains logic elsewhere to resolve a worktree's `.git` file pointer (e.g. `src/vs/workbench/contrib/chat/browser/actions/chatContinueInAction.ts` has a comment `// Git worktree — .git is a file with "gitdir: "` and resolves it), so the primitive for detecting/resolving worktree gitdirs exists in the codebase but isn't used by `findParentRepoFolders`.
## Steps to Reproduce
1. Clone a repository normally, e.g. `git clone C:\repo`.
2. Create a worktree for a branch: `git worktree add C:\repo.worktrees\my-branch my-branch` (run from inside `C:\repo`).
3. Add a custom agent at `C:\repo.worktrees\my-branch\.github\agents\my-agent.agent.md`.
4. Open a **subfolder** of the worktree directly in VS Code — not the worktree root itself, e.g. `C:\repo.worktrees\my-branch\src` (this matters: opening the worktree root itself works fine, because `.github` is then a direct child of the opened folder and no parent-repository lookup is needed at all).
5. Trust the workspace.
6. Enable:
```json
{
"chat.useCustomizationsInParentRepositories": true
}
```
7. Open the Copilot Chat agent picker.
Alternate reproduction: instead of step 4, open a **multi-root `.code-workspace`** whose folders are subfolders of the worktree (rather than the worktree root itself) — a common layout for larger repositories that split source, docs, and tooling into separate workspace folders. The same failure occurs for each workspace folder.
## Expected Behavior
The custom agent (or `AGENTS.md` / `copilot-instructions.md` / instructions files) defined at `/.github/...` is discovered by walking up from the opened subfolder to the worktree root, the same way it would be discovered from an ordinary subfolder of a non-worktree clone.
## Actual Behavior
The custom agent/customization is not discovered. Verified via the debug logs (`debug-logs//main.jsonl`, `Agent Discovery` event) that the scanned folder list only contains `/.github/agents` for the opened subfolder itself — no parent-repository root was added — and confirmed the worktree root's `.git` is a small text file (not a directory) containing:
```
gitdir: C:/repo/.git/worktrees/my-branch
```
## Additional Notes
- This is not fixed by #332893 (which correctly fixes the analogous submodule scenario) — the walk-up strategy used there cannot work for worktrees since the real `.git` directory isn't in the parent chain.
- A workaround is possible by resolving the `gitdir:` pointer in the `.git` file when it is *not* a directory, extracting the common repository root (see `.git/worktrees/` → strip `/worktrees/` to get the common `.git` directory → its parent is the repo root), similar to what `chatContinueInAction.ts` already does elsewhere in the codebase.
Contributor guide
Assessment
This issue has not been assessed yet.