Skip to content

fix: resolve the git repository from cwd instead of the inherited environment - #2255

Open
dylanpulver wants to merge 2 commits into
changesets:mainfrom
dylanpulver:fix/git-env-in-worktree
Open

fix: resolve the git repository from cwd instead of the inherited environment#2255
dylanpulver wants to merge 2 commits into
changesets:mainfrom
dylanpulver:fix/git-env-in-worktree

Conversation

@dylanpulver

@dylanpulver dylanpulver commented Aug 19, 2026

Copy link
Copy Markdown

Fixes #2027

The environment variable alone reproduces it, no hook or worktree needed:

npx changeset status --since=origin/main                                       # works
GIT_DIR=$(git rev-parse --git-dir) npx changeset status --since=origin/main    # fails

Git runs hooks with GIT_DIR pointing at the worktree-specific git directory and does not set GIT_WORK_TREE (an ordinary checkout gets neither, which is why only worktree pushes are affected). With GIT_DIR set and GIT_WORK_TREE unset, git treats cwd itself as the work tree root. Calls in @changesets/git pass cwd but inherit the environment, so the inherited GIT_DIR wins. filterChangesetsSinceRef passes cwd as the .changeset directory, so git diff --name-only --diff-filter=d looks for each committed path under .changeset/<path>, finds nothing, classifies every file as deleted, and filters them all out.

The fix

The exec wrapper strips the inherited variables that would redirect git away from the repository containing cwd. Routing every call through one helper covers the other git-shelling commands, not just the one in the report. tinyexec merges with process.env, so variables are dropped by overriding with undefined; keys match case-insensitively for Windows.

Only GIT_DIR is needed for this bug. I included the rest of the repository/work-tree/object-store/index set because leaving them keeps the same failure alive for a pre-commit hook that sets GIT_INDEX_FILE. Happy to narrow. packages/release-utils/src/gitUtils.ts spawns git the same way and I left it alone, since it runs in the action on an ordinary checkout where neither variable is set.

Alternatives rejected

Setting GIT_WORK_TREE alongside the inherited GIT_DIR, as the issue suggests, is circular: finding the correct value needs the real worktree root, and asking git for it needs an already-correct environment. Setting it to cwd is wrong in exactly the failing case.

Honouring the pair when a caller sets both is not coherent: @manypkg/get-packages reads package.json from cwd regardless, so a GIT_WORK_TREE pointing elsewhere means git and the filesystem disagree about which project is being inspected.

Fixing it locally in @changesets/read would leave the wrapper sensitive to GIT_INDEX_FILE, and any future caller passing a subdirectory would reintroduce it.

Testing

Three tests in packages/git/src/index.test.ts, all red on main: getCurrentCommitId reporting the cwd repository's HEAD rather than the one GIT_DIR points at, and getChangedChangesetFilesSinceRef finding the changeset both with cwd at .changeset and in a real git worktree add worktree.

End to end, a real pre-push hook running changeset status --since=origin/main from a worktree rejects the push on main and succeeds here, same commit and hook. pnpm types:check, pnpm lint, pnpm format clean; git, read and status suites pass. The pack/publish e2e snapshot tests fail for me, but identically on main with the same counts, so that is my local package manager versions. Changeset included.

@netlify

netlify Bot commented Aug 19, 2026

Copy link
Copy Markdown

Deploy Preview for changesets ready!

Name Link
🔨 Latest commit f185876
🔍 Latest deploy log https://app.netlify.com/projects/changesets/deploys/6a863248e7a3b000089ee828
😎 Deploy Preview https://deploy-preview-2255--changesets.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@changeset-bot

changeset-bot Bot commented Aug 19, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: f185876

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 6 packages
Name Type
@changesets/git Patch
@changesets/apply-release-plan Patch
@changesets/cli Patch
@changesets/read Patch
@changesets/release-utils Patch
@changesets/get-release-plan Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@codecov

codecov Bot commented Aug 19, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.45455% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 84.73%. Comparing base (bed4581) to head (f185876).

Files with missing lines Patch % Lines
packages/git/src/index.ts 95.45% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2255      +/-   ##
==========================================
+ Coverage   84.53%   84.73%   +0.20%     
==========================================
  Files          80       80              
  Lines        3168     3177       +9     
  Branches      890      893       +3     
==========================================
+ Hits         2678     2692      +14     
+ Misses        433      428       -5     
  Partials       57       57              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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.

status --since=<ref> reports no changesets when invoked from a pre-push hook inside a git worktree

1 participant