들어가며
38차시는 하나의 좋은 커밋을 만드는 법이었다. git diff가 이미 보여주는 무엇 대신 왜를 담는 메시지, Conventional Commits 형식, 본문을 위한 HEREDOC, 그리고 기여를 정직하게 붙이는 Co-Authored-By 트레일러까지. 한 문장으로 줄이면 38차시는 커밋 하나의 이야기였다.
39차시는 그 커밋들을 모은다. 분석한 변경을 커밋으로 쌓았으면, 이제 그 커밋들을 한 묶음으로 PR(Pull Request)로 올려 리뷰와 병합의 무대에 세운다. 베스트 프랙티스 문서가 권하는 4단계 워크플로우의 마지막 스텝이 정확히 이것이다 — Explore → Plan → Implement → Commit, 그 Commit 스텝의 프롬프트는 한 줄이다.
commit with a descriptive message and open a PR
커밋과 PR은 이어진 동작처럼 보이지만, 둘 사이엔 결정적인 차이가 하나 있다. 그리고 이 차시 전체가 그 차이 위에 선다.
커밋은 working-tree의 변경 하나를 본다(
git diff). PR은 브랜치 전체를 본다(git diff main...HEAD).
이 한 줄을 머리에 박고 시작하자. PR을 잘 만든다는 건 결국 “이 브랜치가 base에서 갈라진 뒤 쌓인 모든 변경을 하나의 이야기로 묶는 것”이고, PR 자동화에서 가장 흔한 실패는 “최신 커밋 하나만 보고 PR을 쓰는 것”이다. 그래서 이 차시는 PR의 분석 단위(브랜치)부터, 제목·본문을 쓰는 형식(## Summary/## Test plan), 실제로 PR을 여는 도구(gh CLI), 그리고 만든 PR로 다시 돌아오는 법(claude --from-pr)까지를 차례로 짚는다.
먼저, 38차시에서 했던 것과 똑같이 오해 하나를 걷어낸다.
/pr 같은 건 없다 — PR도 자연어로 부른다
38차시에서 /commit 내장 슬래시 명령이 없다는 걸 봤다. PR도 똑같다. /pr이나 /create-pr 같은 내장 명령은 없다. 명령 레퍼런스에서 GitHub과 엮인 내장을 훑어보면 이런 것들이다.
| 명령 | 하는 일 | 비고 |
|---|---|---|
/install-github-app | 저장소에 Claude GitHub App 설치(+선택적 GitHub Actions 설정) | PR 생성이 아니라 연동 |
/diff | 커밋 안 된 변경을 인터랙티브하게 보는 뷰어 | 읽기 전용 |
/review [PR] | GitHub PR을 번호로 리뷰(/code-review와 같은 엔진) | 40차시 영역 |
/code-review | 현재 diff 리뷰, --comment로 PR 인라인 코멘트 게시 | 40차시 영역 |
/security-review | 현재 브랜치 변경의 보안 분석 | — |
보다시피 PR을 만드는 전용 명령은 없다. PR은 명령이 아니라 요청으로 시작한다. 일반 워크플로우 문서가 그대로 보여준다.
You can create pull requests by asking Claude directly (“create a pr for my changes”), or guide Claude through it step-by-step
즉 이렇게 부른다.
변경사항으로 PR 만들어줘
또는 단계별로 — 먼저 요약하고, PR을 만들고, 설명을 다듬는다.
인증 모듈에 내가 한 변경을 요약해줘
PR 만들어줘
보안 개선 부분 맥락을 더해서 PR 설명을 보강해줘
그러면 Claude가 뒤에서 gh CLI를 Bash로 굴려 PR 절차를 돈다. 38차시에서 “커밋은 명령이 아니라 절차”였듯, PR도 그렇다 — 다만 이번엔 절차의 마지막에 git commit이 아니라 gh pr create가 온다.
PR과 커밋의 결정적 차이 — “최신 커밋 하나”가 아니라 “브랜치 전체”
이 차시에서 딱 하나만 가져간다면 이것이다.
커밋을 만들 때 Claude가 보는 건 지금 working-tree의 변경이다 — git diff(스테이징 안 된 것)와 git diff --staged(스테이징된 것). 즉 “아직 커밋 안 된 하나의 변경 덩어리”가 단위다.
PR은 다르다. PR이 담는 건 브랜치가 base 브랜치(보통 main)에서 갈라진 뒤 쌓인 모든 커밋이다. 그래서 PR 본문을 쓰려면 최신 커밋 하나가 아니라 브랜치 전체의 변경을 봐야 한다. 이걸 보는 git 명령이 따로 있다.
| 보는 것 | 명령 | 의미 |
|---|---|---|
| 브랜치가 추가한 변경 | git diff main...HEAD (점 3개) | main에서 갈라진 뒤 이 브랜치가 더한 diff — GitHub이 PR diff로 보여주는 바로 그것 |
| 브랜치의 커밋 목록 | git log main..HEAD (점 2개) | main엔 없고 이 브랜치엔 있는 커밋들 — PR에 포함될 커밋 전부 |
점의 개수가 다른 게 핵심이다. main...HEAD(3-dot diff)는 “두 브랜치가 갈라진 지점(merge-base)부터 HEAD까지, 이 브랜치가 추가한 변경”을 보여준다 — PR을 열었을 때 GitHub 페이지에 뜨는 그 diff와 정확히 같다. main..HEAD(2-dot log)는 그 사이의 커밋들을 나열한다.
그래서 PR 생성의 제1 규칙은 이렇게 된다.
PR 본문은 최신 커밋 하나가 아니라, 브랜치의 모든 커밋을 분석해서 쓴다.
왜 이 경고가 그렇게 중요할까? 흔한 함정이기 때문이다. 브랜치에 커밋이 다섯 개 쌓였는데 마지막 커밋만 보고 PR 제목을 쓰면, PR은 그 브랜치가 한 일의 5분의 1만 설명하게 된다. 사람이 직접 PR을 쓸 때도 자주 저지르는 실수고, 자동화에서는 더 쉽게 빠진다 — 그래서 Claude의 PR 절차는 git log main..HEAD로 브랜치의 커밋 전부를 먼저 읽고 시작한다.
정리하면, 38차시에서 39차시로 넘어오며 분석의 단위가 바뀐다.
- 커밋(38차시): 단위 = 변경 하나(
git diff). 흩어진 줄 변경을 하나의 의도로 묶는다. - PR(39차시): 단위 = 브랜치 전체(
git diff main...HEAD). 여러 커밋을 하나의 이야기로 묶는다.
PR 생성도 “명령”이 아니라 “절차”다
38차시의 커밋이 7단계 절차였듯, PR도 절차다. 구조는 닮았지만, 보는 대상이 working-tree에서 브랜치로, 마지막 동작이 git commit에서 gh pr create로 바뀐다.
| 단계 | 명령 | 무엇을 하나 |
|---|---|---|
| 1 | git status | 현재 상태 — 커밋 안 된 변경, 현재 브랜치 |
| 2 | git diff + git diff main...HEAD | working-tree 변경 그리고 브랜치 전체 변경 |
| 3 | git log main..HEAD | 브랜치의 모든 커밋 (NOT 최신 하나) |
| 4 | (원격 추적 확인) | 브랜치가 원격에 푸시됐는지, 추적 중인지 |
| 5 | (제목·본문 작성) | 브랜치 전체를 묶어 제목 + ## Summary/## Test plan |
| 6 | git push -u | 필요시 브랜치를 원격에 올린다 |
| 7 | gh pr create | HEREDOC 본문으로 PR 생성 |
13번은 38차시에서 본 그대로 읽기 전용 git이다 — 권한 프롬프트 없이 자동으로 돌고, Claude는 종종 이들을 한 번에 병렬로 읽는다(37차시). 차이는 23번에서 브랜치 범위(main...HEAD, main..HEAD)를 함께 본다는 것뿐이다.
그리고 38차시와 결정적으로 갈리는 지점은 6번이다. 커밋은 로컬에서 끝나지만, PR은 푸시를 동반한다 — 즉 원격(외부)으로 나가는 작업이다. 이 차이가 뒤의 안전 절에서 다시 중요해진다.
PR 본문 — ## Summary와 ## Test plan
커밋 메시지에 형식(Conventional Commits)이 있었듯, PR 본문에도 Claude가 따르는 표준 구조가 있다. 두 블록이다.
## Summary
<1-3개 불릿: 이 브랜치가 무엇을·왜>
## Test plan
[이 PR을 검증하기 위한 체크리스트…]
🤖 Generated with [Claude Code](https://claude.com/claude-code)
각 블록의 의미를 38차시와 이어 보면 분명해진다.
## Summary — 38차시 “무엇이 아니라 왜”의 PR 판이다. 커밋 메시지가 하나의 변경의 의도를 담았다면, Summary는 브랜치 전체의 의도를 1~3개 불릿으로 담는다. diff는 PR 페이지에 이미 다 있으니, Summary는 그 diff가 말해주지 않는 왜와 무엇을 위한 묶음인지를 쓴다.
## Test plan — “이 변경을 어떻게 검증하나”다. 이건 그냥 관례가 아니라 베스트 프랙티스 문서의 핵심 원칙과 맞닿아 있다 — “Give Claude a way to verify its work.” 리뷰어(사람이든, 다음 에이전트든)가 이 PR이 정말 동작하는지 확인할 방법을 체크리스트로 남기는 자리다. 어떤 테스트를 돌렸고, 무엇을 수동으로 확인해야 하는지.
Review Claude’s generated PR before submitting and ask Claude to highlight potential risks or considerations.
문서의 이 당부도 같은 맥락이다 — PR을 제출하기 전에 검토하고, Claude에게 잠재적 위험·고려사항을 짚어 달라고 하라. Summary가 무엇을 했나라면, Test plan과 위험 점검은 그게 맞는지 어떻게 아나다.
gh pr create와 HEREDOC
본문 구조가 정해졌으면, 실제로 PR을 여는 건 gh CLI다. 그리고 본문은 멀티라인이라, 38차시에서 본 HEREDOC을 그대로 쓴다.
gh pr create --title "feat: 로그인 폼에 비밀번호 표시 토글 추가" --body "$(cat <<'EOF'
## Summary
- 비밀번호 필드에 표시/숨김 토글을 추가해 입력 검증 부담을 줄임
- 접근성(aria-label)과 키보드 포커스 처리 포함
## Test plan
- [ ] 토글 클릭 시 비밀번호 표시/숨김 전환 확인
- [ ] 스크린리더에서 aria-label 읽힘 확인
- [ ] 폼 제출 시 값이 그대로 전송되는지 확인
🤖 Generated with [Claude Code](https://claude.com/claude-code)
EOF
)"
여기서도 포인트는 38차시와 같다 — **작은따옴표로 감싼 'EOF'**가 셸의 $·백틱 해석을 막아, 본문에 특수문자가 들어가도 글자 그대로 보존된다. 멀티라인 PR 본문을 --body에 안전하게 욱여넣는 관용구다.
gh가 왜 필요한지는 베스트 프랙티스 문서가 분명히 한다.
If you use GitHub, install the
ghCLI. Claude knows how to use it for creating issues, opening pull requests, and reading comments. Withoutgh, Claude can still use the GitHub API, but unauthenticated requests often hit rate limits.
요약하면 이렇다 — gh가 깔려 인증돼 있으면 Claude는 그걸로 PR을 만들고, 이슈를 열고, 코멘트를 읽는다. gh가 없으면 GitHub API로 떨어지는데, 인증 안 된 요청은 rate limit에 자주 걸린다. 그러니 PR 워크플로우의 사전 준비는 사실상 하나다 — gh를 설치하고 gh auth login으로 인증해 두는 것.
💡
gh는 GitHub 전용이다. 같은 일을 GitLab은glab, Bitbucket은 자체 CLI로 한다. Claude는 “이 CLI로 PR/MR 만들어줘”라고 알려주면 처음 보는 CLI도--help를 읽어 가며 쓴다(베스트 프랙티스 — “Claude is also effective at learning CLI tools it doesn’t already know”).
🤖 Generated with Claude Code 푸터 — 38차시의 핸드오프가 닫힌다
위 PR 본문 마지막 줄을 보자.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
38차시에서 이걸 예고했었다 — 커밋엔 트레일러, PR엔 푸터. 자리만 잡아 뒀던 그 푸터가 여기서 실제로 붙는다.
| 위치 | 표시 | 형태 |
|---|---|---|
| 커밋(38차시) | Co-Authored-By: Claude <noreply@anthropic.com> | Git 트레일러 (Key: Value) |
| PR(39차시) | 🤖 Generated with [Claude Code](https://claude.com/claude-code) | PR 본문 푸터 |
둘은 같은 철학의 두 표현이다 — Claude의 기여를 정직하게 표시하되, 커밋의 작성자(author) 정보는 사람 그대로 둔다(37차시 — git config를 건드리지 않는다). 커밋은 공동 작성자로, PR은 본문 푸터로.
이 표시를 끄거나 바꾸는 건 38차시에서 본 attribution 설정의 pr 키다. 커밋과 PR을 따로 제어할 수 있다.
{
"attribution": {
"commit": "",
"pr": ""
}
}
pr을 빈 문자열("")로 두면 PR 푸터만 꺼진다. 커밋 트레일러는 두고 PR 푸터만 끄거나(혹은 반대로), 문구 자체를 팀 표준으로 바꿀 수도 있다.
{
"attribution": {
"commit": "🤖 Generated with Claude Code",
"pr": ""
}
}
기본값은 켜져 있다는 것만 기억하면 된다(구 includeCoAuthoredBy, default true — 38차시). 끄려면 명시적으로 비운다.
세션은 PR에 연결된다 — claude --from-pr
여기서부터가 “PR 관리”의 핵심이고, 이 차시가 38차시와 가장 크게 갈라지는 지점이다. PR은 만들고 끝이 아니라, 작업으로 돌아오는 영속 핸들이 된다.
gh pr create로 PR을 만드는 순간, 일반 워크플로우 문서의 이 문장이 발동한다.
When you create a PR using
gh pr create, the session is automatically linked to that PR. To return to it later, runclaude --from-pr <number>or paste the PR URL into the/resumepicker search.
즉 PR을 만든 그 세션이 PR에 자동으로 링크된다. 며칠 뒤 리뷰 코멘트가 달려 다시 손봐야 할 때, 컨텍스트를 처음부터 다시 설명할 필요가 없다 — PR 번호 하나로 그때 그 작업 맥락 그대로 돌아온다.
claude --from-pr 123
CLI 레퍼런스가 이 플래그를 이렇게 정의한다.
Resume sessions linked to a specific pull request. Accepts a PR number, a GitHub or GitHub Enterprise PR URL, a GitLab merge request URL, or a Bitbucket pull request URL. Sessions are linked automatically when Claude creates the pull request
PR 번호뿐 아니라 GitHub/GitHub Enterprise PR URL, GitLab MR URL, Bitbucket PR URL도 받는다. PR URL을 /resume 피커 검색창에 붙여 넣어도 같은 세션으로 들어간다. 이게 PR을 단순한 “결과물”이 아니라 작업의 영속적인 주소로 만든다.
PR “관리” — gh로 보고, 읽고, 되돌아오기
생성이 절반이라면 나머지 절반은 관리다. 만든 PR을 확인하고, 리뷰 코멘트를 읽고, 고치는 흐름 — 여기서도 도구는 한결같이 gh + 자연어다.
PR을 보고 목록을 확인한다. 굳이 외울 명령은 없다. “내 열린 PR 목록 보여줘”, “이 PR 상태 어때?”라고 하면 Claude가 gh pr list·gh pr view로 가져온다.
리뷰 코멘트를 읽는다. 예전엔 /pr-comments라는 전용 명령이 있었지만, v2.1.91에서 제거됐다. 명령 레퍼런스의 설명이 명확하다.
Removed in v2.1.91. Ask Claude directly to view pull request comments instead. … Requires the
ghCLI
즉 이제는 자연어로 부탁한다 — “이 PR에 달린 리뷰 코멘트 정리해줘”. Claude가 내부적으로 gh로 코멘트를 가져와 요약한다. 전용 명령이 사라진 자리를 자연어 + gh가 대체한 셈이다.
비대화형으로도 묶을 수 있다. PR/커밋 요약 같은 작업은 헤드리스로 파이프할 수 있다(베스트 프랙티스).
git log --oneline -20 | claude -p "이 최근 커밋들을 요약해줘"
그리고 리뷰로 이어진다. 만든 PR을 그대로 신뢰하지 않는 게 원칙이다. GitHub PR을 리뷰하는 내장 /review <PR>, 현재 diff를 검사하고 --comment로 PR 인라인 코멘트를 다는 /code-review — 이 리뷰 도구들은 40차시의 주제다. 39차시에서 PR을 만들고 관리했다면, 40차시는 그 PR을 리뷰한다.
37차시의 안전 원칙은 PR에서 더 강해진다
37차시의 안전 원칙은 38차시 커밋에 그대로 적용됐다. PR에서는 한 단계 더 강해진다 — PR은 푸시를 동반하는, 즉 로컬 밖으로 나가는 작업이기 때문이다.
- 요청해야만 PR을 만든다. 그리고 PR은 거의 항상 푸시를 동반한다. 37차시에서 봤듯 Claude는 요청 없이 원격에 푸시하지 않는다. “PR 만들어줘”라고 명시적으로 말해야 푸시→PR로 들어간다.
- 기본 브랜치 위라면 먼저 브랜치를 판다.
main·master에서 바로 PR을 올리는 일은 없다. 커밋 전에(38차시) 새 브랜치부터 만들고, 그 브랜치를 PR의 head로 올린다. CLAUDE.md에 “Repository etiquette (branch naming, PR conventions)“(브랜치 네이밍·PR 컨벤션)를 적어 두라는 베스트 프랙티스 권장이 정확히 이 자리다(21차시). - 파괴적 원격 조작은 하지 않는다.
push --force같은 명령으로 남의 작업을 덮어쓰지 않는다(37차시).
그리고 이 선들은 말이 아니라 **권한 시스템(17차시)**으로 못 박을 수 있다. 38차시가 “커밋은 허용, 푸시는 차단”이었다면, PR 워크플로우를 자율화하려면 PR 생성까지 명시적으로 연다.
{
"permissions": {
"allow": [
"Bash(git commit *)",
"Bash(git push *)",
"Bash(gh pr create *)"
]
}
}
거꾸로, PR은 사람이 직접 누르고 싶다면 gh pr create를 빼 두면 된다 — 그러면 커밋까지는 자율, PR은 사람의 손에 남는다. 어느 쪽이든 명시적으로 정하는 게 핵심이다. (gh를 읽기 전용으로만 자율화하고 싶다면 Bash(gh pr view *)·Bash(gh pr list *)만 여는 식으로 더 잘게 쪼갤 수도 있다.)
이 자율화가 끝까지 가면 CI까지 닿는다 — 베스트 프랙티스의 fix-issue 스킬은 *“7. Create a descriptive commit message → 8. Push and create a PR”*로 끝나고, /batch는 각 서브에이전트가 “테스트를 돌리고 PR을 연다”. 헤드리스에서 PR을 여는 이 패턴은 **41차시(CI/CD)**로 이어진다.
흔한 함정
/pr슬래시 명령을 찾는다. 그런 내장 명령은 없다. “PR 만들어줘”라는 자연어로 부르고, Claude가gh를 Bash로 굴린다.- 최신 커밋 하나만 보고 PR을 쓴다. PR은 브랜치 전체다.
git log main..HEAD로 모든 커밋을,git diff main...HEAD로 브랜치가 추가한 변경 전부를 본다. - 3-dot과 2-dot을 헷갈린다. PR diff는
git diff main...HEAD(점 3개 — 갈라진 뒤 추가한 변경). 커밋 목록은git log main..HEAD(점 2개). gh없이 PR이 매끄럽게 될 거라 기대한다.gh가 없으면 GitHub API로 떨어지고 인증 안 된 요청은 rate limit에 걸린다.gh설치 +gh auth login이 사실상 전제다.- PR 본문에 Summary만 쓴다.
## Test plan이 빠지면 리뷰어가 검증할 방법을 잃는다 — 베스트 프랙티스의 “verify its work”가 PR에서 굳은 자리다. - 멀티라인 본문을
--body "..."에 그냥 욱여넣는다. HEREDOC("$(cat <<'EOF' … EOF)")으로. 작은따옴표'EOF'가 셸 해석을 막는다(38차시). - 푸터를 못 끄는 줄 안다.
attribution설정의pr키를""로 비우면 PR 푸터만 꺼진다(커밋 트레일러와 따로). - PR을 만들고 세션을 버린다. 세션은 PR에 자동 링크된다.
claude --from-pr <번호>로 그 작업 맥락 그대로 돌아온다 — 이게 관리의 핵심이다. - PR 코멘트 보려고
/pr-comments를 친다. v2.1.91에서 제거됐다. “이 PR 코멘트 정리해줘”라고 자연어로 부르면 Claude가 gh로 가져온다. - 생성한 PR을 그대로 믿는다. 제출 전에 리뷰하고 위험을 짚게 한다. 본격 리뷰는 40차시.
- 기본 브랜치에서 바로 PR을 올린다.
main위라면 먼저 브랜치를 판다. 브랜치·PR 컨벤션은 CLAUDE.md에 적는다(21차시).
정리
핵심 요점
- PR은 “최신 커밋 하나”가 아니라 “브랜치 전체”를 본다. 커밋의 단위는 working-tree diff(
git diff), PR의 단위는 브랜치(git diff main...HEAD, 3-dot). 그래서 PR 생성의 제1 규칙은 브랜치의 모든 커밋(git log main..HEAD, 2-dot)을 분석하는 것 — 최신 하나만 보면 PR이 한 일의 일부만 설명하게 된다. - PR도 슬래시 명령이 아니라 절차다.
/pr내장은 없다. “create a pr” 자연어 →ghCLI(Bash). 절차는 커밋과 닮았지만 브랜치 범위를 보고, 끝이gh pr create다. - PR 본문 =
## Summary+## Test plan. Summary는 브랜치 전체의 왜·무엇(38차시 “무엇이 아니라 왜”의 PR 판), Test plan은 어떻게 검증하나(베스트 프랙티스 “verify its work”). 멀티라인은 HEREDOC으로. ghCLI가 PR을 여는 액추에이터다. 있으면gh pr create, 없으면 GitHub API(rate limit).gh설치 +gh auth login이 전제다.- 커밋 =
Co-Authored-By트레일러, PR =🤖 Generated with Claude Code푸터. 38차시가 깔아둔 핸드오프가 닫힌다. 끄거나 바꾸려면attribution설정의pr키를 비운다(커밋과 따로). - 세션은 PR에 자동 링크된다 —
claude --from-pr <번호>. PR이 작업의 영속 핸들이 된다. 코멘트 읽기 전용/pr-comments는 제거됐고(v2.1.91), 이제 자연어로 부르면 gh로 가져온다. - 37차시 안전 원칙은 PR에서 더 강하다. PR은 푸시를 동반하는 외부 작업 — 요청해야만, 기본 브랜치면 먼저 브랜치.
allow Bash(gh pr create *)로 자율 범위를 못 박는다.
다음 단계
39차시가 PR을 만들고 관리하는 법이었다면, 40차시는 그 PR을 리뷰하는 법이다. 이 차시에서 잠깐 스친 /review <PR>(GitHub PR 리뷰)와 /code-review --comment(인라인 코멘트 게시)가 본격적으로 등장하고, 코드 품질·잠재 버그·보안·테스트 누락을 짚는 리뷰 체크리스트, 그리고 받은 피드백을 다시 코드로 되먹이는 흐름으로 이어진다. PR을 열었으니, 이제 그 PR을 읽을 차례다.
참고 자료
- 일반 워크플로우 — “Create pull requests”(자연어 “create a pr”, 단계별 레시피),
gh pr create세션 자동 링크와claude --from-pr <number> - 베스트 프랙티스 — Explore→Plan→Implement→Commit의 “open a PR”,
ghCLI 사용 권장과 미설치 시 API rate limit, CLAUDE.md의 repository etiquette, fix-issue 스킬의 “Push and create a PR” - CLI 레퍼런스 —
--from-pr(PR 번호·GitHub/GitLab/Bitbucket URL로 링크된 세션 복귀) - 설정 —
attribution(커밋·PR 기여 표시를 따로 커스터마이즈,pr키) - 명령 레퍼런스 — 내장 명령 목록(
/pr없음,/install-github-app·/review·/code-review·/diff),/pr-comments는 v2.1.91 제거