Skip to content

[package-deps-hash] Fix build cache failures in git linked worktrees caused by GIT_DIR set by pre-commit hooks#5815

Open
istateside wants to merge 2 commits into
microsoft:mainfrom
istateside:fix/git-dir-worktree-hook-repo-root
Open

[package-deps-hash] Fix build cache failures in git linked worktrees caused by GIT_DIR set by pre-commit hooks#5815
istateside wants to merge 2 commits into
microsoft:mainfrom
istateside:fix/git-dir-worktree-hook-repo-root

Conversation

@istateside
Copy link
Copy Markdown

@istateside istateside commented Jun 3, 2026

Summary

Fixes build cache failures when Rush commands that trigger incremental build analysis run inside a git linked worktree via a pre-commit hook.

Fixes #5479

When git invokes a pre-commit hook in a linked worktree, it sets GIT_DIR to the per-worktree metadata directory (e.g. .git/worktrees/{name}) but does not set GIT_WORK_TREE. Child processes inherit this environment. getRepoRoot() calls git rev-parse --show-toplevel and inherits this GIT_DIR, causing git to return the currentWorkingDirectory argument (e.g. the rushJsonFolder subdirectory) instead of the actual worktree root. All subsequent git calls use this wrong root, causing git status -u to miss the top-level .gitignore, surfacing node_modules/ symlinks as untracked files, which git hash-object cannot hash — ultimately reported as "Build cache is only supported if running in a Git repository."

Details

The fix strips GIT_DIR and GIT_WORK_TREE from the environment before spawning any git subprocess in getRepoState.ts. This lets git auto-discover the correct repo root by scanning up from currentWorkingDirectory, which correctly resolves to the linked worktree root regardless of the hook-injected environment. Three call sites are patched: getRepoRoot, spawnGitAsync (used by getDetailedRepoStateAsync and hashFilesAsync), and getRepoChanges.

This regression was introduced in #5500, which switched from git ls-tree -r HEAD (reads committed objects, never surfaces node_modules/) to git ls-files --cached + git status -u (scans the work tree, exposing the broken .gitignore context).

The diff also includes prettier reformatting the WINDOWS_RESERVED_BASENAMES array from a compact multi-line form to one-entry-per-line — this is an unrelated side effect of the project's pre-commit hook. Happy to add a // prettier-ignore comment to suppress it if preferred.

How it was tested

Added a unit test to getRepoDeps.test.ts that sets GIT_DIR to a nonexistent path (simulating hook interference) and verifies that getRepoRoot still returns the correct repo root. Without the fix, git rev-parse exits 128 ("not a git repository") and the function throws; with the fix, GIT_DIR is stripped and git auto-discovers the root correctly.

Also manually reproduced the original failure by running a Rush build command from within a git linked worktree via a pre-commit hook and confirmed the build cache error no longer occurs with this fix applied.

Reproduction

The bug can be reproduced with this shell script: https://gist.github.com/istateside/e8b0c5f694424a423ae29fe9203ec895

The script bootstraps a Rush monorepo with all of the requisite contributing factors to recreate the bug:

  1. The repo is a Rush monorepo
  2. The base directory for the Rush monorepo is not the base directory of the git repo (rush.json is not in the root directory of the git repo)
  3. The build cache is enabled
  4. A pre-commit hook runs a Rush command

In that environment, the bug is triggered if you are in a linked worktree and make a commit, to trigger the pre-commit rush command.

@github-project-automation github-project-automation Bot moved this to Needs triage in Bug Triage Jun 3, 2026
@istateside istateside force-pushed the fix/git-dir-worktree-hook-repo-root branch from 7b20309 to 7bfddde Compare June 3, 2026 14:49
Comment on lines +36 to +57
'CON',
'PRN',
'AUX',
'NUL',
'COM1',
'COM2',
'COM3',
'COM4',
'COM5',
'COM6',
'COM7',
'COM8',
'COM9',
'LPT1',
'LPT2',
'LPT3',
'LPT4',
'LPT5',
'LPT6',
'LPT7',
'LPT8',
'LPT9'
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

This change came from the pre-commit prettier script - not sure if my dev environment isn't set up correctly, but I can revert this specific change if needed.

@istateside
Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree company="Squarespace"

@istateside istateside marked this pull request as ready for review June 5, 2026 15:36
… calls to fix build cache in linked worktrees

When a git pre-commit hook runs in a linked worktree, git sets GIT_DIR to the
per-worktree metadata directory (.git/worktrees/{name}) without setting
GIT_WORK_TREE. With GIT_DIR set this way, `git rev-parse --show-toplevel`
returns the CWD (e.g. the rushJsonFolder subdirectory) instead of the actual
worktree root, causing all subsequent git calls to use the wrong root directory.
This makes `git status -u` miss the top-level .gitignore, surfacing node_modules
symlinks as untracked files, which then causes `git hash-object` to fail on
symlink-to-directory entries and ultimately breaks the build cache.

Fix: strip GIT_DIR and GIT_WORK_TREE from the environment in getRepoRoot,
spawnGitAsync, and getRepoChanges so git auto-discovers the correct repo root
from the working directory regardless of hook-injected env vars.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Needs triage

Development

Successfully merging this pull request may close these issues.

[rush] rush build with build cache enabled will crash when a symlink file links to a directory

1 participant