Git Writing — 사람이 읽는 PR·이슈·커밋
이 스킬이 다루는 것
| 상황 | 담당 |
|---|---|
| 내가 올리는 PR의 제목·본문 | 이 스킬 |
| 이슈 작성·수정 | 이 스킬 |
| 커밋 메시지 | 이 스킬 (전역 규칙 — 한국어, Co-Authored-By 금지 — 위에 얹힌다) |
| 팀원이 올린 PR을 리뷰 | pr-review-loop |
| 커밋·PR 직후 이해도 확인 | senior-mentor |
트리거를 나눈 이유: 같은 시점을 두고 스킬이 경합하면 발동 신뢰도가 떨어진다.
PR 생성 시점에는 이 스킬(본문)과 senior-mentor(이해도)가 둘 다 걸릴 수 있고, 서로 배타가 아니다.
전제 — 구조는 문제가 아니다
이 사용자의 레포들에서 PR·이슈의 섹션 골격은 이미 잘 작동한다 (PR: 개요/주요 변경/검증/리뷰 포인트/남긴 것 · 이슈: 배경/실측/해결 방향/완료 조건). 골격을 갈아엎거나 새 템플릿을 강제하지 마라. 이 스킬이 고치는 것은 문장 안에서 일어나는 일이다.
실제 산출물(팀 게임 프로젝트의 PR들, 그래픽 툴 플러그인의 이슈들)에서 관찰된 문제는 매체를 가리지 않고 같다:
- 한 문장에 결정 + 근거 + 반사실("~였다면 ~로 남습니다")을 전부 욱여넣은 고밀도 문장
계약③,ADR-2,[G6]같은 내부 참조 코드와 "슬루", "그리디 홀드" 같은 전문용어가 설명 없이 등장- 문서마다, 심지어 한 문서 안에서 어미가 섞임
독자를 그려라
읽는 사람은 소규모 팀의 팀원이다. 리뷰어이거나, 이 변경·이슈 위에 다음 작업을 쌓을 사람이다. 이 글은 분석 보고서가 아니라 팀원이 한 번 읽고 다음 행동(리뷰 시작, 작업 착수, 판단)에 들어갈 수 있는 작업 문서다. 문장이 완결적이고 정확해도, 읽는 사람이 두 번 읽어야 하면 실패다.
공통 규칙 — 모든 매체에 적용
1. 한 문장에는 하나의 정보
무엇을 했는지(또는 무엇이 문제인지) 한 문장. 왜 그런지는 다음 문장. 대안이 왜 아닌지는 필요할 때만 그다음 문장. 이 셋을 대시(—)와 쉼표로 한 문장에 이으면, 정보는 보존되지만 읽기는 무너진다.
실제 PR에서 관찰된 패턴을 재구성한 예시:
전 (한 호흡에 결정·이유·계약 노출까지):
QuestLogWidget은 자체bCompleted플래그를 버리고 표시 전용으로 전환, 완료 여부는 매번 QuestState에 질의. 위젯 로컬 상태는 레벨 전환·세이브에서 사라지고, Reward(보상 지급)·Dialogue(HasQuestDone조건)가 같은 상태를 읽어야 해서 공유 계약③으로 노출했다.
후 (문장마다 정보 하나, 서술어까지 완결):
QuestLogWidget은 이제 표시만 담당합니다. 완료 여부는 매번 QuestState에 물어봅니다. 위젯이 직접 들고 있던bCompleted플래그는 레벨 전환이나 세이브에서 사라지는 값이라 버렸습니다. Reward와 Dialogue도 같은 완료 상태를 읽어야 해서, 조회 함수들을 공유 계약③(위젯–상태 간 공유 API 규약)으로 노출했습니다.
1-b. 쪼갠 문장은 연결어미로 다시 잇는다
규칙 1로 정보를 나눈 뒤, 인접한 두 문장이 인과·역접·조건 관계면 연결어미(-아서, -라서, -지만, -는데, -면)로 잇는다. 관계를 "그래서", "다만" 같은 접속부사로 문장 밖에서 되붙이지 말고 어미 안에 넣어라. 한국어는 논리 관계를 연결어미가 나르기 때문에, 그 자리가 비면 짧은 단정문이 줄지어 서고 읽는 사람은 관계를 스스로 채워 넣어야 한다. 위 "후" 예시가 읽히는 이유가 그것이다 — 셋째·넷째 문장이 "-라", "-해서"로 이어져 있고 앞 두 문장과 길이가 다르다. 전부 짧으면 아무것도 강조되지 않는다.
주어는 현상이 아니라 행위자로 잡는다. 무너지다·갈라지다·덮다 같은 동사가 손에 잡히면 그 문장에 들어갈 실측이나 호출 순서를 아직 확인하지 않았다는 신호이니, 사실을 찾아 넣으면 동사는 저절로 평범해진다.
❌ 완료 상태가 두 줄기로 갈라집니다. 세이브에서 값이 무너집니다. ⭕ 위젯과 QuestState가 각자 완료 여부를 들고 있어서, 세이브 직렬화가 위젯 쪽
bCompleted를 포함하지 않으면 로드 뒤 두 값이 어긋납니다.
2. 문장을 끝까지 써라
"로 전환," "에 질의." 같은 서술어 생략체를 쓰지 마라. 명사 뭉치("중복·잔량 판정을 상태 소유자가 최종 결정")는 동사로 풀어라. 글자 수를 아끼는 만큼 읽는 사람의 해석 비용이 늘어난다 — 아껴야 하는 것은 글자가 아니라 독자의 시간이다.
비유로 기술적 사실을 대체하지 마라. "범인은 리타겟 정책이 아니었습니다", "쓰레기 회전이 됩니다", "축이 눕는 순간"처럼 비유가 사실의 자리에 서면, 읽는 사람은 무슨 일이 일어났는지 추측해야 한다. 사실을 먼저 쓰고, 비유는 이해를 돕는 자리에만 뒤따르게 해라 — "실제 포말이 공기 섞인 흰 물이라 불투명한 것과 같은 이치입니다"처럼 설명을 마친 뒤 붙는 비유가 그 자리다.
3. 참조 코드·전문용어는 첫 등장에서 풀어준다
계약③, ADR-002, Milestones §3, [G6] 같은 내부 코드와, 팀원이 모를 수 있는 전문용어("히스테리시스", "슬루", "temporal IK")는 쓰는 사람 머릿속에는 선명하지만 읽는 사람은 찾아봐야 한다. 첫 등장에서 괄호 한 줄로 무엇인지 적어라. 두 번째부터는 코드·용어만 써도 된다.
공유 계약③(위젯–상태 간 공유 API 규약)으로 노출했습니다. … 계약③의 시그니처는 그대로입니다.
문서 링크가 가능하면 링크가 더 좋다. 단, 링크가 있어도 한 줄 설명은 남긴다 — 링크를 타는 것도 비용이다.
설명은 확인한 것만 붙여라. 문서나 코드에서 뜻을 확인하지 못한 용어는 설명을 지어 붙이지 말고 원문 표현 그대로 둬라. 그럴듯하게 틀린 설명은 설명 없는 코드보다 해롭다 — 읽는 사람이 확인 없이 틀린 이해를 갖게 된다. (실측 사례: 이슈 재작성 테스트에서 bone_swing에 "팔뚝 평행 스윙"이라는 지어낸 설명이 붙었다. 실제로는 세로 본 swing이다.)
단, "확인 못 했으니 그냥 둔다"로 끝내지 마라. 본문에 쓸 용어는 쓰기 전에 코드·문서에서 뜻을 확인하는 것이 기본 순서다. 확인이 안 되면 먼저 그 용어를 쓰지 않고 풀어 쓸 수 있는지 본다. 그래도 써야 하면 docs/rig.md §21 같은 출처를 함께 남긴다 — 설명도 출처도 없는 용어가 가장 나쁘다.
수식·기호는 결과를 먼저 쓰고 표기를 뒤에 붙인다. (2π−θ, −a)를 그대로 던지지 말고 그 표기가 무엇을 뜻하는지 먼저 쓴다.
❌ 축 연속성 규칙은 내적이 음수면
(2π−θ, −a)로 바꿉니다. ⭕ 축 연속성 규칙은 같은 회전을 반대 방향으로 도는 표현(2π−θ만큼 축−a둘레로)으로 바꿉니다.
혼자 쓰고 혼자 머지하는 레포일수록 이 규칙을 세게 적용한다. 되묻는 사람이 없어서 무설명이 교정되지 않고, 몇 주 뒤 자기 자신이 못 읽는 문서가 된다. 독자를 "이 코드를 안 본 팀원"으로 계속 가정해라.
4. 근거는 선별한다
모든 결정에 근거와 반사실을 달면 본문 전체의 밀도가 올라가 정작 중요한 근거가 묻힌다. 기준은 전역 문서 작성 원칙과 같다: 이 근거가 읽는 사람의 행동을 바꾸는가.
- 읽는 사람이 뒤집을 수 있고 지금 뒤집는 게 싼 결정 → 근거를 충분히. PR이면 리뷰 포인트 섹션으로 올린다
- 이미 확정된 결정의 실행, 사소한 구현 선택 → 결정만 적는다. 이유가 궁금하면 물어볼 것이다
- 실제 이유를 모르면 지어내지 마라. 근거 없는 결정은 근거 없이 적는 것이 정직하다
5. 어미는 합쇼체, 팀원 지칭은 이름+님
- 팀원에게 보내는 글이므로 기본값은 **합쇼체(-습니다)**다. 한 문서 안에서 섞지 말고, 문서 사이에서도 유지해라.
- 팀원을 지칭할 때는 이름 + 님으로 쓴다 ("민수님이 볼 부분"). 이름만 부르는 반말 지칭("민수이 볼 부분")을 쓰지 마라.
- (팀이 다른 관례를 정하면 그것을 따른다 — 중요한 것은 일관성이다.)
6. 굵은 글씨는 놓치면 사고 나는 것에만
문단마다 균일하게 볼드가 있으면 아무것도 강조되지 않는다. 읽는 사람이 놓쳤을 때 실제로 문제가 되는 것 — 머지 전 확인 필수, 깨진 상태로 들어가는 것, 되돌리기 어려운 결정 — 에만 써라.
PR
- 제목: 한 줄만 보고 "무엇이 바뀌는지" 알 수 있어야 한다. GitHub 목록 화면에서 잘리지 않을 길이로. 팀에 굳은 접두 관례(트랙/주차 표기 등)가 있으면 유지한다. 병기(A + B + C)를 세 개 이상 잇지 마라 — 셋 다 중요하면 개요 첫 문장에서 풀어라.
- 골격: 기존 PR들의 골격(개요/주요 변경/검증/리뷰 포인트/남긴 것)을 따른다. 해당 없는 섹션은 비워두지 말고 뺀다. 검증 섹션만은 뺄 수 없다 — 레포의 기존 PR 골격에 검증 섹션이 없어도 만든다. 실행·미실행 구분이 들어갈 자리가 거기뿐이고, 체크리스트만 있던 레포에서 이 스킬을 쓴 PR이 검증 절 없이 올라간 사례가 있다.
- 검증 섹션: 리뷰어가 그대로 따라할 수 있게 — 어떤 씬·명령·조작으로 무엇을 보는지까지.
- 검증은 실행한 것과 안 한 것을 나눠 적는다. 실제로 돌린 것은 무엇으로 확인했는지 결과와 함께 적고, 안 돌린 것은 "미실행"으로 명시한다. 예상을 실행 결과처럼 쓰면 리뷰어는 확인된 것으로 믿는다 — "머지 전에 돌려보겠습니다"는 검증이 아니라 계획이다.
이슈
- 제목은 증상 중심 한 줄. 읽는 사람이 목록에서 제목만 보고 "무슨 문제인지"를 알아야 한다. 원인 분석을 제목에 압축하지 마라 — 원인은 본문 몫이다.
- 골격: 기존 이슈들의 골격(배경 / 지금 상태·실측 / 해결 방향 / 완료 조건)을 따른다. 이 골격 자체는 좋다.
- 본문 첫 문단은 코드를 안 연 사람도 읽혀야 한다. 파일:라인 참조는 근거로 붙이되, 문장 자체는 참조 없이도 뜻이 통하게 써라. "무엇이 어떻게 잘못 동작하고, 사용자·결과물에는 어떻게 보이는가"를 먼저, 코드 수준 원인은 그다음에.
- 실측이 있으면 실측을 적어라. "고착될 수 있다"보다 "f103~130 사이 28프레임이 동일 회전으로 정지한다"가 낫다. 다만 실측 나열이 본문을 삼키면 요약 한 줄 + 상세는 접거나 뒤로 보낸다.
- 완료 조건은 확인 가능한 문장으로. "개선된다"가 아니라 "이 구간이 지표에 잡힌다"처럼, 닫을 때 판정할 수 있게 쓴다.
커밋 메시지
전역 규칙(한국어, Co-Authored-By 금지)에 다음을 얹는다:
- 제목 줄은 "무엇을 왜"의 무엇 쪽 한 줄. 목록(
git log --oneline)에서 잘리지 않을 길이로, 이 커밋이 코드를 어떻게 바꾸는지가 드러나게. - 본문이 필요한 커밋(설계 결정이 들어간 것, 이유가 코드에 안 보이는 것)은 빈 줄 하나 띄우고 왜를 문장으로 적는다. 공통 규칙 1~4가 그대로 적용된다.
- 루틴 커밋(오타, 정리, 단순 반영)에 본문을 억지로 달지 마라. 제목 한 줄이면 끝이다.
- 본문이 있는 커밋은 게시 전에 린트를 거친다(아래 "올리기 전 검사" 1). 실측에서 갈라지다·무너지다·조용히 같은 어휘가 몰려 있던 곳은 커밋 본문이었다. PR 본문에는 거의 없었다. 스크립트는 합쇼체·해라체를 모두 센다.
올리기 전 검사 — 린트, 판정자, 자가 검사
작성자는 자기 초안의 리듬을 보지 못한다. 규칙을 쓴 바로 그 문단에서 같은 리듬이 다시 나오는 것이 원작성자 실측으로 확인됐고, 판단형 자가 검사는 그냥 통과한다. 그래서 세는 일은 스크립트가, 판정은 초안을 쓰지 않은 컨텍스트가 한다.
본문은 파일로 쓴다(gh pr create --body-file, gh issue create --body-file). 그 파일에 대해:
- 린트.
python scripts/prose-lint.py <본문 파일> > <린트 출력 파일>. 걸린 문장을 줄 번호와 함께 인용해 준다. 후보 목록이다. 사실을 정확히 말하는 문장은 걸려도 그대로 둔다. - 판정자. 초안을 쓰지 않은 컨텍스트에 본문 파일·린트 출력·
references/review-request.md를 본문 파일 옆에 복사해 빈칸을 채운 사본을 넘기고 문장 단위 교체안을 받는다. 원본 양식은 고치지 않는다. 작업 중인 모델이 Claude이고 codex 플러그인이 있으면 codex 서브에이전트에게 받는다 — 이 리듬은 Claude 고유의 성향이라 다른 모델이 사각을 공유하지 않는다. 없으면 같은 모델의 서브에이전트다. 판정자는 본문을 다시 쓰지 않는다. 통째로 다시 쓰면 같은 리듬이 돌아온다. 걸린 문장마다 "원문 → 교체안"만 받고, 본 에이전트가 그 교체만 적용한다. - 린트 재실행. 교체를 적용한 뒤 한 번 더 돌려 새로 걸린 것이 없는지 본다.
커밋 메시지는 1만 한다. 자동 커밋 규약 아래서 커밋마다 판정자를 부르면 무겁고, 커밋 층에서 실측된 문제는 어휘라 단어 검사로 충분하다.
그 뒤 본문을 다시 읽으며 확인한다:
- 첫 문단(또는 커밋 제목 줄)만 읽은 팀원이 "이게 무슨 일인지" 한 문장으로 말할 수 있는가
- 아무 불릿이나 골라 소리 내어 읽었을 때 한 호흡에 끝나는가 — 숨이 차면 문장을 쪼개고, 쪼갠 문장이 인과·역접이면 연결어미로 다시 잇는다(규칙 1-b)
- 참조 코드·전문용어가 설명 없이 처음 등장하는 곳이 없는가
- 개요(이슈면 배경) 첫 문단에 뜻이 안 풀린 용어가 3개 이상인가 — 그렇다면 그 문단은 코드를 이미 아는 사람만 읽을 수 있는 상태다
- 붙인 설명이 문서·코드에서 실제로 확인한 것인가 — 확인 못 했으면 설명을 빼고 원문 표현으로 되돌린다
- 검증 섹션에 실행하지 않은 항목이 실행한 것처럼 적혀 있지 않은가
- 어미가 섞이지 않았는가, 팀원 지칭이 이름+님인가
- AI 내부 상태값·수사(전역 "보고서·문서 작성 원칙"의 금지 목록)가 없는가
- 도구가 붙인 자동 푸터("Generated with …")가 남아 있지 않은가 — 전역 지침은 팀원에게 가지 않고 이 스킬은 간다
하지 말 것
- 섹션 골격을 새로 발명하는 것 — 기존 골격을 따르고, 해당 없는 섹션은 뺀다
- 근거를 지어내는 것
- 밀도를 낮춘다는 이유로 정보를 삭제하는 것 — 문장을 쪼개는 것이지 내용을 버리는 것이 아니다. 판단이 애매하면 남긴다
- 전역 "보고서·문서 작성 원칙"을 여기 다시 쓰는 것 — 그 원칙은 이 스킬 위에 그대로 얹힌다
성공 기준 · 존재 의의
같은 폴더의 RATIONALE.md에 있다. 여기 옮겨 적지 않는다 — 두 벌이 되면 갈라진다.
RATIONALE.md는 원작성자의 관측 기록이라 배포에 포함되지 않는다. 이 스킬을 새로 받았다면 자기 관측 기록으로 직접 만든다. 그때 ## 재는 것에는 아래 기준을 그대로 옮긴다 — 메커니즘에 딸린 것이라 사람이 바뀌어도 같다:
- 팀원이 PR·이슈를 읽고 내용을 되묻는 횟수가 줄어든다
- 사용자가 게시 전에 본문을 손으로 고치는 빈도가 줄어든다 — 수동으로 고친 부분이 다음 규칙 후보다
- 문서 간 문체가 일관된다
사용자가 "이 스킬 의도대로 작동해?" 라고 물으면 그 파일을 읽고 이번 세션과 대조한다.