Skip to content

fix(pstack): protect untracked and ignored worktree files - #459

Open
dajiaohuang wants to merge 4 commits into
cursor:mainfrom
dajiaohuang:fix/pstack-worktree-cleanup-safety
Open

dajiaohuang wants to merge 4 commits into
cursor:mainfrom
dajiaohuang:fix/pstack-worktree-cleanup-safety

Conversation

@dajiaohuang

@dajiaohuang dajiaohuang commented Sep 29, 2026 •

Copy link
Copy Markdown

Summary

  • Count tracked, untracked, and ignored worktree paths as held WIP.
  • Remove the guidance to force-remove worktrees or delete leftover directories.

Fixes #449.

Validation

  • Bash syntax check passed.
  • Synthetic Git worktree with one untracked file and one ignored directory reported wip:2 and hold-wip.
  • git diff --check passed.

Note

Low Risk
Documentation and read-only audit script changes only; deletion behavior is stricter and safer for local worktrees, with no production runtime impact.

Overview
Tightens worktree cleanup so untracked and ignored paths are never treated as disposable scratch.

The audit script now runs git status with --untracked-files=all and --ignored=matching, labels any dirty worktree as wip:N (line count of all paths), and drops the old scratch bucket. The playbook adds an explicit ownership/safety framing and rewrites steps 4–5: default to holding any wip worktree, require per-path user approval before removal, use non-force git worktree remove only after a fresh status preflight, and forbid rm -rf or git worktree prune to override Git refusals.

Reviewed by Cursor Bugbot for commit f5752d5. Bugbot is set up for automated code reviews on this repo. Configure here.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is ON, but it could not run because the branch was deleted or merged before autofix could start.

Reviewed by Cursor Bugbot for commit a17c461. Configure here.

Comment thread pstack/skills/poteto-mode/playbooks/worktree-cleanup.md Outdated
@deanrie

deanrie commented Oct 3, 2026

Copy link
Copy Markdown

Verified on a test repo. A worktree with one untracked note plus an ignored build/ and run.log goes from scratch:1 and review on main to wip:3 and hold-wip with this patch, and the playbook text matches. I also confirmed the claim in step 5. Plain git worktree remove does delete an ignored-only worktree without --force, so the status preflight is the right gate.

Two non-blocking suggestions:

  • Keep a separate ignored:N counter next to wip:N or add a column. If ignored paths are counted, almost every worktree with node_modules or build becomes hold-wip, and the user can no longer tell three important notes from forty thousand build files. Both should hold, but that difference is the whole triage signal.
  • wc -l on --ignored=matching output counts !! build/ as one line, so the number is paths, not files. Worth calling that out in the playbook.

Related: #470 touches the same script. It covers closed unmerged PRs and unpushed commits bucketed as safe, and the git fetch even though the header says read-only. Landing them together would avoid two conflicting edits.

deanrie pushed a commit to deanrie/plugins that referenced this pull request Oct 13, 2026
… work as safe

Three problems in worktree-audit.sh (cursor#470):
- a PR in any non-open state satisfied `$pr != "-"`, so a CLOSED (unmerged)
  PR made the worktree `safe`;
- the computed `remote` column (ahead/no-remote/detached) was never read by
  the bucket logic, so unpushed commits could be bucketed `safe`;
- the header called the script read-only although it runs `git fetch`.

Only ancestry of origin/main or a MERGED PR now counts as proof the work
exists elsewhere. Worktrees whose HEAD is ahead of / absent from the remote
or detached and not on origin/main go to a new `hold-unpushed` bucket,
ranked right after hold-wip and hold-open-pr. A CLOSED PR falls through to
`review`. The header now states the one write the script performs, and the
playbook documents the new bucket in step 1 (steps 4-5 are left untouched to
avoid conflicting with cursor#459).

Verified on a synthetic repo with a stubbed gh: ahead1+CLOSED and detached
off-main -> hold-unpushed; pushed+MERGED, pushed+CLOSED-on-main and detached
on origin/main -> safe; pushed+CLOSED with commits not on main -> review.

Fixes cursor#470
deanrie pushed a commit to deanrie/plugins that referenced this pull request Oct 14, 2026
… work as safe

Three problems in worktree-audit.sh (cursor#470):
- a PR in any non-open state satisfied `$pr != "-"`, so a CLOSED (unmerged)
  PR made the worktree `safe`;
- the computed `remote` column (ahead/no-remote/detached) was never read by
  the bucket logic, so unpushed commits could be bucketed `safe`;
- the header called the script read-only although it runs `git fetch`.

Only ancestry of origin/main or a MERGED PR now counts as proof the work
exists elsewhere. Worktrees whose HEAD is ahead of / absent from the remote
or detached and not on origin/main go to a new `hold-unpushed` bucket,
ranked right after hold-wip and hold-open-pr. A CLOSED PR falls through to
`review`. The header now states the one write the script performs, and the
playbook documents the new bucket in step 1 (steps 4-5 are left untouched to
avoid conflicting with cursor#459).

Verified on a synthetic repo with a stubbed gh: ahead1+CLOSED and detached
off-main -> hold-unpushed; pushed+MERGED, pushed+CLOSED-on-main and detached
on origin/main -> safe; pushed+CLOSED with commits not on main -> review.

Fixes cursor#470
@deanrie

deanrie commented Oct 22, 2026

Copy link
Copy Markdown

Hey @dajiaohuang, a note for whoever reviews this. #459 and #492 edit the same two files (worktree-audit.sh and the cleanup playbook) and no longer apply independently, so #770 stacks them: your three commits are cherry-picked with -x and your authorship, on top of #492, with one hand-resolved hunk in playbook steps 3 to 5 (your text for 4 and 5, #492's step 3 with the Subagents sentence from main). It also adds the tests this PR did not have: fixture worktrees with an untracked-only file and ignored-only build output, both asserted as wip:N / hold-wip, plus a guard that no row ever reports scratch:. If the maintainer prefers the originals, #770 says so in its first line and can be closed; if you would rather carry the tests here yourself, the commit is 5a3b772 on the pstack/worktree-audit-stack branch of my fork and applies cleanly to this branch once #492's harness is present.

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.

pstack: worktree-cleanup treats untracked and ignored files as disposable (--force, rm -rf)

2 participants