Skip to content

fix(post-checkout): scaffold only on clone/init - #393

Merged
twistedmelonman merged 1 commit into
mainfrom
claude/fix-post-checkout-scaffold-392
Oct 2, 2026
Merged

twistedmelonman merged 1 commit into
mainfrom
claude/fix-post-checkout-scaffold-392

Conversation

@twistedmelonman

Copy link
Copy Markdown
Member

Summary

The global post-checkout hook copied the .claude/ scaffold on every git checkout -b and every git worktree add -b, not only on a fresh clone or init. Guards 0a (null prev_head) and 0b (linked worktree) protected only the ignore entry, which runs after the copy. The scaffold was left behind as untracked files. In a linked worktree, those files also stop git worktree remove, and with it gh pr merge --delete-branch.

Change

  • git/template/hooks/post-checkout: guards 0a and 0b move into is_fresh_clone_or_init, which runs before the copy and after seed_editorconfig. seed_editorconfig is unchanged and keeps its own origin-remote guard. add_claude_gitignore_entry no longer repeats guard 0. Guards 1-3 keep their numbers. The header and guard comments now describe the new order.
  • If git rev-parse cannot answer, the hook treats the checkout as not fresh and skips. This matches the old ignore-entry behavior.

Tests

bash/tests/test-post-checkout-gitignore.sh:

  • Case C (git checkout -b in a repo with commits) asserts that no .claude/ appears.
  • Case D2 (git worktree add -b of an established repo) asserts that no .claude/ appears in the new worktree.
  • Case H asserts that the wrapper's synthesized init call (null SHAs, main work tree) still scaffolds. Case A already covers a real clone.

Against the old hook, the two new no-scaffold assertions fail:

FAIL: branch switch: no .claude/ scaffold copied -- expected 'no', got 'yes'
FAIL: worktree of established repo: no .claude/ scaffold copied -- expected 'no', got 'yes'

With the fix, all four post-checkout-related files pass locally: test-post-checkout-gitignore.sh, test-post-checkout-editorconfig-seed.sh, test-post-checkout-hookspath.sh, test-git-wrapper-init-hook.sh. The full suite runs in CI as bash-tests.

shellcheck -S info with the canonical config is clean on both files.

Closes #392

The .claude/ scaffold copy was gated only on branch_checkout == 1 and on
.claude/ being absent. Guards 0a (null prev_head) and 0b (linked worktree:
--absolute-git-dir differs from --git-common-dir) protected only the
ignore entry, which runs after the copy. So `git checkout -b` and
`git worktree add -b` both copied the scaffold and left it as untracked
files. In a linked worktree that also stops `git worktree remove`, and
with it `gh pr merge --delete-branch`.

Move both guards into is_fresh_clone_or_init and apply it before the
copy, after seed_editorconfig, which keeps its own origin-remote guard.
The ignore-entry function no longer repeats them. The wrapper's
synthesized init call (null SHAs, main work tree) and a real clone still
pass both guards.

Tests: Cases C (checkout -b) and D2 (worktree add -b) now assert that no
.claude/ appears; both failed against the old hook. Case H now asserts
that the synthesized init call still scaffolds.

Closes #392
@twistedmelonman
twistedmelonman merged commit d730484 into main Oct 2, 2026
3 checks passed
@twistedmelonman
twistedmelonman deleted the claude/fix-post-checkout-scaffold-392 branch October 2, 2026 18:42
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.

post-checkout copies the .claude/ scaffold on every new branch, not just clone/init

1 participant