들어가며
Git을 로컬에서 혼자 잘 쓰는 것과, 팀과 함께 GitHub 위에서 잘 쓰는 것은 다른 문제입니다.
코드 변경에는 항상 맥락이 있습니다. 왜 이 기능을 만들었는지, 왜 이렇게 구현했는지, 이 변경이 어떤 문제를 해결하는지 — 이 맥락이 코드 안에만 있으면 나중에 아무도 알 수 없습니다. GitHub의 Issue, PR, README는 그 맥락을 코드 밖에 기록하는 도구입니다.
이 글은 GitHub 협업 도구들을 왜 필요한가의 관점에서 정리합니다.
Issue — 코드 변경의 출발점
Issue는 단순한 할 일 목록이 아닙니다. 팀의 의사결정 히스토리입니다.
Slack에서 "이 버튼 색깔 바꾸자"라고 얘기하면, 6개월 뒤 "왜 이 색깔이야?"라는 질문에 아무도 답할 수 없습니다. Issue에 기록하면 왜 이 결정을 했는지, 어떤 대안을 검토했는지, 누가 최종 승인했는지 모두 추적 가능합니다.
Issue는 코드 변경의 출발점이 되어야 합니다.
Issue #42 열기
↓
브랜치 생성: feature/42-dark-mode
↓
커밋: "feat(ui): 다크모드 토글 추가 (closes #42)"
↓
PR 생성 → 리뷰 → 머지
↓
Issue #42 자동 종료
이 흐름이 완성되면, 코드 한 줄이 왜 생겼는지 언제든 추적할 수 있습니다.
좋은 Issue 작성법
## 버그 리포트 / 기능 요청
### 현재 상황
결제 페이지에서 쿠폰 코드 입력 후 적용 버튼을 누르면 500 에러 발생
### 기대 동작
쿠폰 할인이 적용된 금액이 표시되어야 함
### 재현 방법
1. 장바구니에 상품 추가
2. 결제 페이지 이동
3. 쿠폰 코드 "SUMMER2026" 입력
4. "적용" 클릭
### 환경
- OS: macOS 14.2
- 브라우저: Chrome 120
- 로그: `TypeError: Cannot read property 'discount' of undefined`
Pull Request(PR) — 팀과의 대화
PR은 코드 합치기 요청이 아닙니다. 내 코드를 팀의 코드베이스에 편입시키기 위한 대화입니다.
PR 없이 바로 main 브랜치에 push하면, 코드 검증 없이 프로덕션에 반영될 수 있습니다. PR은 그 사이의 검증 단계입니다.
PR은 네 가지를 만들어냅니다.
- 코드 품질 향상 — 최소 1명의 리뷰어가 버그를 잡습니다
- 지식 공유 — 팀 전체가 코드베이스의 변화를 인지합니다
- 의사결정 기록 — "왜 이렇게 짰는가"에 대한 토론이 남습니다
- 책임 분산 — 한 명이 아닌 팀이 코드를 승인합니다
PR은 작게 유지할수록 좋습니다
1000줄짜리 PR은 리뷰하기 어렵습니다. 파일이 많아질수록 리뷰어의 집중력이 분산되고, 중요한 버그를 놓칠 가능성이 높아집니다. 400줄이 넘어가면 리뷰어가 전체 맥락을 유지하기 어려워집니다.
적정 기준: 200~400줄. 이 범위에서 리뷰어가 맥락을 유지하며 꼼꼼히 볼 수 있습니다.
기능을 여러 개 구현했다면 PR도 여러 개로 나눕니다.
❌ 하나의 PR에 모두 넣는 경우:
feat: 소셜 로그인 + 프로필 편집 + 알림 설정 (1200줄)
✅ 기능별로 분리:
PR #1 — feat(auth): 구글 소셜 로그인 (280줄)
PR #2 — feat(profile): 프로필 이미지 편집 (310줄)
PR #3 — feat(notification): 알림 설정 페이지 (190줄)
PR을 작게 쪼개면 리뷰 속도가 빨라지고, 문제가 생겼을 때 롤백 범위도 작아집니다.
좋은 PR 작성법
## PR 제목
feat: 소셜 로그인 구글 OAuth 2.0 연동
## 변경 사항
- `GoogleAuthService` 클래스 추가
- 기존 `AuthController`에 `/auth/google` 엔드포인트 추가
- 사용자 프로필 자동 생성 로직 포함
## 왜 이렇게 구현했나요?
passport.js 대신 직접 OAuth flow를 구현한 이유:
→ 라이브러리 추상화로 인한 디버깅 어려움 경험 때문
## 테스트 방법
1. `npm run dev` 실행
2. /login 페이지에서 "구글로 로그인" 클릭
3. 구글 계정 선택 후 메인 페이지 리다이렉트 확인
## 관련 이슈
Closes #37
## 체크리스트
- [x] 테스트 작성
- [x] 환경변수 `.env.example` 업데이트
- [ ] 문서 업데이트 필요 (다음 PR에서)
PR 리뷰할 때 주의할 점
❌ "이렇게 하면 안 되죠"
✅ "이 방식은 N+1 쿼리 문제가 생길 수 있을 것 같아요.
`include`로 eager loading하면 어떨까요?"
❌ "왜 이렇게 짰어요?"
✅ "이 패턴을 선택한 이유가 있나요?
저는 X 방식도 고려해볼 만하다고 생각해서요."
PR 리뷰는 코드를 판단하는 것이 아니라 더 좋은 코드를 함께 만드는 과정입니다. 리뷰어도 틀릴 수 있고, 작성자도 맞을 수 있습니다.
README — 존재하는 이유
README는 프로젝트의 첫인상이자 존재 이유입니다. 기술 스택 나열이 아니라, 이 프로젝트가 세상에 존재하는 이유를 설명해야 합니다.
나쁜 README의 구조
# MyApp
Node.js, React, MongoDB를 사용한 웹 애플리케이션입니다.
## 설치
npm install
npm start
이 프로젝트가 왜 존재하는지, 무슨 문제를 해결하는지 알 수 없습니다.
좋은 README의 구조
# LunchMate — 팀의 점심 고민을 30초 만에 해결하세요
매일 반복되는 "오늘 뭐 먹지?" 논쟁. LunchMate는 팀원들의 선호와
반경 500m 내 식당 데이터를 기반으로 민주적인 점심 메뉴를 추천합니다.
## 왜 만들었나요?
15명 팀에서 점심 메뉴 결정에 평균 12분이 소요된다는 것을 알았습니다.
하루 12분 × 250일 = 연간 50시간. 이걸 30초로 줄이고 싶었습니다.
## 핵심 기능
- 팀원 음식 선호/기피 음식 프로필 설정
- 카카오맵 API 연동 주변 식당 추천
- 투표 기능으로 최종 결정
## 빠른 시작
git clone https://github.com/username/lunchmate.git
cp .env.example .env
docker-compose up
## 기술 스택
| 영역 | 기술 | 선택 이유 |
|------|------|-----------|
| Backend | Node.js + Express | 팀 친숙도 |
| Database | PostgreSQL | 관계형 데이터 구조 적합 |
| Infra | Docker | 환경 일관성 |
## 기여하기
이슈를 먼저 열어주세요. PR은 feature/* 브랜치에서만 받습니다.
## 라이선스
MIT
좋은 README의 핵심 3요소는 "왜(이 프로젝트가 어떤 문제를 해결하는가)", "어떻게(30초 안에 실행할 수 있는 QuickStart)", "무엇을(기술 스택과 그 선택 이유, 단순 나열 X)"입니다.
일상적인 협업 워크플로우
기능 개발
# 1. 최신 main 브랜치로 동기화
git switch main
git pull origin main
# 2. 이슈 번호를 포함한 기능 브랜치 생성
git switch -c feature/42-user-profile
# 3. 작업 후 관련 파일만 스테이징
git add src/components/UserProfile.tsx
git add src/api/user.ts
# 4. 의미 있는 단위로 커밋
git commit -m "feat(profile): 사용자 프로필 이미지 업로드 기능 추가"
# 5. 원격 브랜치에 push
git push origin feature/42-user-profile
# 6. PR 생성
gh pr create --title "feat: 사용자 프로필 이미지 업로드" --body "Closes #42"
코드 리뷰 반영
# 리뷰어 코멘트 수정 후
git add .
git commit -m "refactor: 리뷰 반영 - 이미지 크기 검증 로직 분리"
git push origin feature/42-user-profile
# PR이 자동으로 업데이트됨
긴급 핫픽스
# 현재 작업 임시 저장
git stash
# main에서 핫픽스 브랜치 분기
git switch main
git pull origin main
git switch -c hotfix/payment-null-error
# 수정 후 커밋
git commit -m "fix(payment): 쿠폰 없을 때 null 참조 오류 수정"
git push origin hotfix/payment-null-error
# PR 생성 → 긴급 리뷰 → 머지
# 원래 작업으로 복귀
git switch feature/42-user-profile
git stash pop
GitHub Actions — CI/CD 자동화
PR이 열릴 때마다 자동으로 테스트를 실행하고, main에 머지되면 자동 배포하는 것이 팀의 기본입니다.
# .github/workflows/ci.yml
name: CI
on:
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- run: npm test
- run: npm run lint
이제 테스트가 실패한 PR은 머지 자체가 불가능해집니다. 코드 품질이 자동으로 보장됩니다.
기억해야 할 핵심 포인트
커밋은 저장이 아니라 의도의 기록이다. 미래의 동료(그리고 미래의 나)가 왜 이 코드가 생겼는가를 커밋 메시지만 보고 이해할 수 있어야 합니다. git commit -m "수정"은 커밋이 아닙니다.
PR은 코드 제출이 아니라 팀과의 대화다. 변경 이유, 구현 선택의 근거, 테스트 방법을 명확히 담은 PR은 리뷰어의 시간을 아끼고 팀의 신뢰를 쌓습니다.
README는 기술 나열이 아니라 존재 이유에서 시작한다. 이 프로젝트는 어떤 문제를 해결하는가라는 질문에 첫 문단에서 답해야 합니다. 이 질문에 답하지 못하는 README는, 작성자 스스로도 이 프로젝트가 왜 필요한지 모른다는 신호입니다.
마치며
Issue에서 시작해 PR로 마무리되는 흐름이 자연스러워질수록, 팀의 코드베이스는 더 읽기 쉬워집니다. 도구가 아니라 습관의 문제입니다.