From 1efeb48276a41f2852712021b1cbcf7fdce65aee Mon Sep 17 00:00:00 2001 From: wlrnjs Date: Sun, 4 Oct 2026 18:36:21 +0900 Subject: [PATCH] =?UTF-8?q?fix(claude):=20=EB=B9=84=EA=B0=9C=EB=B0=9C?= =?UTF-8?q?=EC=9E=90=20=EC=9E=91=EC=97=85=20=EB=B8=8C=EB=9E=9C=EC=B9=98=20?= =?UTF-8?q?=EC=A0=91=EB=91=90=EC=82=AC=EB=A5=BC=20preview/=EC=97=90?= =?UTF-8?q?=EC=84=9C=20work/=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 저장소에 preview 브랜치가 있으면 git이 preview/<이름> 브랜치를 만들 수 없어 new-preview-worktree.sh가 항상 실패했습니다. 스크립트, guard-preview-branch 훅, CLAUDE.md의 접두사를 work/로 함께 바꿨습니다. Co-Authored-By: Claude Opus 5.5 --- .claude/hooks/guard-preview-branch.mjs | 18 ++++++++++-------- .claude/scripts/new-preview-worktree.sh | 5 +++-- CLAUDE.md | 6 +++--- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/.claude/hooks/guard-preview-branch.mjs b/.claude/hooks/guard-preview-branch.mjs index 029a060..892f1fc 100755 --- a/.claude/hooks/guard-preview-branch.mjs +++ b/.claude/hooks/guard-preview-branch.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node // -// 비개발자가 Claude로 작업할 때 반드시 .claude/worktrees 아래의 preview/ 브랜치 워크트리에서만 +// 비개발자가 Claude로 작업할 때 반드시 .claude/worktrees 아래의 work/ 브랜치 워크트리에서만 // 파일을 고치고 커밋하게 강제하는 PreToolUse 훅이다. // // 이 훅은 .claude/settings.json에 등록되어 있어 기본으로 켜져 있다. 개발자는 개인 파일인 @@ -12,10 +12,10 @@ // // 막는 범위는 다음과 같다. // - 이 저장소 안의 파일을 Edit/Write할 때, 그 파일이 .claude/worktrees/<이름>/ 아래에 있고 -// 그 워크트리의 브랜치가 preview/로 시작하지 않으면 막는다. 메인 워킹 디렉토리는 항상 막는다. +// 그 워크트리의 브랜치가 work/로 시작하지 않으면 막는다. 메인 워킹 디렉토리는 항상 막는다. // - 저장소의 .claude/hooks, .claude/scripts, .claude/settings.json은 워크트리 안이라도 막는다. -// - Bash의 git commit, merge, rebase, reset, cherry-pick은 preview/ 워크트리 안에서만 허용한다. -// - git push는 preview/ 브랜치로만 허용하고, force push와 preview, main으로의 push, gh pr merge는 막는다. +// - Bash의 git commit, merge, rebase, reset, cherry-pick은 work/ 워크트리 안에서만 허용한다. +// - git push는 work/ 브랜치로만 허용하고, force push와 preview, main으로의 push, gh pr merge는 막는다. // // 저장소 밖의 파일(스크래치패드, 메모리 등)은 검사하지 않는다. @@ -26,9 +26,11 @@ import { fileURLToPath } from 'node:url'; if (process.env.FI_ADMIN_DEVELOPER === '1') process.exit(0); +// 작업 브랜치 이름 앞부분. 저장소에 preview 브랜치가 있어 git이 preview/<이름> 브랜치를 만들 수 없으므로 work/를 쓴다. +const BRANCH_PREFIX = 'work/'; const GUIDE = - '작업은 preview/ 브랜치 워크트리에서만 할 수 있습니다. 먼저 `bash .claude/scripts/new-preview-worktree.sh <영문-작업-이름>`을 실행해 ' + + '작업은 work/ 브랜치 워크트리에서만 할 수 있습니다. 먼저 `bash .claude/scripts/new-preview-worktree.sh <영문-작업-이름>`을 실행해 ' + '.claude/worktrees/<작업-이름>/ 워크트리를 만들고, 그 안의 파일만 수정하십시오.'; const block = (reason) => { @@ -67,13 +69,13 @@ const existingDir = (path) => { return realpathSync(dir); }; -// 주어진 디렉토리가 이 저장소의 preview/ 워크트리 안이면 그 워크트리 경로를, 아니면 이유를 돌려준다. +// 주어진 디렉토리가 이 저장소의 work/ 워크트리 안이면 그 워크트리 경로를, 아니면 이유를 돌려준다. const checkLocation = (dir) => { if (!isInside(dir, WORKTREES)) return { error: '메인 워킹 디렉토리에서는 작업할 수 없습니다.' }; const top = git(dir, 'rev-parse', '--show-toplevel'); if (!top || realpathSync(top) === ROOT) return { error: '워크트리 밖입니다.' }; const branch = git(dir, 'rev-parse', '--abbrev-ref', 'HEAD'); - if (!branch.startsWith('preview/')) return { error: `현재 브랜치(${branch || '알 수 없음'})가 preview/로 시작하지 않습니다.` }; + if (!branch.startsWith(BRANCH_PREFIX)) return { error: `현재 브랜치(${branch || '알 수 없음'})가 ${BRANCH_PREFIX}로 시작하지 않습니다.` }; return { top: realpathSync(top), branch }; }; @@ -116,7 +118,7 @@ if (tool === 'Bash') { if (/\bgit\s+(-C\s+\S+\s+)?push\b/.test(command)) { if (/\s(--force\S*|-f|--mirror|--delete|-d)\b|\s\+\S/.test(command)) block('강제 push와 브랜치 삭제는 할 수 없습니다.'); - // preview/<작업-이름>은 허용해야 하므로 preview 뒤에 /가 붙지 않은 경우만 막는다. + // preview 브랜치 자체로 가는 push만 막도록 preview 뒤에 공백이나 명령 끝이 오는 경우로 좁힌다. if (/\b(main|master)\b|(^|[\s:])preview(?=\s|$)/.test(command)) block('preview, main으로는 push할 수 없습니다.'); const location = checkLocation(runDir); if (location.error) block(location.error); diff --git a/.claude/scripts/new-preview-worktree.sh b/.claude/scripts/new-preview-worktree.sh index 1a66e4d..0ae94a7 100755 --- a/.claude/scripts/new-preview-worktree.sh +++ b/.claude/scripts/new-preview-worktree.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# 최신 origin/preview에서 preview/<작업-이름> 브랜치를 만들고 .claude/worktrees/<작업-이름>/에 +# 최신 origin/preview에서 work/<작업-이름> 브랜치를 만들고 .claude/worktrees/<작업-이름>/에 # 워크트리로 체크아웃한다. 비개발자가 Claude로 작업을 시작할 때 Claude가 이 스크립트를 실행한다. # # bash .claude/scripts/new-preview-worktree.sh notice-banner-text @@ -18,7 +18,8 @@ fi root=$(cd "$(dirname "$0")/../.." && pwd) dir="$root/.claude/worktrees/$name" -branch="preview/$name" +# 저장소에 preview 브랜치가 있으면 git이 preview/<이름> 브랜치를 만들 수 없으므로 work/를 쓴다. +branch="work/$name" if [ -e "$dir" ]; then echo "이미 있는 워크트리입니다: $dir" >&2 diff --git a/CLAUDE.md b/CLAUDE.md index 7025815..f76b43a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -16,14 +16,14 @@ - 환경 변수 값이 필요하거나 env 때문에 생긴 문제로 보이면 사용자에게 직접 확인해 달라고 요청한다. - 막는 훅은 `.claude/hooks/guard-env.mjs`이고 개발자를 포함해 누구도 끌 수 없다. -### 2. 작업은 `.claude/worktrees` 아래 preview 브랜치 워크트리에서만 한다 +### 2. 작업은 `.claude/worktrees` 아래 `work/` 브랜치 워크트리에서만 한다 이 저장소는 비개발자도 Claude로 작업한다. 메인 워킹 디렉토리나 `preview`에서 바로 고치지 않도록 다음 순서를 반드시 지킨다. -1. 파일을 고치기 전에 `bash .claude/scripts/new-preview-worktree.sh <작업-이름>`을 실행한다. 작업 이름은 영문 소문자와 하이픈으로 짓는다(예: `notice-banner-text`). 스크립트가 최신 `origin/preview`에서 `preview/<작업-이름>` 브랜치를 만들어 `.claude/worktrees/<작업-이름>/`에 체크아웃하고, 필요한 설정 파일을 복사한다. +1. 파일을 고치기 전에 `bash .claude/scripts/new-preview-worktree.sh <작업-이름>`을 실행한다. 작업 이름은 영문 소문자와 하이픈으로 짓는다(예: `notice-banner-text`). 스크립트가 최신 `origin/preview`에서 `work/<작업-이름>` 브랜치를 만들어 `.claude/worktrees/<작업-이름>/`에 체크아웃하고, 필요한 설정 파일을 복사한다. 2. 이후 모든 수정과 명령은 그 워크트리 경로 안에서 한다. 같은 작업을 이어서 할 때는 기존 워크트리를 쓰고 새로 만들지 않는다. 3. 화면 확인이 필요하면 사용자에게 그 워크트리 경로에서 `pnpm dev`를 직접 실행해 달라고 안내한다. -4. 커밋과 push는 사용자에게 무엇을 바꿨는지 설명하고 허락을 받은 뒤에 한다. push는 `preview/` 브랜치로만 하고, `preview`와 `main`으로 push하거나 force push하거나 PR을 머지하지 않는다. `preview` 반영은 개발자가 PR 리뷰를 거쳐 한다. +4. 커밋과 push는 사용자에게 무엇을 바꿨는지 설명하고 허락을 받은 뒤에 한다. push는 `work/` 브랜치로만 하고, `preview`와 `main`으로 push하거나 force push하거나 PR을 머지하지 않는다. `preview` 반영은 개발자가 PR 리뷰를 거쳐 한다. 5. 비개발자에게 설명할 때는 git 용어를 줄이고, 무엇이 바뀌었는지와 어디서 확인하면 되는지를 먼저 말한다. 막는 훅은 `.claude/hooks/guard-preview-branch.mjs`다. 개발자는 개인 파일인 `.claude/settings.local.json`에 `{"env": {"FI_ADMIN_DEVELOPER": "1"}}`을 넣어 이 훅만 끄고 `feat/`, `fix/` 등 기존 브랜치 흐름으로 작업할 수 있다. 이 훅이 켜진 상태에서는 `.claude/hooks`, `.claude/scripts`, `.claude/settings.json`도 수정할 수 없다.