Skip to content

chore(scripts): add setup-worktree.sh with copy-on-write node_modules - #388

Closed
kkohtaka wants to merge 1 commit into
masterfrom
claude/worktree-disk-space-issue-2b0e9e
Closed

chore(scripts): add setup-worktree.sh with copy-on-write node_modules#388
kkohtaka wants to merge 1 commit into
masterfrom
claude/worktree-disk-space-issue-2b0e9e

Conversation

@kkohtaka

Copy link
Copy Markdown
Owner

Summary

  • Worktrees under .claude/worktrees/ were filling the disk. The checkout itself is only ~3MB (git objects are shared with the main repo), but npm ci in each worktree costs ~424MB — a handful of accumulated worktrees had reached 858MB against 15GB of free space.
  • scripts/setup-worktree.sh creates a worktree and populates node_modules with cp -c instead, which on APFS clones it copy-on-write: blocks stay shared until npm rewrites a file. Measured on a fresh worktree: 5.2s / 8.6MB of real disk, against ~90s / 424MB for npm ci.
  • Exposed as npm run setup:worktree -- <name> [branch].

Behavior notes for reviewers:

  • New branches are based on origin/master after a git fetch, per the branch rules in CLAUDE.md; an existing branch name is checked out as-is.
  • The main checkout is resolved via --git-common-dir, so the script works when invoked from inside another worktree (where .git is a file).
  • npm install reruns only when the branch's package-lock.json differs from the main checkout's. Note that npm ci would defeat the clone entirely, since it deletes node_modules before reinstalling.

Test plan

  • Ran the script end to end, then npm test inside the created worktree — 48 tests passed, so the cloned node_modules is functional.
  • Verified workspace symlinks (autonyan-shared -> ../src/shared) and node_modules/.bin/* survive the clone as relative links, and that require.resolve('autonyan-shared') resolves into the new worktree rather than the main checkout.
  • Measured real disk consumption via df before/after (8.6MB) rather than du, which reports the full 434MB for CoW clones.
  • npm run lint, the read-only formatting checks, and npm run test:coverage all pass. shfmt -d scripts/*.sh was verified separately via go run since shfmt is not installed locally; tflint could not be run locally either, but this PR changes no Terraform.
  • Removed the verification worktree and its branch afterwards.

🤖 Generated with Claude Code

Worktrees under .claude/worktrees/ were filling the disk: the checkout
itself is ~3MB since git objects are shared, but `npm ci` in each one
costs ~424MB, so a handful of accumulated worktrees reached 858MB.

On APFS, `cp -c` clones the main checkout's node_modules copy-on-write,
sharing blocks until npm rewrites a file. Measured on a fresh worktree:
5.2s and 8.6MB of real disk, against ~90s and 424MB for `npm ci`.

The script bases new branches on origin/master per the branch rules,
resolves the main checkout via --git-common-dir so it works when invoked
from inside another worktree, and reruns `npm install` only when the
branch's lockfile differs from the main checkout's.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@codecov

codecov Bot commented Jul 27, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

🚀 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.

@github-actions

Copy link
Copy Markdown

✅ Terraform Plan (Staging) SUCCESS

📊 View full plan output in the workflow run

Auto-triggered after Test workflow success

@kkohtaka

Copy link
Copy Markdown
Owner Author

Closing: this addresses the wrong code path.

The worktrees that actually fill the disk are created by Claude Code itself — there are 41 claude/* branches locally, each Created from refs/remotes/origin/master by the harness. npm run setup:worktree is a manual entry point that never sits in that path, so it would not have prevented any of the accumulation it was written for. It also does nothing about the accumulation itself; the cleanup in this session was done by hand.

The measurement stands (cp -c clones node_modules for ~8.6MB / 5.2s instead of ~424MB / 90s on APFS), but the useful primitive is "populate node_modules cheaply in the worktree we are already in", applied automatically, rather than "create a worktree". Will reopen the work in that shape.

@kkohtaka kkohtaka closed this Jul 27, 2026
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