Skip to content

hooks: resolve enlistment root for worktrees outside enlistment tree#1979

Open
tyrielv wants to merge 1 commit into
microsoft:masterfrom
tyrielv:tyrielv/worktree-remote-placement
Open

hooks: resolve enlistment root for worktrees outside enlistment tree#1979
tyrielv wants to merge 1 commit into
microsoft:masterfrom
tyrielv:tyrielv/worktree-remote-placement

Conversation

@tyrielv
Copy link
Copy Markdown
Contributor

@tyrielv tyrielv commented May 19, 2026

Summary

All native hooks (virtual-filesystem, read-object, post-index-changed) and managed hooks (GVFS.Hooks) resolved the primary enlistment root by walking up from CWD looking for a .gvfs/ directory. Worktrees placed outside the enlistment directory tree (e.g. in a temp directory or as a sibling) could not use git commands — hooks failed with 'must be run from inside a GVFS enlistment'.

Fix

Added a worktree fallback path: when .gvfs walk-up fails, walk up looking for a .git file (indicating a linked worktree), then resolve the primary enlistment root through the gitdir chain — first from the gvfs-enlistment-root marker file, then by deriving from commondir. The resolved root is validated by checking that .gvfs/ exists.

Native hooks (common.windows.cpp)

  • Extract ReadFirstLine, Utf8ToWide, TryParseGitFile helpers
  • Refactor GetWorktreePipeSuffix to use shared helpers
  • Add TryResolveFromWorktree returning both enlistment root and pipe suffix
  • GetGVFSPipeName tries .gvfs walk-up first, then worktree fallback

Managed hooks (Program.cs)

  • After TryGetGVFSEnlistmentRoot fails, try TryGetWorktreeInfoGetEnlistmentRoot() before exiting
  • Validate .gvfs exists at the resolved root

Testing

  • 3 unit tests for GetEnlistmentRoot (marker file, SharedGitDir fallback, marker-preferred)
  • Functional test creating worktree in temp directory, verifying git status from root and subdirectory, file projection, and commits
  • All 806 unit tests pass

@tyrielv tyrielv force-pushed the tyrielv/worktree-remote-placement branch from 13a70d3 to 915fe80 Compare May 19, 2026 20:47
All native hooks (virtual-filesystem, read-object, post-index-changed)
and managed hooks (GVFS.Hooks) resolved the primary enlistment root by
walking up from CWD looking for a .gvfs/ directory. This meant worktrees
placed outside the enlistment directory tree (e.g. in a temp directory
or as a sibling) could not use git commands — the hooks would fail with
'must be run from inside a GVFS enlistment'.

Fix by adding a worktree fallback path: when .gvfs walk-up fails, walk
up looking for a .git file (indicating a linked worktree), then resolve
the primary enlistment root through the gitdir chain — first from the
gvfs-enlistment-root marker file, then by deriving from commondir.
The resolved root is validated by checking that .gvfs/ exists there.

Native hooks (common.windows.cpp):
- Extract ReadFirstLine, Utf8ToWide, TryParseGitFile helpers
- Refactor GetWorktreePipeSuffix to use shared helpers
- Add TryResolveFromWorktree that returns both enlistment root and
  pipe suffix
- GetGVFSPipeName tries .gvfs walk-up first, then worktree fallback

Managed hooks (Program.cs):
- After TryGetGVFSEnlistmentRoot fails, try TryGetWorktreeInfo ->
  GetEnlistmentRoot() before exiting
- Validate .gvfs exists at the resolved root

Tests:
- Unit tests for GetEnlistmentRoot with marker file, SharedGitDir
  fallback, and marker-preferred scenarios
- Functional test creating worktree in temp directory, verifying
  git status from root and subdirectory, file projection, commits

Assisted-by: Claude Opus 4.6
Signed-off-by: Ty Larrabee <tyrielv@gmail.com>
@tyrielv tyrielv force-pushed the tyrielv/worktree-remote-placement branch from 915fe80 to 4c69e85 Compare May 19, 2026 21:00
@tyrielv tyrielv marked this pull request as ready for review May 20, 2026 18:34
@tyrielv tyrielv requested a review from KeithIsSleeping May 20, 2026 18:34
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