microsoft / microsoft/vscode

chat.useCustomizationsInParentRepositories does not discover customizations through Git worktree .git files

Open
#334,728 0 comments 0 reactions 1 assignee Assigned to @aeschli View on GitHub
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.