Skip to content

git: discover worktrees when opening a worktree directory (#264209)#309321

Open
marcelsafin wants to merge 1 commit intomicrosoft:mainfrom
marcelsafin:fix/git-worktree-detect-from-worktree
Open

git: discover worktrees when opening a worktree directory (#264209)#309321
marcelsafin wants to merge 1 commit intomicrosoft:mainfrom
marcelsafin:fix/git-worktree-detect-from-worktree

Conversation

@marcelsafin
Copy link
Copy Markdown

@marcelsafin marcelsafin commented Apr 12, 2026

Summary

When a worktree directory is opened with git.detectWorktrees enabled, checkForWorktrees() previously returned early without discovering the main repository or sibling worktrees. This left worktree management commands non-functional.

Fixes #264209

The Problem

Opening a worktree directory (rather than the main repository) over Remote-SSH with git.detectWorktrees: true results in no worktree commands being available because:

  1. checkForWorktrees() bails out immediately when repository.kind === "worktree"
  2. The main repository is never opened
  3. Commands like "Create Worktree" (repositoryFilter: ["repository", "submodule"]) find no matching repository
  4. "Open Worktree" requires gitOpenRepositoryCount > 1 — not met with only 1 repo
  5. SCM menu items that depend on scmProviderContext == "repository" are hidden

The Fix

Remove the early return for worktree-kind repositories and always filter out the current repository from the worktree candidate list via pathEquals(w.path, repository.root). This:

  • Enables bidirectional discovery: worktree → main repo, and main repo → worktrees
  • Fixes a pre-existing off-by-one: the old code included the current repo in repository.worktrees, wasting a slot in detectWorktreesLimit and triggering the "too many worktrees" warning one entry too early

Safety guarantees:

  • No infinite recursion: getRepositoryExact() short-circuits when a repo is already open
  • Outside-workspace repos allowed: isRepositoryOutsideWorkspace() already recognizes paths in any open repository's worktree list (model.ts L1130-1136)
  • Bare repos handled: getWorktreesFS() excludes the main worktree entry for bare repos
  • Timing safe: worktrees is empty on first call but populated after onDidRunGitStatus, which re-triggers checkForWorktrees()

Also fixes a confusing log message that said detection "is not skipped" when it was in fact skipping.

Copilot AI review requested due to automatic review settings April 12, 2026 21:32
@vs-code-engineering
Copy link
Copy Markdown
Contributor

vs-code-engineering bot commented Apr 12, 2026

📬 CODENOTIFY

The following users are being notified based on files changed in this PR:

@lszomoru

Matched files:

  • extensions/git/src/model.ts

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes Git worktree discovery when opening a worktree directory (instead of the main repository) with git.detectWorktrees enabled, ensuring worktree management commands become available by auto-opening the main repo and sibling worktrees.

Changes:

  • Update worktree auto-discovery logic to consider sibling worktrees + main repo when the opened repository is itself a worktree.
  • Adjust worktree candidate selection to exclude the currently-open worktree from auto-open candidates.
  • Remove/replace a confusing trace message related to worktree detection skipping.

Comment on lines +810 to +814
// When a worktree is opened, discover sibling worktrees and the
// main repository so that worktree management commands are available.
const candidateWorktrees = repository.kind === 'worktree'
? repository.worktrees.filter(w => !pathEquals(w.path, repository.root))
: repository.worktrees;
Copy link

Copilot AI Apr 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

repository.worktrees includes the main worktree entry (path == repository.root) for non-bare repos (see git.ts#getWorktreesFS), so when repository.kind !== 'worktree' this code still counts/opens the current repository as a candidate worktree. This can cause an off-by-one vs detectWorktreesLimit (warning shown too early and one fewer sibling worktree opened) and triggers an unnecessary self-scan. Consider filtering out the current repo path for all kinds (e.g. repository.worktrees.filter(w => !pathEquals(w.path, repository.root))) rather than only when kind === 'worktree'.

Suggested change
// When a worktree is opened, discover sibling worktrees and the
// main repository so that worktree management commands are available.
const candidateWorktrees = repository.kind === 'worktree'
? repository.worktrees.filter(w => !pathEquals(w.path, repository.root))
: repository.worktrees;
// Discover additional worktrees for the repository, but do not
// include the currently opened repository itself.
const candidateWorktrees = repository.worktrees
.filter(w => !pathEquals(w.path, repository.root));

Copilot uses AI. Check for mistakes.
@marcelsafin marcelsafin force-pushed the fix/git-worktree-detect-from-worktree branch from 2557225 to 37e9a50 Compare April 12, 2026 21:38
@marcelsafin marcelsafin requested a review from Copilot April 12, 2026 21:40
@marcelsafin
Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.

if (repository.worktrees.length > worktreesLimit) {
window.showWarningMessage(l10n.t('The "{0}" repository has {1} worktrees which won\'t be opened automatically. You can still open each one individually by opening a file within.', path.basename(repository.root), repository.worktrees.length));
if (candidateWorktrees.length > worktreesLimit) {
window.showWarningMessage(l10n.t('The "{0}" repository has {1} worktrees which won\'t be opened automatically. You can still open each one individually by opening a file within.', path.basename(repository.root), candidateWorktrees.length));
Copy link

Copilot AI Apr 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The warning message says the repository "has {1} worktrees which won't be opened automatically", but the code still opens the first worktreesLimit entries (slice(0, worktreesLimit)). This makes the message/count misleading; consider either reporting the number that will not be opened (e.g. candidateWorktrees.length - worktreesLimit) or rewording to indicate only the first N will be opened automatically.

Suggested change
window.showWarningMessage(l10n.t('The "{0}" repository has {1} worktrees which won\'t be opened automatically. You can still open each one individually by opening a file within.', path.basename(repository.root), candidateWorktrees.length));
window.showWarningMessage(l10n.t('The "{0}" repository has {1} worktrees which won\'t be opened automatically. You can still open each one individually by opening a file within.', path.basename(repository.root), candidateWorktrees.length - worktreesLimit));

Copilot uses AI. Check for mistakes.
When a worktree directory is opened with `git.detectWorktrees` enabled,
`checkForWorktrees()` previously returned early without discovering the
main repository or sibling worktrees. This left worktree management
commands non-functional because:

- Commands like "Create Worktree" filter for repository/submodule kind
- "Open Worktree" requires gitOpenRepositoryCount > 1
- SCM menu items depend on a repository-kind provider being open

Remove the early return for worktree-kind repositories and instead
always filter out the current repository from the candidate list. This
enables bidirectional worktree discovery (worktree → main repo, and
main repo → worktrees) and also fixes a pre-existing off-by-one in the
limit/warning logic where the main repo counted itself as a candidate.

The existing `isRepositoryOutsideWorkspace()` check already allows this
because it recognizes paths that appear in any open repository's worktree
list, and `getRepositoryExact()` prevents duplicate/recursive opens.

Also fixes a confusing log message that said detection "is not skipped"
when it was in fact skipping.

Fixes microsoft#264209

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@marcelsafin marcelsafin force-pushed the fix/git-worktree-detect-from-worktree branch from 37e9a50 to dbc73f7 Compare April 12, 2026 21:44
@marcelsafin marcelsafin requested a review from Copilot April 12, 2026 21:45
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Git Worktree menu does not appear in command palette with git.detectWorktrees enabled over SSH

3 participants