Git을 넘어 — 오픈소스 기여자의 세계로 (상세)
이 글은 “Git을 넘어 — 오픈소스 기여자의 세계로” 강의의 상세 내용입니다. 강의 개요는 여기에서 확인할 수 있습니다.
선수 강의: Git & GitHub으로 협업하며 개발하기
이 내용을 슬라이드로 보려면 프레젠테이션 모드를 이용하세요.
Part 1 — 도입: 우리가 매일 쓰는 도구는 모두 오픈소스
오늘 강의실에 들어오면서 쓴 도구를 떠올려 보자
| 분류 | 도구 | 형태 |
|---|---|---|
| 운영체제 | Linux, Android, macOS의 다수 컴포넌트 | 대부분 오픈소스 또는 OSS 기반 |
| 웹 브라우저 | Chrome(Chromium), Firefox, Safari(WebKit), Edge(Chromium) | 모두 오픈소스 엔진 |
| 에디터 | VS Code, Vim, Neovim, IntelliJ Community | 핵심 또는 전체가 오픈소스 |
| 언어·런타임 | Python, Node.js, Java(OpenJDK), Go, Rust | 전부 오픈소스 |
| AI 도구 | Claude Code(설치형), Cursor(VS Code fork), Ollama | OSS 기반 또는 일부 오픈소스 |
오늘 우리가 만지는 거의 모든 소프트웨어는 누군가의 PR 머지로 만들어졌습니다.
그 “누군가” 가 오늘 강의가 끝나면 여러분이 될 수도 있습니다.
첫 PR은 거의 항상 사소합니다
유명 메인테이너의 GitHub 활동을 거슬러 올라가 보면, 시작은 거의 항상 README 오타 수정, 번역 한 줄, 에러 메시지 개선 같은 작은 PR입니다.
대단한 알고리즘 기여나 새 기능이 첫 단추가 아닙니다.
이 점을 실제 사례로 확인해 봅시다. 강의 첫 5분에 강사가 라이브로 보여 줄 페이지와, 각 화면에서 학생에게 가리킬 정확한 지점을 정리합니다.
라이브 데모 1 — “방금 강의자료를 그릴 때 쓴 그 도구”
excalidraw.com으로 잠깐 가서 한 도형을 그리고, “방금 이 강의 자료에 들어간 도식이 여기서 그려졌습니다” 라고 말한다.- 곧바로 GitHub 저장소로 전환: https://github.com/excalidraw/excalidraw
- README 상단의 뱃지들 (license MIT, stars, contributors) 을 가리키며 “오픈소스” 임을 시각적으로 확인.
- Insights → Contributors 클릭 — 수백 명이 commit 한 사실을 보여 줌. 이 페이지가 “사람들” 을 시각화하는 곳임.
라이브 데모 2 — 실제로 1글자만 바꾼 PR 한 개
학생에게 가리킬 지점들:
| PR 페이지의 무엇을 본다 | 무엇을 말한다 |
|---|---|
| 제목 | “Fix typo in Discord badge URL parameter” — 8단어로 무엇이 바뀌었는지 명확 |
| Files changed 탭 | 변경된 파일: README.md 1개. 라인 수: +1 / -1 |
| 실제 diff | widge=false → widget=false — 글자 그대로 한 글자 추가 |
| Conversation 탭 | 별도 리뷰 코멘트 없음. CI 통과 후 메인테이너 dwelle이 바로 머지 |
| 작성자 프로필 클릭 | github.com/NANDGOPALSHARMA-29 — Excalidraw에 보낸 PR은 이것 1개뿐 |
핵심 메시지: “한 글자 수정도 PR이 되고, 메인테이너가 환영하며, 머지된다.”
라이브 데모 3 — 한 단계 진보된 첫 PR (코드 수정)
이 PR이 보여 주는 것들:
- 문제 진단 — Ctrl+Y 단축키가 Windows에서만 작동하던 버그. 작성자가 평소 Linux를 쓰다가 발견.
- 변경 위치 —
packages/excalidraw/actions/actionHistory.tsx한 파일. - 변경 코드 —
isWindows && event.ctrlKey && ...의isWindows조건 제거. - 리뷰 상호작용 — 메인테이너 dwelle이 “Mac에서는 Ctrl+Cmd+Y가 더 적절합니다” 라고 제안.
- 작성자 응답 — 한 번 더 commit을 추가해 Mac 케이스 분리.
- 머지 — auto-merge(squash) 활성화로 자동 머지.
학생에게 강조할 점:
“이 PR은 어떤 사람이 평소 도구를 쓰다가 불편함을 느꼈고, 그게 몇 줄짜리 수정으로 해결되었고,
메인테이너가 그 수정을 더 좋게 다듬어 주었습니다. 이게 오픈소스 기여의 가장 흔한 모양입니다.”
라이브 데모 4 — “이 사람들의 첫 PR이 이거였다는 것”
앞에서 본 두 PR의 작성자 프로필을 각각 열어 같은 사실을 확인:
- PR #11096 작성자 →
github.com/NANDGOPALSHARMA-29?tab=overview→ Pull Shark 뱃지, Repositories 탭 → 본인 사이드 프로젝트만 18개. Excalidraw에 보낸 PR은 PR #11096 그 1개뿐 - PR #11179 작성자 →
github.com/sznmelvin→ Excalidraw에 보낸 PR은 PR #11179 그 1개뿐
메시지의 핵심:
“이 두 사람 모두 Excalidraw의 메인테이너가 아닙니다. 그저 사용자였고, 불편함을 느꼈고, PR로 고쳤습니다.
강의가 끝나면 여러분도 이 페이지에 한 줄 들어갈 수 있습니다.”
가벼운 리뷰: fork → branch → commit → PR → merge
이미 알고 있는 내용이지만, 이번 강의의 출발선을 맞추기 위해 한 번 정리합니다:
이 흐름은 이번 강의 내내 배경 음악처럼 깔립니다.
다만 강의의 초점은 이 화살표 위에 — 각 단계에서 사람들이 무엇을 하고, 어떤 권한을 가지며, 어떤 매너로 소통하는지에 있습니다.
Part 2 — GitHub의 사람들과 권한
왜 “권한과 역할” 부터 시작하나
학생들이 가장 자주 묻는 질문 중 하나:
“내가 PR을 보내면 누가 머지하나요?”
답은 단순합니다 — 머지 권한을 가진 사람입니다.
그 권한이 어떻게 분배되어 있는지, 그리고 그 권한이 어떻게 비공식 위계 로 연결되는지 알면 오픈소스 프로젝트의 절반이 보입니다.
Repository roles — GitHub이 부여하는 5단계 권한
| 권한 단계 | 할 수 있는 것 | 대표 사용처 |
|---|---|---|
| Read | 코드 보기, 이슈/PR 열기, 코멘트 작성 | 외부 협업자, 감사자 |
| Triage | Read + 이슈/PR 라벨링·할당·닫기 (코드 변경은 못함) | Triage 자원봉사자 |
| Write | Triage + 브랜치 push, PR 머지(제한적), 리뷰 제출 | 일반 팀원 |
| Maintain | Write + 저장소 설정 일부 변경 (제외: 권한 부여, 삭제, billing) | 프로젝트 메인테이너 |
| Admin | 모든 권한 (권한 부여, 삭제, billing 포함) | 조직 소유자 |
Settings → Collaborators 메뉴에서 사람마다 위 단계 중 하나를 부여합니다.
같은 사람이라도 저장소마다 다른 권한을 가질 수 있습니다.
Organization roles — 조직 단위의 권한
| 역할 | 의미 |
|---|---|
| Owner | 조직 자체의 모든 권한 (멤버 추가/제거, billing, 모든 저장소) |
| Member | 조직의 일반 멤버. 저장소별 권한은 따로 부여됨 |
| Outside collaborator | 조직 멤버가 아닌 외부인. 특정 저장소에만 권한이 부여됨 |
조직 권한과 저장소 권한은 별도입니다.
조직의 Owner라고 해서 모든 저장소를 자동으로 Admin으로 다루는 건 아니지만, 대부분의 경우 그렇게 설정됩니다.
인터랙티브: 역할별 권한 매트릭스
아래 데모에서 역할을 클릭하면 그 역할이 할 수 있는 일과 할 수 없는 일이 즉시 표시됩니다.
“내가 지금 이 저장소에서 무슨 권한이 있는가” 를 머릿속에 그릴 때 도움이 됩니다.
비공식 위계 — GitHub 권한과는 별도의 사회적 구조
GitHub이 부여하는 권한 위에, 오픈소스 커뮤니티는 사회적 위계를 별도로 가집니다.
이 구분이 처음 기여하는 사람에게 가장 헷갈리는 지점입니다.
| 비공식 역할 | 누구인가 | 어떻게 되는가 |
|---|---|---|
| Contributor | PR이 1회 이상 머지된 사람 | PR 제출 + 머지로 자동 |
| Committer | 저장소에 직접 push할 수 있도록 권한받은 사람 | 메인테이너가 GitHub Write 권한 부여 |
| Reviewer | PR을 검토할 자격이 명시된 사람 (CODEOWNERS, 팀 멤버 등) | 프로젝트가 정한 기준에 따라 지명 |
| Maintainer | 머지·릴리스·정책 결정에 실질 권한이 있는 사람 | 오랜 기여 + 커뮤니티 합의 |
| Core / TSC | 프로젝트의 거버넌스 자체를 결정 (방향성, 분쟁 해결) | 정관 또는 공식 선출 절차 |
핵심 통찰: GitHub 권한(Read/Triage/Write/Maintain/Admin)은 “기술적 권한” 이고,
Contributor/Committer/Maintainer/Core는 “사회적 역할” 입니다.
같은 사람이 두 측면에서 다른 위치에 있을 수 있습니다.
사례: Kubernetes 거버넌스 (SIG 구조)
대형 OSS 프로젝트의 거버넌스가 어떻게 구조화되는지 가장 시각적으로 잘 보여 주는 예입니다.
라이브로 둘러볼 페이지:
- kubernetes/community/sig-list.md — Special Interest Group들의 목록 (storage, network, auth, …)
- 루트 디렉토리의
sig-*폴더들 — sig-network, sig-storage, sig-node 등. 각 SIG는 코드 소유권을 가진 영구 작업 그룹 - 루트 디렉토리의
wg-*폴더들 — wg-batch, wg-ai-gateway 등. 여러 SIG에 걸친 임시 조직, 코드 소유권 없음 - 각 SIG 폴더 안쪽 — README에 Subproject 목록이 있음. SIG 내부의 더 작은 작업 단위 (예: sig-network/README.md 안의 KEP, CNI, kube-proxy 등)
- 각 SIG의
OWNERS파일 (sig-node 예시) — Approver / Reviewer 가 명시됨 - committee-steering/ — Steering Committee (선출제, 임기 있음)
정리한 계층 관계:
학생들에게 던질 만한 질문:
“우리가 본 README의 한 줄 수정 PR은 이 거대한 계층 어디에서 머지될까?”
답: 보통 해당 영역 SIG의 reviewer 1명 + approver 1명이 LGTM/approve를 주면 머지됩니다.
Steering Committee가 직접 머지에 관여하지는 않습니다.
거버넌스는 “방향성” 을 정하고, 실제 코드 머지는 SIG 안에서 자율적으로 일어납니다.
GitHub 프로필의 시각적 신호
기여자의 GitHub 프로필은 이력서이자 평판 시스템입니다. 메인테이너는 PR 작성자의 프로필을 종종 빠르게 훑어 봅니다.
확인되는 신호들:
| 신호 | 의미 |
|---|---|
| Contribution graph | 활동의 꾸준함 (단발성 vs 지속적) |
| Achievements 뱃지 | Pull Shark, Galaxy Brain, Quickdraw 등 — 약하지만 신호 |
| Pro / Sponsor 뱃지 | 유료 사용자 또는 후원자 |
| Pinned repositories | 본인이 자랑할 만한 작업 |
| Insights → Contributors (저장소) | 해당 프로젝트에서 작성자의 누적 PR 수 |
| Followers / Stars | 영향력의 약한 지표 |
과대 해석은 금물입니다. 좋은 프로필이 아니어도 좋은 PR이 가능하고, 화려한 프로필이 PR의 품질을 보장하지도 않습니다.
다만 메인테이너의 첫 인상에 영향을 주는 건 사실입니다.
강의 중 인터랙티브 활동
학생들에게 다음을 권장합니다:
- 자기 프로필을 열고
github.com/<id>화면 확인 - 강사가 보여 주는 유명 메인테이너 프로필(예: sindresorhus, gaearon, antfu)과 비교
- “내 프로필이 5년 뒤에 어떻게 보였으면 좋겠는가” 를 머릿속으로 그려 보기
Part 3 — 오픈소스 프로젝트의 해부학
프로젝트의 첫인상은 코드가 아니라 메타파일에서 만들어진다
오픈소스 저장소를 처음 만났을 때, 메인테이너가 기여자에게 의도적으로 보여 주는 정보는 코드 자체가 아니라 루트의 메타파일들입니다.
이것들을 빠르게 읽는 능력이 곧 “오픈소스 문해력” 입니다.
인터랙티브: OSS 프로젝트의 해부도
아래 데모는 일반적인 오픈소스 저장소 화면을 가상으로 옮긴 것입니다.
각 영역을 클릭하면 그 영역이 무엇이고, 왜 중요한지 즉시 표시됩니다.
라이선스 — 모든 결정의 토대
오픈소스의 시작은 라이선스입니다. 라이선스가 없는 코드는 GitHub에 공개되어 있어도 법적으로 “권리 보유 전부” 입니다.
| 라이선스 | 핵심 성격 | 파생물 라이선스 제약 | 상업 제품 사용 (closed source 포함) | 대표 사용처 |
|---|---|---|---|---|
| MIT | 가장 자유로움 — “표시만 해 줘” | 없음 — 어떤 라이선스로든 재배포 | ✅ 제약 없음 | React, Vue, Express, jQuery |
| Apache 2.0 | MIT + 특허권 명시 보호 | 없음 (NOTICE 보존 필수) | ✅ 제약 없음 (NOTICE 포함) | Kubernetes, Android, TensorFlow |
| BSD 2/3-Clause | MIT와 유사, 더 엄격한 표시 조항 | 없음 | ✅ 제약 없음 (저작권 표시 의무) | FreeBSD, Go |
| GPL v3 | “이 코드를 쓴 결과물도 GPL로 공개해야 함” — 강한 카피레프트 | 강함 | ⚠️ 가능하나 파생물 소스 공개 의무 | Linux 커널, GIMP, GCC |
| LGPL | 라이브러리 링크는 자유, 라이브러리 수정 시 GPL 적용 | 중간 | ✅ 동적 링크 사용 자유 (라이브러리 수정 시 공개) | glibc, FFmpeg(LGPL 모드) |
| AGPL v3 | GPL + “네트워크로 접근 가능하게 한 경우에도 소스 공개 의무” | 매우 강함 | ⚠️ SaaS 형태도 소스 공개 의무 (사실상 closed source 불가) | MongoDB(과거), Mastodon |
카피레프트(Copyleft) 는 GPL 계열의 핵심 개념입니다.
“이 코드의 파생물도 똑같은 자유를 보장해야 한다” 는 의미로, 결과적으로 상용 폐쇄 소스 와 섞기 어렵게 만듭니다.
MIT/Apache는 카피레프트가 없어 기업이 가져다 쓰기 쉽고, 그래서 산업계에 가장 널리 퍼져 있습니다.
README의 미학
좋은 README는 3분 안에 다음 질문에 답해야 합니다:
- 이게 무엇을 하는 도구인가? (한 줄)
- 왜 이걸 쓰는가? (alternatives 대비)
- 어떻게 빨리 설치/실행하는가?
- 더 자세히 알려면 어디로 가는가?
좋은 README의 시각 요소:
- 로고 또는 hero 이미지 — 프로젝트의 정체성
- shields.io 뱃지 — 빌드 상태, npm 다운로드 수, 라이선스, 버전
- 데모 GIF 또는 스크린샷 — 동작이 한눈에 보임
- 빠른 시작 코드 블록 — 복사·붙여넣기로 바로 실행
- 상세 문서 링크 — 깊이 들어가는 사람을 위한 출구
기여자 인프라 — .github/ 디렉토리 안쪽
대부분의 활발한 OSS는 저장소 루트의 .github/ 폴더에 기여자 가이드 와 자동화 정책을 모아 둡니다.
| 파일 | 역할 |
|---|---|
CONTRIBUTING.md | 기여 방법 — 이슈 작성, PR 양식, 커밋 컨벤션, 테스트 실행법 |
CODE_OF_CONDUCT.md | 커뮤니티 행동 강령 (보통 Contributor Covenant 1.4 또는 2.x) |
ISSUE_TEMPLATE/ | 버그 리포트, 기능 제안 등 이슈 양식 |
PULL_REQUEST_TEMPLATE.md | PR 양식 (체크리스트, 변경 요약, 관련 이슈 링크 등) |
FUNDING.yml | “Sponsor” 버튼에 연결되는 결제·후원 채널 |
workflows/*.yml | GitHub Actions (CI/CD) |
dependabot.yml | 의존성 자동 업데이트 설정 |
CODEOWNERS | 파일/디렉토리별 자동 리뷰어 지정 |
CODEOWNERS 는 특히 자주 간과되지만 중요합니다.
“이 파일을 건드리는 PR은 자동으로 이 사람이 리뷰어로 지정된다” 는 규칙을 명시합니다.
큰 프로젝트에서 리뷰가 “올바른 사람에게” 가는 비결이 여기 있습니다.
Labels — 색깔로 분류하는 작업의 종류
| 자주 보이는 라벨 | 의미 |
|---|---|
good first issue | 첫 기여자에게 추천 — 범위가 명확하고 작음 |
help wanted | 메인테이너가 외부 도움을 환영하는 이슈 |
bug / enhancement | 버그 / 새 기능 |
documentation | 문서 개선 |
breaking change | 호환성을 깨는 변경 — 신중하게 |
wontfix / invalid | 닫힌 사유 |
needs triage | 분류 대기 |
GitHub 검색에서 라벨을 활용하면 첫 이슈를 빠르게 찾을 수 있습니다:
| |
자동화 흔적들 — CI 뱃지, Dependabot, Releases
활발한 프로젝트는 README와 PR 페이지에 자동화의 흔적이 가득합니다:
- CI 뱃지 — GitHub Actions / CircleCI / Travis 의 빌드 상태 (
passing/failing) - Dependabot PR — 의존성 라이브러리 새 버전이 나오면 자동으로 업데이트 PR이 열림
- Releases —
v1.2.3같은 태그, GitHub Releases 페이지에 자동 생성된 changelog - Semantic Versioning —
MAJOR.MINOR.PATCH의 약속 - Conventional Commits —
feat:,fix:,chore:같은 커밋 prefix 컨벤션
이 흔적들의 활발도가 곧 프로젝트의 건강 지표 입니다.
Dependabot PR이 6개월째 쌓여 있고 CI가 빨갛다면, 메인테이너의 손이 잠시 떠난 신호일 수 있습니다.
로드맵 & 의사결정 — RFC, PEP, TC39
큰 OSS(Open Source Software)는 큰 변경을 PR 하나로 처리하지 않습니다.
사전 합의 절차 가 별도로 존재합니다.
| 프로세스 | 프로젝트 | 역할 |
|---|---|---|
| RFC | Rust, React, Vue | 설계 제안서 — 코드 작성 전에 토론 |
| PEP | Python | Python Enhancement Proposal — 언어 변경의 공식 경로 |
| TC39 stage | JavaScript | ECMAScript 표준 제안 절차 (Stage 0~4) |
| KEP | Kubernetes | Kubernetes Enhancement Proposal |
학생들이 알아둘 점: 언어·표준에 가까울수록 PR보다 RFC가 우선입니다.
코드를 들고 가기 전에 “이 변경이 받아들여질 수 있는가” 를 먼저 글로 합의합니다.
커뮤니티 채널 — 어디서 묻나
프로젝트마다 1차 응답이 일어나는 채널이 다릅니다:
| 채널 | 자주 쓰이는 곳 | 성격 |
|---|---|---|
| GitHub Issues | 거의 모든 프로젝트 | 공식적, 검색됨, 영구 보존 |
| GitHub Discussions | 점점 늘어남 | Q&A, 아이디어 토론 |
| Discord | 프론트엔드 진영(React, Vue, Vite), 게임 엔진 | 빠른 캐주얼 토론 |
| Slack | 기업 주도 OSS, Kubernetes(CNCF 슬랙) | 워킹 그룹별 채널 |
| Matrix/IRC | Linux, KDE, 전통 OSS | 자유 소프트웨어 문화 |
| 메일링 리스트 | Linux kernel, GCC, Python core | 가장 보수적, 검색이 어렵지만 영구 보존 |
PR을 보내기 전에 채널에서 한 번 묻는 것 이 흔히 유효한 습관입니다.
“이 방향으로 PR을 준비하려는데 환영하시나요?” 식의 가벼운 질문은 PR이 폐기될 위험을 크게 줄여 줍니다.
Part 4 — 실제 PR 사례 워킹: Mermaid
왜 사례 워킹이 중요한가
PR 작성법을 추상적으로 설명하는 것보다 실제 머지된 PR과 거절된 PR을 한 줄씩 읽는 것 이 훨씬 강력합니다.
의사결정의 결이 코멘트 한 줄 한 줄에 드러나기 때문입니다.
이 강의에서는 Mermaid (markdown diagram 도구) 의 실제 PR을 사례로 사용합니다.
PR 한 사이클의 단계
인터랙티브: PR Lifecycle Walker
아래 데모에서 단계별로 진행해 보며, 각 단계에서 무엇이 일어나는지 따라가 보세요.
머지되는 PR의 패턴
라이브로 함께 읽을 예시:
이 PR을 라이브로 함께 읽으면서, 다음 6가지 신호를 화면에서 직접 가리켜 보여 줍니다:
| 강사가 강조하는 신호 | 이 PR에서 어떻게 나타나나 |
|---|---|
| 이슈와 PR의 연결 | PR 설명 상단에 Resolves #6336 — 이슈 페이지 (Self-edges/loops 가 어색하게 보이는 버그)로 클릭만 하면 이동. 양쪽이 자동으로 묶임 |
| PR 설명문의 구조 | Summary → Background (근본 원인 분석) → Before/After (GIF·스크린샷) → Design Decisions → Tasks (체크리스트). “왜·무엇·어떻게” 가 명확히 분리 |
| 작은 단위 | 약 229줄 변경. 4개 파일 (핵심 로직 1 + 단위 테스트 1 + Cypress E2E 2). 200~400줄 “평균” 범위에 정확히 들어맞음 |
| 메인테이너의 응답 속도 | 첫 PR 제출 후 며칠 안에 리뷰어 ashishjain0512가 11개 코멘트로 첫 리뷰. 활발한 프로젝트의 모습 |
| 리뷰 코멘트의 톤 | “제목은 dagre인데 실제로는 flowchart와 state diagram을 다루는데, 의도가 맞나요?” — 공격이 아니라 질문. 작성자가 방어 대신 범위 확대로 응답 |
| 머지 직전 마지막 커밋 | 두 라운드 리뷰 후 모든 지적 사항 반영. 마지막 commit이 “Cypress E2E 케이스 추가 + 코드 스타일 정리”. 리뷰를 받아들인 흔적 이 그래프에 남음 |
PR 페이지에서 라이브로 클릭할 정확한 지점
- PR 제목: 컨벤셔널 커밋 형식 (
fix(dagre):) 으로 시작 — 한눈에 “버그 수정 / dagre 영역” 임을 알 수 있음 - PR 설명문 상단:
Resolves #6336링크 클릭 → 원본 이슈로 이동. 이슈에 사용자가 올린 GIF가 있어 문제가 시각적으로 명확 - Files changed 탭: 4개 파일. 코드 변경과 테스트 변경이 같은 PR 에 들어 있다는 점이 핵심
- Conversation 탭 중 ashishjain0512의 첫 리뷰: 인라인 코멘트 11개 → 그중 핵심 2개를 강조해서 읽어 줌
- Conversation 탭 끝: 작성자가 새 commit을 push 한 흔적 — 리뷰 후 어떻게 대응했는지 시간 순으로 보임
- 머지 직후의 commit graph: squash로 1개 commit이 main에 추가됨. 머지된 commit 메시지가 PR 제목과 그대로 매칭
핵심 메시지:
이 PR이 머지된 이유는 코드가 천재적이어서가 아니라,
이슈 → 근본 원인 → 설계 결정 → 코드 + 테스트 → 리뷰 수용 의 흐름이 명확하게 드러나기 때문입니다.
좋은 PR은 코드 품질이 아니라 “맥락의 전달” 에서 갈립니다.
거절되거나 논쟁된 PR의 패턴
거절된 PR도 보물입니다 — 무엇이 어긋났는지가 코멘트에 적혀 있습니다.
| 자주 보이는 거절 사유 | 메인테이너의 표현 예시 |
|---|---|
| 프로젝트 방향과 맞지 않음 | “We’ve decided not to support X. See #1234.” |
| 이슈에서 사전 합의가 없었음 | “Please open an issue first to discuss this.” |
| 너무 큰 범위 | “Could you split this into smaller PRs?” |
| 기존 패턴과 다른 스타일 | “This doesn’t follow our existing conventions.” |
| 테스트가 없음 | “Please add tests covering the new behavior.” |
| 이미 다른 PR에서 진행 중 | “Closing in favor of #5678.” |
핵심 통찰:
거절된 PR의 대부분은 “코드가 나쁘다” 가 아니라 “맥락이 빠졌다” 입니다.
이슈에서 사전 합의가 없었거나, 프로젝트의 방향성을 모르고 보낸 PR이 가장 흔한 거절 사유입니다.
CLA / DCO / sign-off
큰 OSS (특히 기업 주도, 재단 산하)는 PR을 머지하기 전에 법적 동의 를 요구합니다.
| 메커니즘 | 풀네임 | 동작 방식 |
|---|---|---|
| CLA | Contributor License Agreement | 처음 PR 보낼 때 봇이 자동 서명 링크를 요청 — 1회 서명하면 영구 적용 |
| DCO | Developer Certificate of Origin | 매 커밋의 푸터에 Signed-off-by: 라인 — git commit -s 로 자동 추가 |
CLA가 필요한 대표 프로젝트:
- Google 산하 (Kubernetes, gRPC, Angular, TensorFlow)
- Apache Software Foundation 프로젝트
- Eclipse Foundation
- Microsoft .NET
DCO를 쓰는 대표 프로젝트:
- Linux 커널
- Docker / Moby
- GitLab
git commit -s 시연:
| |
-s 플래그가 자동으로 마지막 줄에 sign-off를 추가합니다.
한 번 실수로 빠뜨리면 봇이 PR을 차단하고, git commit --amend -s 또는 rebase로 다시 sign-off 해야 합니다.
Part 5 — 코드 외 기여의 길
“첫 PR이 꼭 코드일 필요는 없다”
오픈소스 커뮤니티에서 코드 외 기여는 종종 더 환영받습니다.
이유는 단순합니다 — 코드를 쓸 사람은 많지만, 문서/번역/트리아지를 하려는 사람은 항상 부족하기 때문입니다.
코드 외 기여의 종류
| 기여 종류 | 무엇을 하는가 | 어디서 시작할까 |
|---|---|---|
| 번역 (i18n) | UI 문자열, 문서, 에러 메시지의 다국어화 | Crowdin, Transifex, 또는 저장소의 locale/ 디렉토리 |
| 문서 개선 | 오타, 끊어진 링크, 누락된 설명, 새 튜토리얼 | “Edit on GitHub” 링크 → 직접 수정 PR |
| 이슈 재현 | 버그 리포트의 재현 단계를 직접 시도, 정확한 재현 환경 정리 | needs triage 라벨 이슈 |
| 이슈 트리아지 | 오래된 이슈 정리, 라벨링, 중복 이슈 묶기 | Triage 권한이 부여되면 더 효율적 |
| 디자인 | 로고, 아이콘, 일러스트, README의 hero 이미지 | 디자이너 환영 명시 프로젝트 |
| 코드 리뷰 | 다른 사람의 PR 리뷰 — 권한 없이도 의견 코멘트 가능 | PR 페이지에서 “Files changed” 보고 코멘트 |
| 블로그 / 튜토리얼 | 외부에 글을 쓰면서 해당 프로젝트의 가시성을 높임 | 본인 블로그, dev.to, Medium |
| 컨퍼런스 발표 | 그 프로젝트를 주제로 발표하기 | meetup, 사내 발표부터 |
번역 기여의 진입장벽이 가장 낮은 이유
- 코드를 이해할 필요가 적음 (UI 문자열만 다루는 경우 다수)
- 한국어 화자가 PR을 보내면 검토자 풀이 작아 빠르게 머지되는 경우 많음
- 메인테이너가 비영어권 사용자를 위해 적극 환영
- 첫 PR로 “Contributor” 뱃지를 받기에 충분
예: VS Code의 한국어 번역, React 한국어 문서, MDN 한국어, Excalidraw의 다국어 등은 모두 외부 번역 기여자가 큰 몫을 합니다.
코드 외 기여의 “보이지 않는 가치”
학생들이 종종 오해하는 점:
“코드 외 기여는 가벼운 기여” 가 아닙니다.
큰 OSS의 메인테이너가 가장 자주 번아웃되는 영역이 바로 이슈 트리아지, 문서 정리, 커뮤니티 응대 입니다.
이 영역을 도와주는 기여자는 메인테이너에게 깊은 신뢰를 얻습니다.
Part 6 — 실습 + 강사 시연
학생 실습 (10분): first-contributions
가장 마찰이 없는 첫 PR 경험입니다.
학생이 강의 중에 따라 할 단계:
- 저장소 페이지 우상단 Fork 클릭 → 내 계정으로 복제
- 내 fork 페이지에서 Add file → Create new file (또는 Clone 후 로컬 작업)
Contributors.md의 alphabetical 위치에 본인 이름과 GitHub 링크 한 줄 추가- Commit message:
Add <your-name> - Pull request 열기 — base:
firstcontributions:main, compare:<you>:main - PR 설명에 간단한 자기소개 한 줄
- 자동 봇이 곧 환영 메시지를 남기고, 메인테이너가 짧은 시간 내 머지
이 한 PR이 여러분의 GitHub contribution graph에 첫 초록색 칸 을 찍는 순간입니다.
강사 시연 (13분): TimeCountdown 으로 PR 한 사이클 전체
학생 실습이 끝난 직후, 강사는 본인의 실제 저장소로 양쪽 관점 을 모두 시연합니다.
시연 환경
| 항목 | 구성 |
|---|---|
| 메인 계정 | CodeCompose7 — TimeCountdown 저장소 소유 (메인테이너 역할) |
| 더미 계정 | 강사의 다른 계정 (Contributor 역할) |
| 사전 준비 | TimeCountdown 저장소에 good first issue 라벨이 붙은 이슈 1개 |
| 브라우저 | 두 계정을 동시에 보기 위해 일반창 + 시크릿창, 또는 두 개의 브라우저 |
Step 1 — 메인 계정 (받는 쪽): 이슈 확인
- github.com/CodeCompose7/TimeCountdown/issues 열기
- 사전 준비된 이슈를 보여 줌
- 제목·라벨·재현 단계가 어떻게 구조화되어 있는지 강조
- 이슈에 적힌
good first issue라벨, 명확한 작업 범위, 메인테이너의 사전 환영 코멘트 확인
Step 2 — 더미 계정 (보내는 쪽): Fork & Clone
- 더미 계정으로 로그인된 브라우저에서 같은 저장소 열기
- Fork 클릭 — 자기 계정으로 복제
- fork 페이지에서 키보드
.(마침표) 키 누르기 → 같은 저장소가github.dev에서 열림 (브라우저 안 VS Code 에디터)- URL 의
github.com을github.dev로 직접 바꿔도 동일 - (또는 로컬 Clone 후 에디터 작업 — 시연에서는 빠른 흐름을 위해 web editor 추천)
- URL 의
Step 3 — 더미 계정: 브랜치 + 변경
- web editor 또는 로컬에서
fix/<issue-내용>(예시fix/reset-confirm) 브랜치 생성 - 이슈에서 요구한 변경을 적용
- 의미 있는 commit message 작성 — 예:
Add reset confirmation dialog (#3)(#3)처럼 이슈 번호를 명시하면 PR과 이슈가 자동 연결됨
- push
Step 4 — 더미 계정: PR 열기
fork 페이지에 자동 표시되는 Compare & pull request 클릭
PR 양식 작성:
1 2 3 4 5 6 7 8 9 10 11 12 13## Why Closes #3. Currently the reset button immediately wipes the timer without confirmation, which is easy to trigger by accident. ## What - Add a confirm dialog before reset - Allow ESC to cancel the dialog ## How tested - Clicked Reset → dialog appears → Confirm wipes, Cancel keeps state - Tested on Chrome 130 / Safari 17base:
CodeCompose7:main, compare:<더미 계정>:fix/reset-confirm확인Create pull request 제출
Step 5 — 메인 계정 (받는 쪽): PR 알림 & 리뷰
브라우저를 메인 계정 쪽으로 전환:
- Notifications 또는 메일에서 PR 알림 확인 → 클릭
- Conversation 탭 — PR 설명문 읽기
- Files changed 탭 → diff 확인
- 변경 라인 옆
+버튼 클릭 → 인라인 코멘트 작성 (예: “이 부분 ESC 키 처리를 별도 함수로 빼는 게 어떨까요?”) - Start a review → 여러 코멘트를 모아 한 번에 보내기
Step 6 — 리뷰 옵션 비교 시연
Review changes 메뉴를 열어 셋의 차이를 보여 줌:
| 옵션 | 효과 |
|---|---|
| Comment | 코멘트만 제출 — 승인/거절 의사 없음 |
| Approve | 명시적으로 LGTM. 보호된 브랜치에서 머지 가능 상태로 |
| Request changes | 명시적 거절 — 작성자가 변경 후 다시 요청해야 머지 가능 |
이번 시연에서는 Request changes 를 선택하고, 위에서 적은 코멘트들을 묶어 제출.
Step 7 — Suggested changes 블록 시연
주의: “Suggested changes (suggestion 블록)” 은 PR 전체에 대한 Request changes 결론과 다른 기능입니다.
Request changes 는 우상단 Review changes 메뉴의 리뷰 결론,
Suggested changes 는 인라인 코멘트 안에 코드 수정안을 박아 넣는 블록 입니다.
위치를 라이브로 짚어 줍니다:
- Files changed 탭에서 코드 라인 옆
+클릭 → 코멘트 박스 열림 - 코멘트 박스 상단 툴바 의 오른쪽 끝, 종이에
+/-가 붙은 모양의 아이콘 (호버 시 “Add a suggestion”) 클릭 - 코멘트 박스에 자동으로
suggestion코드 블록 템플릿이 채워짐 — 그 라인의 현재 코드 가 먼저 들어옴 - 그 코드를 원하는 형태로 직접 수정한 뒤 코멘트 제출
예시:
| |
이 블록은 작성자가 Commit suggestion 버튼 하나로 즉시 반영할 수 있습니다.
리뷰어의 친절함이 코드 변경 한 줄로 도착하는 가장 매끄러운 UX 중 하나입니다.
Step 8 — 더미 계정: 변경 요청에 응답
브라우저를 더미 계정으로 전환:
- PR 알림 확인 → 코멘트 읽기
- Commit suggestion 클릭 — 리뷰어의 제안을 그대로 적용
- 나머지 의견에는 답글 작성 — “좋은 지적입니다. 다음 커밋에 반영하겠습니다.”
- 로컬(또는 web editor)에서 추가 수정 → 새 commit → push
- PR 화면에 자동으로 새 커밋이 표시됨
Step 9 — (선택) 컨플릭트 만들고 해결
- 메인 계정에서 main 브랜치에 사소한 변경을 push (의도적 컨플릭트 유발)
- 더미 계정의 PR 페이지 하단에 “This branch has conflicts that must be resolved” 표시
- Resolve conflicts 버튼 → GitHub 웹 에디터에서
<<<<<<< HEAD,=======,>>>>>>> main마커 확인 - 양쪽 코드 중 어느 쪽을 살릴지 결정 → Mark as resolved → Commit merge
Step 10 — 메인 계정: 승인 & 머지
- Review changes → Approve 로 승인
- Merge pull request 버튼 옆 드롭다운 클릭 → 세 가지 옵션 시연:
| 옵션 | 결과 |
|---|---|
| Create a merge commit | 머지 커밋이 남고 브랜치 모양이 그래프에 보존 |
| Squash and merge | PR 안 모든 커밋을 1개로 압축해서 main에 머지 — “1 PR = 1 commit” 정책 |
| Rebase and merge | 머지 커밋 없이 일렬로 — 깨끗한 일직선 히스토리 |
이번 시연에서는 Squash and merge 선택 → 머지 메시지 정리 → confirm.
Step 11 — 닫힌 후의 흐름
- PR이 자동으로 닫히고, 연결된 이슈 #3도 자동으로 close
- 더미 계정의 fork에서
fix/reset-confirm브랜치 삭제 (정리) - 더미 계정의 프로필 contribution graph에 새 초록색 칸 1개
한 사이클 끝.
시연이 학생들에게 남기는 것
- “이슈 → 브랜치 → PR → 리뷰 → 머지” 라는 추상 흐름이 구체적인 화면 클릭의 연속 으로 자리잡음
- 보내는 쪽과 받는 쪽이 같은 화면을 다르게 본다 는 사실 체감
- Squash / Rebase / Merge commit 의 차이를 머지 직전에 처음 만나는 게 아니라, 미리 비교해서 봄
Part 7 — AI 시대의 오픈소스 기여
2026년 현재의 풍경
AI 코드 어시스턴트(Copilot, Cursor, Claude Code, Codeium 등)가 일상화된 후,
오픈소스 메인테이너들은 새로운 PR 패턴을 경험하고 있습니다:
- 짧은 시간에 대량으로 들어오는 “그럴듯해 보이지만 동작하지 않는” PR
- 이슈 설명 없이 AI 생성 코드만 들고 오는 PR
- 라이선스가 의심스러운 코드 조각
이에 대한 프로젝트들의 정책이 갈라지고 있습니다.
AI 생성 PR에 대한 프로젝트별 정책
| 프로젝트 | 입장 |
|---|---|
| curl | “Slop” PR(저품질 AI PR) 거부 — 메인테이너 Daniel Stenberg가 공개 글로 강하게 경고 |
| NetBSD | AI 생성 코드 기여 명시적으로 금지 (commit policy에 기재) |
| Gentoo | AI 생성 contribution 금지 |
| Linux 커널 | 명시적 정책 없음 — 다만 DCO sign-off 책임은 인간이 짐 |
| React, Vue 등 일반 OSS | 대체로 환영하되, 본인이 코드를 이해하고 책임진다는 전제 |
핵심은 “누가 코드의 동작과 라이선스를 보장하는가” 입니다.
AI가 만든 코드여도 PR을 보낸 사람 이 책임을 집니다.
라이선스와 학습 데이터 논쟁
GitHub Copilot, Claude 등이 GPL/AGPL 코드를 학습 데이터로 사용한 것에 대한 법적 다툼이 진행 중입니다.
2025~2026년 현재 명확한 결론은 없으나, 메인테이너로서 의심스러우면 거절하는 것이 보수적인 선택입니다.
기여자가 가질 만한 자세
- 공시 — PR 설명에 “Claude Code로 초안을 작성하고 직접 검토했습니다” 정도 한 줄
- 이해 — 본인이 그 코드를 읽고 수정할 수 있어야 함. AI가 만든 함수의 동작을 설명 못 한다면 그 PR은 보내지 말 것
- 검증 — 환각(존재하지 않는 API 호출) 여부를 사람이 확인
- 컨벤션 일치 — 프로젝트의 코드 스타일에 맞춰 정리
학생들에게 던지는 질문
“여러분이 오픈소스 메인테이너라면, AI 생성 PR에 어떤 정책을 만들겠는가?”
정답은 없습니다. 이 화두를 가지고 강의를 닫는 것이 이번 강의의 마지막 떡밥입니다.
Part 8 — 클로징 & 다음 단계
강의가 끝난 뒤 첫 1주
GitHub Skills 코스 한 개 완주
skills.github.comhttps://skills.github.com/관심사 프로젝트의
good first issue5개 둘러보기- 평소 쓰는 라이브러리/도구 1~2개 선정
- GitHub 검색:
is:issue is:open label:"good first issue" repo:<owner>/<name> - “할 수 있을 것 같다” 싶은 이슈 1개 정해서 코멘트로 의사 표시
번역/문서 기여 1건 — 가장 빠른 첫 Contributor 뱃지 경로
추천 시작점
| 영역 | 추천 프로젝트 |
|---|---|
| 첫 PR 연습 | firstcontributions/first-contributions |
| 튜토리얼 | skills.github.com 의 “Introduction to GitHub”, “Review pull requests” |
| 번역 | 본인이 자주 쓰는 도구의 한국어 번역 디렉토리 |
| 문서 | MDN Web Docs (한국어), React Korean docs, Vue.js 한국어 문서 |
| 시각적으로 좋은 작은 프로젝트 | Excalidraw, Mermaid, shadcn/ui, Astro |
Q&A 시간에 자주 나오는 질문들
- “PR을 보내면 답이 늦게 와요” — 메인테이너 다수가 자원봉사. 1~2주는 정상 범주
- “변경 요청을 받았는데 동의가 안 돼요” — 정중하게 근거를 설명하면 됩니다. “왜 이렇게 결정했는지” 만 또렷이 전하면 충분
- “PR이 close 됐어요” — 거절 자체로도 학습 가치가 큽니다. 코멘트를 다시 읽고 다음 PR에 반영
- “회사 코드 일부를 OSS에 기여해도 되나요?” — 회사 정책 확인 + 라이선스 호환성 확인 필수. 보통 사내 법무팀과 상의
핵심 메시지 다시 보기
| 파트 | 핵심 메시지 |
|---|---|
| Part 1 | 여러분이 매일 쓰는 모든 도구는 오픈소스이고, 그 contributors도 처음엔 한 줄 수정으로 시작했습니다 |
| Part 2 | GitHub은 단순한 코드 저장소가 아니라, 권한과 역할이 다층적으로 설계된 “사회"입니다 |
| Part 3 | 오픈소스 프로젝트는 코드뿐 아니라 라이선스·문서·자동화로 이루어진 하나의 생명체입니다 |
| Part 4 | 좋은 PR과 거절되는 PR의 차이는 “코드의 품질"보다 “맥락의 전달"에 있습니다 |
| Part 5 | 첫 기여는 꼭 코드일 필요가 없습니다 — 번역·문서·트리아지가 더 환영받기도 합니다 |
| Part 6 | PR을 보내는 쪽과 받는 쪽 양쪽을 모두 경험해야 협업의 감각이 완성됩니다 |
| Part 7 | AI 시대에 “누가 코드를 썼는가"의 의미가 다시 쓰이고 있고, 메인테이너의 정책도 갈라지고 있습니다 |
| Part 8 | 다음 PR은 여러분이 가장 좋아하는 프로젝트의 README 오타 수정에서 시작될 수 있습니다 |
참고 자료
- Open Source Guide: https://opensource.guide/
- GitHub Skills: https://skills.github.com/
- choosealicense.com: https://choosealicense.com/
- Contributor Covenant (Code of Conduct): https://www.contributor-covenant.org/
- awesome-readme: https://github.com/matiassingers/awesome-readme
- first-contributions: https://github.com/firstcontributions/first-contributions
- Kubernetes Community: https://github.com/kubernetes/community
- Python PEP Index: https://peps.python.org/
- Rust RFCs: https://github.com/rust-lang/rfcs
- Daniel Stenberg, “The I in LLM stands for intelligence” (curl maintainer essay): https://daniel.haxx.se/blog/2024/01/02/the-i-in-llm-stands-for-intelligence/
- 시연 저장소 TimeCountdown: https://github.com/CodeCompose7/TimeCountdown