Skip to content

fix(hooks): decline when a worktree has no dependencies - #1095

Open
chappie-daemon wants to merge 1 commit into
rewrite/mainfrom
fix/husky-hooks-in-worktrees
Open

chappie-daemon wants to merge 1 commit into
rewrite/mainfrom
fix/husky-hooks-in-worktrees

Conversation

@chappie-daemon

Copy link
Copy Markdown
Collaborator

What was wrong

A factory worktree cannot commit. git worktree add does not run prepare, so the new checkout has neither .husky/_ nor node_modules, and the first line of both hooks aborts:

$ git commit -q --allow-empty -m probe
.husky/pre-commit: 2: .: cannot open .husky/_/husky.sh: No such file
rc=1

sh exits a non-interactive script when a . fails, so no gate ever runs and the commit never happens. The workaround every agent finds is --no-verify, which skips the gates the hooks exist to enforce.

Six tool-call rows across 2026-11-06..09 were this failure, from both the primary and job subagents, all inside projects/nostream-worktrees/*.

What this changes

Both hooks now decline when the checkout has nothing to run, and source the shim only when it exists:

[ -d node_modules ] || exit 0
_root=$(dirname -- "$0")
[ -f "$_root/_/husky.sh" ] && . "$_root/_/husky.sh"

A checkout that can run its gates is unchanged: pnpm run lint, build:check, test:unit and commitlint still run, and still block on failure.

Verified in a fresh worktree off this base

state before after
no node_modules, no .husky/_ rc=1, no commit rc=0, commit lands
node_modules + .husky/_ present shim runs shim runs (HOOK-RAN), pnpm run lint executes

Out of scope

The deeper cause is that a worktree is expected to install before committing. Making prepare run per worktree would put a full dependency install on every factory job, so declining is the cheaper and more honest behaviour for a checkout with no dependencies: there is nothing for the gates to check against.

`git worktree add` never runs `prepare`, so a factory worktree arrives with
neither `.husky/_` nor `node_modules`; the `. _/husky.sh` source then aborted
every commit with rc 1 before any gate ran. Six tool-call rows across four days
were that failure, each paid as a discovery of `--no-verify`.

Both hooks now decline when there are no dependencies to lint or test, and
source the shim only when it exists. A checkout that can run its gates runs
them unchanged - verified in a fresh worktree: commit rc 0 with no deps, and
the shim plus `pnpm run lint` still ran once they were present.
@changeset-bot

changeset-bot Bot commented Nov 9, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: f709124

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

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

@coderabbitai

coderabbitai Bot commented Nov 9, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: be4c716c-01f6-4413-a070-0370e4da6879

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

@greptile-apps

greptile-apps Bot commented Nov 9, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 4/5

[Medium impact] The change affects commit checks in this repository's developer workflow.

Fix the missing-shim path in pre-commit before merging so failed lint still blocks commits.

Findings

  1. P1 Failed lint allows commits ▶

Summary

Both hooks now allow commits when node_modules is absent and source the Husky shim only when it exists.

  • Commit hooks let worktrees proceed when dependencies are missing.

Reviews (1) · Last reviewed commit: "fix(hooks): decline when a worktree has ..." · Reviewed by Greptile

Comment thread .husky/pre-commit
# cannot: a checkout without dependencies has no gates to fail.
[ -d node_modules ] || exit 0
_root=$(dirname -- "$0")
[ -f "$_root/_/husky.sh" ] && . "$_root/_/husky.sh"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Failed lint allows commits

If node_modules exists but .husky/_/husky.sh does not, pre-commit now runs without stopping on a failed command. This can happen in a worktree with linked dependencies or dependencies installed without prepare. If pnpm run lint fails but the build and tests pass, the hook returns success and allows the commit. Enable set -e after the optional shim or check each command's result explicitly.

Suggested change
[ -f "$_root/_/husky.sh" ] && . "$_root/_/husky.sh"
[ -f "$_root/_/husky.sh" ] && . "$_root/_/husky.sh"
set -e

This branch has not been deployed

No deployments
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