Skip to content

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

Description

@barbaraliau

Affected Packages

@changesets/cli
@changesets/git

Summary

When a pre-push hook runs changeset status --since=<ref> from inside a git worktree, the command spuriously fails with:

🦋  error Some packages have been changed but no changesets were found. Run `changeset add` to resolve this error.
🦋  error If this change doesn't need a release, run `changeset add --empty`.

The same command run directly from a shell in the same directory succeeds and reports the expected packages-to-be-bumped. Root cause: git invokes hooks with GIT_DIR set to the worktree-specific git directory (e.g., <repo>/.git/worktrees/<name>) but does not set GIT_WORK_TREE. Changesets CLI's internal git diff / git ls-tree invocations then resolve the working tree incorrectly and return an empty list of changed changeset files, even though the .changeset/*.md file is present in HEAD.

Repro (minimal, env-var only)

In any repo with Changesets and an existing changeset file on a feature branch:

# Works
pnpm changeset status --since=origin/main
# 🦋  info Packages to be bumped at minor:
# 🦋  - @your/pkg

# Fails (mimics what git sets for hook processes inside a worktree)
GIT_DIR=$(git rev-parse --git-dir) pnpm changeset status --since=origin/main
# 🦋  error Some packages have been changed but no changesets were found.

# Works again (restores the missing half of the env pair)
GIT_DIR=$(git rev-parse --git-dir) GIT_WORK_TREE=$(pwd) pnpm changeset status --since=origin/main
# 🦋  info Packages to be bumped at minor:
# 🦋  - @your/pkg

The minimal hook reproduction adds the wrinkle that git push sets GIT_DIR automatically inside a worktree, so users hit this without any explicit env setup — only on their non-main worktree pushes, and only when --since=<ref> is used.

Where I traced it

getChangedChangesetFilesSinceRef in @changesets/git spawns:

git diff --name-only --diff-filter=d --no-relative <divergedAt>

With GIT_DIR inherited and GIT_WORK_TREE unset, this returns an empty/incorrect file list — git can't resolve the work tree because GIT_DIR overrides cwd-based discovery but the partner var isn't there to anchor it.

filterChangesetsSinceRef in @changesets/read then filters out every present .changeset/*.md (because none match the now-empty "changed files since ref" set), so changesets.length === 0 and the status command reports "no changesets were found" despite the file being on disk and committed in HEAD.

Suggested fix

In @changesets/git, either:

  1. Unset GIT_DIR in the child git spawns (let git auto-discover from the passed cwd), or
  2. Set GIT_WORK_TREE alongside the inherited GIT_DIR when calling spawn("git", ...).

Option 1 is the more conservative fix and aligns with the existing cwd parameter already being passed to every spawn call. The current code implicitly assumes git will use cwd for working-tree resolution, which holds only when GIT_DIR is also unset or paired with GIT_WORK_TREE.

Environment

  • @changesets/cli 2.31.0 / @changesets/git 3.0.4
  • pnpm 11.1.3, Node 24, macOS / Linux runners
  • Triggered by: git worktree add ../wt -b feature; cd into the worktree; husky pre-push hook running pnpm changeset status --since=origin/main on push.

Workaround for affected users

Push from the main checkout (worktrees share refs, so git push origin feature-branch from the main repo hits the same remote without setting the worktree GIT_DIR). No project-file changes required.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    needs-infoFurther information is requested

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions