Skip to content

fix worktree mounts using primary enlistment's .gvfs paths#1998

Open
tyrielv wants to merge 1 commit into
microsoft:masterfrom
tyrielv:tyrielv/fix-worktree-db-path
Open

fix worktree mounts using primary enlistment's .gvfs paths#1998
tyrielv wants to merge 1 commit into
microsoft:masterfrom
tyrielv:tyrielv/fix-worktree-db-path

Conversation

@tyrielv
Copy link
Copy Markdown
Contributor

@tyrielv tyrielv commented Jun 2, 2026

Problem

Worktree mounts shared the primary enlistment's .gvfs metadata (placeholder database, RepoMetadata, diagnostics, corrupt objects) instead of using their own per-worktree .gvfs directory.

Symptoms: after git reset --hard in a worktree, fully-materialized files retained stale content because placeholder tracking was shared with the primary mount. The skip-worktree bit hid the stale content from git status/git diff.

Root cause: code throughout the codebase derived .gvfs paths from EnlistmentRoot, which always resolves to the primary enlistment root -- even for worktree mounts. The correct property is DotGVFSRoot, which resolves to the per-worktree .gvfs for worktree mounts.

Fix

Product fixes

  • GVFSDatabase: accept dotGVFSRoot directly instead of deriving from EnlistmentRoot; update all call sites
  • GitRepo: resolve DotGVFSRoot at construction for corrupt object paths
  • GVFSVerb.InitializeLocalCacheAndObjectsPaths: use DotGVFSRoot for RepoMetadata (affects dehydrate, prefetch)
  • DiagnoseVerb: use DotGVFSRoot for .gvfs file collection and RepoMetadata
  • CacheVerb: use DotGVFSRoot for RepoMetadata
  • RequiredGitConfig: narrow parameter to GVFSEnlistment, use DotGVFSRoot
  • GVFSLogsRoot: derive from DotGVFSRoot instead of re-deriving
  • GitMaintenanceStep: check WorkingDirectoryRoot for existence
  • HooksInstaller: use WorkingDirectoryRoot in error messages

Rename to prevent recurrence

Rename Enlistment.EnlistmentRoot to PrimaryEnlistmentRoot, forcing every caller to explicitly choose the right path property. Audit of all ~280 references across ~75 files confirmed each usage is correct.

Test

Added WorktreeUsesPerWorktreePlaceholderDatabase functional test: creates a worktree outside the enlistment tree, materializes a file, and verifies the per-worktree VFSForGit.sqlite contains placeholder entries.

Validation

  • Unit tests: 807 passed, 0 failed
  • All projects compile clean (GVFS, GVFS.Common, GVFS.Mount, GVFS.Service, GVFS.Hooks, FastFetch, UnitTests)

@tyrielv tyrielv force-pushed the tyrielv/fix-worktree-db-path branch 2 times, most recently from 51724bd to a9d689d Compare June 2, 2026 21:03
@tyrielv tyrielv changed the title database: use DotGVFSRoot for per-worktree placeholder DB path fix worktree mounts using primary enlistment's .gvfs paths Jun 2, 2026
@tyrielv tyrielv marked this pull request as ready for review June 2, 2026 21:10
Worktree mounts shared the primary enlistment's .gvfs metadata
(placeholder database, RepoMetadata, diagnostics, corrupt objects)
instead of using their own per-worktree .gvfs directory. This caused
stale file content after git reset --hard in worktrees, because
placeholder tracking was shared with the primary mount.

Root cause: code throughout the codebase derived .gvfs paths from
EnlistmentRoot, which always resolves to the primary enlistment root
even for worktree mounts. The correct property is DotGVFSRoot, which
resolves to the per-worktree .gvfs for worktree mounts and the
primary .gvfs for primary mounts.

Product fixes:
- GVFSDatabase: accept dotGVFSRoot directly instead of deriving from
  EnlistmentRoot; update InProcessMount, SparseVerb, DiskLayoutUpgrade,
  EnlistmentPathData, ProfilingEnvironment call sites
- GitRepo: resolve DotGVFSRoot at construction for corrupt object paths
- GVFSVerb.InitializeLocalCacheAndObjectsPaths: use DotGVFSRoot for
  RepoMetadata (affects dehydrate, prefetch)
- DiagnoseVerb: use DotGVFSRoot for .gvfs file collection and
  RepoMetadata initialization
- CacheVerb: use DotGVFSRoot for RepoMetadata
- RequiredGitConfig: narrow parameter to GVFSEnlistment, use DotGVFSRoot
- GVFSLogsRoot: derive from DotGVFSRoot instead of re-deriving
- GitMaintenanceStep: check WorkingDirectoryRoot for existence
- HooksInstaller: use WorkingDirectoryRoot in error messages

Rename to prevent recurrence:
- Rename Enlistment.EnlistmentRoot to PrimaryEnlistmentRoot, forcing
  every caller to explicitly choose the right path property. Audit of
  all ~280 references across ~75 files confirmed each usage is correct.

Test:
- Add WorktreeUsesPerWorktreePlaceholderDatabase functional test

Assisted-by: Claude Opus 4.6
Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
@tyrielv tyrielv force-pushed the tyrielv/fix-worktree-db-path branch from a9d689d to 656e3a1 Compare June 2, 2026 21:53
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.

1 participant