0007: 이슈 연결 브랜치 네이밍을 required check 로
0007: 이슈 연결 브랜치 네이밍을 required check 로
- Status: accepted
- Date: 2026-05-11
- Related:
docs/engineering-governance.md§”Change lifecycle” 확장; 비공식claude/<auto>worktree 네이밍 패턴 supersede - Deciders: hskim
TL;DR
- 모든 PR 브랜치는
<type>/issue-<N>[-<slug>]regex 강제 — CI required check. scripts/check_branch_and_issue.py가 regex 단일 출처 — CI + 로컬 pre-push 훅 양쪽이 동일 스크립트 호출.- PR body 의
Closes #N이 브랜치<N>과 일치해야 함.
배경
지금까지 작업과 추적 이슈 간 강제 연결 없음:
- PR 템플릿 §1 에
Closes #placeholder 있으나 검증 없음(.github/pull_request_template.md) git branch -a가claude/issue-<N>-<slug>·claude/<adj>-<name>-<hash>(auto-named worktree)·일부 legacyfeat/<N>-<slug>혼재. 컨벤션은 history 로 관찰 가능하나 rule 로 명시 안 됨engineering-governance.mdstep 1(“Open or pick an issue”) 은 soft instruction. 이슈 번호 없이 PR merge 가능
결과: 추적 갭. reviewer 가 Closes #123 grep 으로 이슈 종료 PR 을 찾을 수 없음 — 링크가 기록 안 됐다면. 더 나쁘게 claude/<auto> 패턴은 이슈 존재 자체를 모호하게 만듦 — 브랜치명이 intent 아닌 랜덤 단어 인코딩.
아래 새 rule 로 링크를 required + machine-checked at PR boundary.
결정
main 머지 PR 은 새 CI workflow .github/workflows/branch-and-issue-check.yml 가 강제하는 세 조건 만족 필요:
- 브랜치명 컨벤션 매치:
^(?:feat|fix|docs|chore|refactor|test|eval|ci|perf|build|style)/issue-(\d+)(?:-[a-z0-9]+(?:-[a-z0-9]+)*)?$- prefix 는 위 conventional-commit 타입 + measurement/evaluation 전용
eval중 하나.claude/거부 — Claude Code auto-named worktree 브랜치는 PR 전 rename 필요 issue-<N>필수; 뒤 slug 는 선택이나 human readability 위해 권장- 예:
feat/issue-79-senior-positioning,fix/issue-104
- prefix 는 위 conventional-commit 타입 + measurement/evaluation 전용
-
참조 이슈가 이 repo 에 존재 (state — open/closed — 미검사; follow-up 브랜치가 종료 이슈 참조 가능)
- PR body 에
Closes #N(또는Fixes/Resolves) 포함 + 그 중 하나가 브랜치<N>과 일치. GitHub merge auto-close 와 동일 regex — 기존 UX piggyback
regex·이슈 체크·Closes 매칭 모두 단일 스크립트(scripts/check_branch_and_issue.py)에 위치 — CI workflow(--pr <N>) + 로컬 .githooks/pre-push 훅(--branch <name>) 양쪽 사용. regex 중복 없음, drift 없음.
면제
다음 브랜치 prefix 는 체크 스킵(구조상 추적 이슈 없음):
revert-*— GitHub auto-generated revertdependabot/*— Dependabot PRrenovate/*— Renovate PRpre-commit-ci/*— pre-commit autoupdate PR
강제 레이어
| 레이어 | 시점 | 우회 가능? | 검사 내용 |
|---|---|---|---|
CI (branch-and-issue-check.yml) |
main 으로 모든 pull_request |
No (required status check) | 브랜치 regex + 이슈 존재 + Closes #N 매치 |
로컬 .githooks/pre-push |
git push (make install-hooks 로 opt-in) |
--no-verify |
브랜치 regex + (gh 설치 시) 이슈 존재 |
CI 가 계약. 로컬 훅은 make install-hooks 실행한 개발자를 위한 fast-feedback mirror.
결과
Wins
- 모든 머지 PR 이 이슈 추적 가능.
git log --grep '#'가 이슈의 전체 change set 발견; GitHub UI 가 머지 시 이슈 auto-close - 브랜치명이 intent 인코딩(
feat/issue-79-…는 작업 종류 + 추적 대상 표현) — 랜덤 단어 아님 - PR 템플릿
Closes #placeholder 가 hint 가 아닌 계약 — reviewer 는 누락 시 머지 차단 인지 - CI 게이트 silent 우회 불가; 로컬 훅은 opt-in 개발자에 즉시 피드백
Costs
- Claude Code 기본 worktree 브랜치명(
claude/<adj>-<name>-<hash>)이 거부됨. 기여자는 PR 전 rename 필요(git branch -m feat/issue-<N>-<slug>). 브랜치당 1회 rename, commit 시점이 아닌 브랜치 생성 시점 비용 - PR 당 workflow run 1회 추가. 빠름(~15s, 코드 checkout 없음)
- bot(Dependabot·Renovate)은 prefix 면제; 그들 PR 은 trusted
- 일부 정당한 작업(작은 오타 수정·doc-only follow-up)도 이제 이슈 선행 필요. uniform 추적성 대가로 friction 수용
도입된 제약
scripts/check_branch_and_issue.py가 regex 단일 출처. 향후 변경(허용 prefix·면제·slug shape)은 그 파일 + 테스트tests/test_branch_convention.py편집 — CI workflow 나 훅에 regex 중복 절대 Xmain의 branch protection 은 known-good PR 1건 green + deliberate probe red 확인 후 “Branch & Issue Convention” 을 required status check 로 표시
검토한 대안
claude/issue-<N>-<slug>허용 + auto-name 패턴만 거부. Reject: 사용자가 conventional-commit 타입 선호로claude/prefix drop 을 명시 선택. 또한 브랜치명을 commit 메시지 컨벤션과 정렬 + 브랜치 리스트가 카테고리 changelog 처럼 읽힘(feat/·fix/·docs/즉시 가독)- multi-issue 작업에
epic/<slug>를 issue-less 예외로 허용. Reject: epic 자체가 추적 이슈. epic-issue 번호를 브랜치명에 강제(예:feat/issue-<epic-N>-multi-doc-retrieval)는 uniformity 의 작은 대가 - 로컬 훅만 강제, CI 비강제. Reject: 기존 훅은 opt-in(
git config core.hooksPath .githooks). CI 없으면make install-hooks안 한 기여자가 rule 을 silent 우회. CI 가 유일한 universal 표면 - 이슈 body 검증(예: checklist 요구). Reject as scope creep. 이 ADR 은 추적성, 이슈 위생 아님. 이슈 템플릿(
.github/ISSUE_TEMPLATE/)이 강제 없이 위생 장려 Closes #N만 검사, 브랜치<N>매칭 안 함. Reject:Closes #50인데feat/issue-49-…에 사는 PR 은 거의 확실히 실수 — 브랜치 재사용 또는 sibling PR body 복붙. 매칭이 이를 잡음