PR Discipline
개요
PR은 팀의 시간을 소모합니다. 여기서의 규율은 낭비(예상치 못한 범위로 인한 재리뷰, 잘못된 브랜치로의 병합, 잘못된 속성)를 발생시키기 전에 방지하는 것입니다.
원칙: 아키텍처가 관련된 경우 사전 합의, 항상 일관된 형식, 병합 대상은 두 번 확인.
시작 시 알리기: "이 PR에 pr-discipline을 적용합니다."
1단계: 코딩 전에 maintainer와 조율 (해당되는 경우)
변경 사항이 다음에 영향을 미친다면 PR을 열기 전에 모듈 maintainer에게 제안 한 단락을 보내십시오:
- 기존 엔드포인트의 응답 형식.
- DTO 또는 검증기(validator) 구조.
- 교차 저장소 패턴(validators, services, 에러 처리).
- 아키텍처 추상화(새로운 데코레이터, 서비스 계층, 모듈 수준 패턴).
템플릿:
"[Maintainer], feature Y를 위해 X를 하려고 합니다. 범위: a, b, c. 다른 X는 Z 이유로 현재 상태로 둡니다. 괜찮습니까?"
승인을 기다리십시오. 반대가 있으면 텍스트로 반복하십시오(비용이 저렴함). 승인하면 PR은 사후 논쟁 없이 통과됩니다.
적용되지 않는 경우: 계약을 변경하지 않는 버그 수정, 기존 패턴을 따르는 기능, 모듈 내부 리팩터링, 문서 또는 테스트만 있는 경우.
2단계: PR의 올바른 base 확인
PR의 base 브랜치가 항상 main인 것은 아닙니다. use-worktrees 스킬을 호출하여 해결하십시오 (1단계 — 전체 waterfall). 일단 해결되면 자동 메모리에 유지되며 이후 호출 시 묻지 않고 사용합니다.
이 스킬이 존중하는 일반적인 워크플로우:
| 워크플로우 | Feature 브랜치 시작점 | PR 대상 |
|---|---|---|
| staging 버퍼가 있는 백엔드 | staging | staging (이후 staging → main은 별도) |
| 모바일/웹 (단순) | main 또는 main-web | main 또는 main-web |
| 전통적인 Gitflow | dev | dev (이후 dev → master) |
| Trunk-based | main 또는 trunk | main 또는 trunk |
추정하지 말고 항상 해결하십시오.
3단계: 생성보다 재사용 우선
새로운 파일, validator, guard, 서비스, 컴포넌트, 헬퍼, 상수 또는 타입을 추가하기 전에: reuse-existing-patterns 스킬을 호출하십시오. 해당 스킬은 (카테고리별로) 검색하는 방법, 기존 것을 사용해야 하는 경우, 그리고 병렬 생성을 정당화할 수 있는 경우(PR 본문에 근거 포함)를 다룹니다.
이 습관을 거치지 않고 코딩을 시작하지 마십시오. 이것은 "이미 존재합니다. 현재 패턴을 사용하십시오" 유형의 리뷰 코멘트의 첫 번째 원인입니다.
4단계: PR 생성 — 제목, 본문, 속성
제목
- 70자 미만. 긴 내용은 본문에.
- 저장소 형식 (Conventional Commits이 있다면 그것을; 없다면 짧은 구문).
- 팀 언어 (팀이 스페인어로 작성한다면 제목도 스페인어로).
본문
최소 템플릿:
## 요약
<무엇이 변경되었고 왜 변경되었는지에 대한 1-3개 불릿>
## 테스트 계획
- [ ] <확인할 명령어 또는 흐름>
- [ ] <기타>
## 위험
<엣지 케이스, 롤백 계획, 종속성>
저장소에 템플릿(.github/PULL_REQUEST_TEMPLATE.md)이 있다면 그것을 기본으로 사용하십시오.
속성 (커밋 신원)
git commit에 절대 -c user.email=... 또는 -c user.name=...을 전달하지 마십시오. 작업 저장소에는 올바른 로컬 설정이 있습니다; 전역 설정은 일반적으로 개인용입니다. 실수로 덮어쓰면 작업 커밋이 개인 GitHub 계정에 귀속됩니다.
푸시하기 전에 확인:
git log -1 --format='%an <%ae>'
이메일이 작업용이 아니라면 푸시하지 말고 먼저 수정:
git commit --amend --reset-author # 현재 로컬 설정 사용
속성만을 위해 main/staging(보호된 브랜치)의 히스토리를 다시 쓰지 마십시오 — force-push의 비용이 이점보다 큽니다.
5단계: 백틱이 깨끗한 마크다운 업로드
gh pr edit --body-file 및 gh pr comment --body는 백틱을 \로 이스케이프하여 형식을 깨뜨립니다. 해결책: JSON 페이로드로 gh api -X PATCH를 사용하십시오.
python3 <<'PY'
import json, subprocess
with open('/tmp/body.md') as f:
body = f.read()
subprocess.run(
['gh', 'api', '-X', 'PATCH', 'repos/<org>/<repo>/pulls/<num>', '--input', '-'],
input=json.dumps({'body': body}), text=True, check=True
)
PY
확인:
gh pr view <num> --json body --jq .body | head -10
백틱이 리터럴(이스케이프되지 않음)로 나오면 깨끗한 것입니다.
6단계: 리뷰 코멘트 스타일
- 심각도별로 그룹화: 차단(Blocking) / 사소한 개선(Minor Improvements) / 사소한 것(Nits).
- 발견당 하나의 불릿, 한 줄에: 무엇 + 이유 + 제안된 수정.
- 라인 참조를 위해
파일.ts:42형식 사용 (GitHub에서 클릭 가능). - 관찰보다는 이유를 먼저 제시. 외부 감사가 아닌 동료의 여백 메모처럼.
- 작성자가 PR 본문에 자신의 추론을 문서화했다면 그 추론과 연결하십시오 — 첫 번째 원칙부터 재발명하지 마십시오.
- "B1", "M2"와 같은 인위적인 태그 없음. 도움이 되지 않는 예제 코드 블록 없음.
경험 많은 인간 리뷰어가 "AI 덤프"로 알아차리는 것: 너무 대칭적인 구조, 동일한 전환 문구, 작성자 맥락이 없는 불릿.
7단계: 병합 — 팀 워크플로우에 따른 squash vs merge
저장소의 관례를 확인하십시오. 일반적인 패턴:
| 저장소 유형 | feature → integration | integration → main |
|---|---|---|
| staging이 있는 백엔드 | squash | merge commit |
| staging 없는 모바일/웹 | squash 또는 merge | N/A |
| 전통적인 Gitflow | dev로 merge | master로 merge |
staging이 있는 저장소에서 비대칭인 이유: staging → main을 squash하면 PR이 거대해 보입니다(이미 squash된 N개의 feature를 반복). Merge commit은 staging에 들어간 그대로 feature 목록을 보존합니다.
# feature → staging
gh pr merge --squash <num>
# staging → main (분리된 저장소의 경우)
gh pr merge --merge <num>
저장소에 staging이 있다면 절대 main에 직접 병합하지 마십시오:
git revert는 코드를 되돌리지만 커밋은 히스토리에 영원히 남습니다 — 팀 전체에 보입니다.- 누르기 전에
gh pr create의--base와 GitHub UI의 병합 대상을 삼중 확인하십시오. - 의심스러우면
gh pr merge를 실행하기 전에 사용자에게"staging에 병합할까요?"라고 물으십시오.
빠른 참조
| 상황 | 조치 |
|---|---|
| 변경이 계약 또는 아키텍처에 영향 | 1단계: maintainer와 조율 |
| 브랜치 생성 | 2단계: waterfall로 base 결정 |
| 구현 시작 | 3단계: 패턴이 이미 저장소에 있는지 검색 |
| PR 열 준비 완료 | 4단계: 제목 <70자, 템플릿이 있는 본문, 속성 확인 |
| 코드가 포함된 본문 또는 코멘트 | 5단계: JSON으로 gh api PATCH |
| 리뷰 남기기 | 6단계: 심각도별 불릿, 이유를 먼저 제시 |
| 병합 | 7단계: 관례에 따라 squash 또는 merge |
| staging이 있는 저장소 | main에 직접 병합 금지 |
일반적인 실수
- 사전 조율 없이 아키텍처 PR 열기. 2-3 라운드의 재리뷰와 사후 논쟁을 초래합니다. 코딩 전에 제안 한 단락을 보내십시오.
- 동등한 것이 이미 존재하는데 새 파일이나 추상화 생성하기. 먼저 검색하십시오(3단계). 리뷰어가 지적할 것입니다.
- 전체 설명이 포함된 70자 초과 제목. 제목은 짧게, 세부 사항은 본문에.
- 스크립트된 커밋에
-c user.email전달. 작업 로컬 설정을 개인 전역 설정으로 덮어씁니다. - 백틱이 있는
gh pr edit --body-file file.md. 이스케이프합니다. JSON으로gh api PATCH를 사용하십시오. - 산문 형식의 리뷰. 사용자는 심각도별 불릿을 원합니다 — 스캔 가능해야 하지, 이야기가 아닙니다.
- staging → main squash. 각 feature에서 이미 squash된 히스토리를 반복합니다. Merge commit을 사용하십시오.
- "작아서" main에 직접 병합. 커밋은 히스토리에 영원히 남아 모두에게 보입니다.
위험 신호
절대:
- 사전 조율 없이 계약/아키텍처에 영향을 미치는 PR 열기.
- 동등한 것이 이미 존재하는데 병렬 파일이나 추상화 생성하기.
git commit에-c user.email/-c user.name전달.git log -1 --format='%ae'확인 없이 푸시.- 백틱이 포함된 마크다운에
gh pr edit --body-file사용. - staging이 있는 저장소에서 main에 직접 병합.
- staging → main squash.
- 심각도별로 그룹화하지 않고 리뷰 남기기.
항상:
- 아키텍처 변경을 maintainer와 사전 조율.
- waterfall로 PR의 base 결정,
main으로 추정하지 않음. - 새 패턴을 만들기 전에 저장소에 이미 존재하는지 검색.
- 제목 <70자 + 요약 + 테스트 계획 + 위험이 포함된 본문.
- 푸시 전에 커밋 속성 확인.
- 코드가 포함된 마크다운은 JSON으로
gh api PATCH사용. - 리뷰는 심각도별 불릿, 이유를 먼저 제시.
- feature → integration은 squash, integration → main은 merge commit.