Git을 넘어 — 오픈소스 기여자의 세계로 (상세)

2026년 5월 16일 23분

이 글은 “Git을 넘어 — 오픈소스 기여자의 세계로” 강의의 상세 내용입니다. 강의 개요는 여기에서 확인할 수 있습니다.

선수 강의: Git & GitHub으로 협업하며 개발하기

이 내용을 슬라이드로 보려면 프레젠테이션 모드를 이용하세요.

시연 저장소 — TimeCountdown
https://github.com/CodeCompose7/TimeCountdown

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), OllamaOSS 기반 또는 일부 오픈소스

오늘 우리가 만지는 거의 모든 소프트웨어는 누군가의 PR 머지로 만들어졌습니다.
그 “누군가” 가 오늘 강의가 끝나면 여러분이 될 수도 있습니다.

첫 PR은 거의 항상 사소합니다

유명 메인테이너의 GitHub 활동을 거슬러 올라가 보면, 시작은 거의 항상 README 오타 수정, 번역 한 줄, 에러 메시지 개선 같은 작은 PR입니다.
대단한 알고리즘 기여나 새 기능이 첫 단추가 아닙니다.

이 점을 실제 사례로 확인해 봅시다. 강의 첫 5분에 강사가 라이브로 보여 줄 페이지와, 각 화면에서 학생에게 가리킬 정확한 지점을 정리합니다.

라이브 데모 1 — “방금 강의자료를 그릴 때 쓴 그 도구”

excalidraw.com — 강의자료 그릴 때 쓴 그 도구
https://excalidraw.com
  1. excalidraw.com 으로 잠깐 가서 한 도형을 그리고, “방금 이 강의 자료에 들어간 도식이 여기서 그려졌습니다” 라고 말한다.
  2. 곧바로 GitHub 저장소로 전환: https://github.com/excalidraw/excalidraw
  3. README 상단의 뱃지들 (license MIT, stars, contributors) 을 가리키며 “오픈소스” 임을 시각적으로 확인.
  4. Insights → Contributors 클릭 — 수백 명이 commit 한 사실을 보여 줌. 이 페이지가 “사람들” 을 시각화하는 곳임.

라이브 데모 2 — 실제로 1글자만 바꾼 PR 한 개

PR #11096 — Fix typo in Discord badge URL parameter
https://github.com/excalidraw/excalidraw/pull/11096

학생에게 가리킬 지점들:

PR 페이지의 무엇을 본다무엇을 말한다
제목“Fix typo in Discord badge URL parameter” — 8단어로 무엇이 바뀌었는지 명확
Files changed변경된 파일: README.md 1개. 라인 수: +1 / -1
실제 diffwidge=falsewidget=false — 글자 그대로 한 글자 추가
Conversation별도 리뷰 코멘트 없음. CI 통과 후 메인테이너 dwelle이 바로 머지
작성자 프로필 클릭github.com/NANDGOPALSHARMA-29 — Excalidraw에 보낸 PR은 이것 1개뿐

핵심 메시지: “한 글자 수정도 PR이 되고, 메인테이너가 환영하며, 머지된다.”

라이브 데모 3 — 한 단계 진보된 첫 PR (코드 수정)

PR #11179 — enabled ctrl+y redo shortcut on linux and mac
https://github.com/excalidraw/excalidraw/pull/11179

이 PR이 보여 주는 것들:

  1. 문제 진단 — Ctrl+Y 단축키가 Windows에서만 작동하던 버그. 작성자가 평소 Linux를 쓰다가 발견.
  2. 변경 위치packages/excalidraw/actions/actionHistory.tsx 한 파일.
  3. 변경 코드isWindows && event.ctrlKey && ...isWindows 조건 제거.
  4. 리뷰 상호작용 — 메인테이너 dwelle이 “Mac에서는 Ctrl+Cmd+Y가 더 적절합니다” 라고 제안.
  5. 작성자 응답 — 한 번 더 commit을 추가해 Mac 케이스 분리.
  6. 머지 — 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

이미 알고 있는 내용이지만, 이번 강의의 출발선을 맞추기 위해 한 번 정리합니다:

%%{init: {'theme':'base','themeVariables':{'primaryColor':'#e3f2fd','primaryBorderColor':'#90caf9','lineColor':'#546e7a','textColor':'#333','mainBkg':'#fafafa','nodeBorder':'#90a4ae','clusterBkg':'#f5f5f5','clusterBorder':'#bdbdbd'}}}%% flowchart LR A["원본 저장소"] -- "Fork" --> B["내 fork"] B -- "Clone" --> C["로컬"] C -- "Branch + Commit" --> C C -- "Push" --> B B -- "Pull Request" --> A A -- "Review" --> A A -- "Merge" --> A style A fill:#bbdefb,stroke:#1976d2,stroke-width:2px,rx:10,ry:10 style B fill:#fff9c4,stroke:#f9a825,stroke-width:2px,rx:10,ry:10 style C fill:#c8e6c9,stroke:#388e3c,stroke-width:2px,rx:10,ry:10

이 흐름은 이번 강의 내내 배경 음악처럼 깔립니다.
다만 강의의 초점은 이 화살표 위에 — 각 단계에서 사람들이 무엇을 하고, 어떤 권한을 가지며, 어떤 매너로 소통하는지에 있습니다.


Part 2 — GitHub의 사람들과 권한

왜 “권한과 역할” 부터 시작하나

학생들이 가장 자주 묻는 질문 중 하나:
“내가 PR을 보내면 누가 머지하나요?”

답은 단순합니다 — 머지 권한을 가진 사람입니다.
그 권한이 어떻게 분배되어 있는지, 그리고 그 권한이 어떻게 비공식 위계 로 연결되는지 알면 오픈소스 프로젝트의 절반이 보입니다.

Repository roles — GitHub이 부여하는 5단계 권한

권한 단계할 수 있는 것대표 사용처
Read코드 보기, 이슈/PR 열기, 코멘트 작성외부 협업자, 감사자
TriageRead + 이슈/PR 라벨링·할당·닫기 (코드 변경은 못함)Triage 자원봉사자
WriteTriage + 브랜치 push, PR 머지(제한적), 리뷰 제출일반 팀원
MaintainWrite + 저장소 설정 일부 변경 (제외: 권한 부여, 삭제, billing)프로젝트 메인테이너
Admin모든 권한 (권한 부여, 삭제, billing 포함)조직 소유자

Settings → Collaborators 메뉴에서 사람마다 위 단계 중 하나를 부여합니다.
같은 사람이라도 저장소마다 다른 권한을 가질 수 있습니다.

Organization roles — 조직 단위의 권한

역할의미
Owner조직 자체의 모든 권한 (멤버 추가/제거, billing, 모든 저장소)
Member조직의 일반 멤버. 저장소별 권한은 따로 부여됨
Outside collaborator조직 멤버가 아닌 외부인. 특정 저장소에만 권한이 부여됨

조직 권한과 저장소 권한은 별도입니다.
조직의 Owner라고 해서 모든 저장소를 자동으로 Admin으로 다루는 건 아니지만, 대부분의 경우 그렇게 설정됩니다.

인터랙티브: 역할별 권한 매트릭스

아래 데모에서 역할을 클릭하면 그 역할이 할 수 있는 일과 할 수 없는 일이 즉시 표시됩니다.
“내가 지금 이 저장소에서 무슨 권한이 있는가” 를 머릿속에 그릴 때 도움이 됩니다.

비공식 위계 — GitHub 권한과는 별도의 사회적 구조

GitHub이 부여하는 권한 위에, 오픈소스 커뮤니티는 사회적 위계를 별도로 가집니다.
이 구분이 처음 기여하는 사람에게 가장 헷갈리는 지점입니다.

%%{init: {'theme':'base','themeVariables':{'primaryColor':'#e3f2fd','primaryBorderColor':'#90caf9','lineColor':'#546e7a','textColor':'#333','mainBkg':'#fafafa','nodeBorder':'#90a4ae','clusterBkg':'#f5f5f5','clusterBorder':'#bdbdbd'}}}%% flowchart TB Anyone["누구나\n(GitHub 계정만 있으면)"] Anyone --> Issue["이슈 작성"] Anyone --> PR["PR 제출"] PR --> Contributor["Contributor\nPR이 머지된 사람"] Contributor -.활동 누적.-> Committer["Committer\nGitHub Write 권한 부여됨"] Committer -.신뢰 누적.-> Reviewer["Reviewer\nPR 리뷰 자격"] Reviewer -.리더십.-> Maintainer["Maintainer\n실질 머지 권한 + 방향성 결정"] Maintainer -.프로젝트 운영.-> Core["Core / TSC\n프로젝트 자체의 거버넌스"] style Anyone fill:#bbdefb,stroke:#1976d2,stroke-width:2px,rx:10,ry:10 style Issue fill:#eceff1,stroke:#546e7a,stroke-width:2px,rx:10,ry:10 style PR fill:#eceff1,stroke:#546e7a,stroke-width:2px,rx:10,ry:10 style Contributor fill:#fff9c4,stroke:#f9a825,stroke-width:2px,rx:10,ry:10 style Committer fill:#fff9c4,stroke:#f9a825,stroke-width:2px,rx:10,ry:10 style Reviewer fill:#fff9c4,stroke:#f9a825,stroke-width:2px,rx:10,ry:10 style Maintainer fill:#c8e6c9,stroke:#388e3c,stroke-width:2px,rx:10,ry:10 style Core fill:#c8e6c9,stroke:#388e3c,stroke-width:2px,rx:10,ry:10
비공식 역할누구인가어떻게 되는가
ContributorPR이 1회 이상 머지된 사람PR 제출 + 머지로 자동
Committer저장소에 직접 push할 수 있도록 권한받은 사람메인테이너가 GitHub Write 권한 부여
ReviewerPR을 검토할 자격이 명시된 사람 (CODEOWNERS, 팀 멤버 등)프로젝트가 정한 기준에 따라 지명
Maintainer머지·릴리스·정책 결정에 실질 권한이 있는 사람오랜 기여 + 커뮤니티 합의
Core / TSC프로젝트의 거버넌스 자체를 결정 (방향성, 분쟁 해결)정관 또는 공식 선출 절차

핵심 통찰: GitHub 권한(Read/Triage/Write/Maintain/Admin)은 “기술적 권한” 이고,
Contributor/Committer/Maintainer/Core는 “사회적 역할” 입니다.
같은 사람이 두 측면에서 다른 위치에 있을 수 있습니다.

사례: Kubernetes 거버넌스 (SIG 구조)

대형 OSS 프로젝트의 거버넌스가 어떻게 구조화되는지 가장 시각적으로 잘 보여 주는 예입니다.

kubernetes/community — SIG, WG, Committee 구조
https://github.com/kubernetes/community

라이브로 둘러볼 페이지:

  • 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 (선출제, 임기 있음)

정리한 계층 관계:

%%{init: {'theme':'base','themeVariables':{'primaryColor':'#e3f2fd','primaryBorderColor':'#90caf9','lineColor':'#546e7a','textColor':'#333','mainBkg':'#fafafa','nodeBorder':'#90a4ae','clusterBkg':'#f5f5f5','clusterBorder':'#bdbdbd'}}}%% flowchart TB Project["Kubernetes Project"] Project --> Steering["Steering Committee\n(선출제, 거버넌스)"] Project --> Committee["Committees\n(Code of Conduct 등)"] Project --> SIGs["SIGs (sig-*)\n영구 · 코드 소유권 있음"] Project --> WGs["WGs (wg-*)\n임시 · 코드 소유권 없음"] SIGs --> SP["Subprojects\n(SIG 내부 단위)"] WGs -.여러 SIG에 걸쳐.-> SIGs style Project fill:#bbdefb,stroke:#1976d2,stroke-width:2px,rx:10,ry:10 style Steering fill:#d1c4e9,stroke:#7b1fa2,stroke-width:2px,rx:10,ry:10 style Committee fill:#d1c4e9,stroke:#7b1fa2,stroke-width:2px,rx:10,ry:10 style SIGs fill:#c8e6c9,stroke:#388e3c,stroke-width:2px,rx:10,ry:10 style WGs fill:#fff9c4,stroke:#f9a825,stroke-width:2px,rx:10,ry:10 style SP fill:#c8e6c9,stroke:#388e3c,stroke-width:2px,rx:10,ry:10

학생들에게 던질 만한 질문:
“우리가 본 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의 품질을 보장하지도 않습니다.
다만 메인테이너의 첫 인상에 영향을 주는 건 사실입니다.

강의 중 인터랙티브 활동

학생들에게 다음을 권장합니다:

  1. 자기 프로필을 열고 github.com/<id> 화면 확인
  2. 강사가 보여 주는 유명 메인테이너 프로필(예: sindresorhus, gaearon, antfu)과 비교
  3. “내 프로필이 5년 뒤에 어떻게 보였으면 좋겠는가” 를 머릿속으로 그려 보기

Part 3 — 오픈소스 프로젝트의 해부학

프로젝트의 첫인상은 코드가 아니라 메타파일에서 만들어진다

오픈소스 저장소를 처음 만났을 때, 메인테이너가 기여자에게 의도적으로 보여 주는 정보는 코드 자체가 아니라 루트의 메타파일들입니다.
이것들을 빠르게 읽는 능력이 곧 “오픈소스 문해력” 입니다.

인터랙티브: OSS 프로젝트의 해부도

아래 데모는 일반적인 오픈소스 저장소 화면을 가상으로 옮긴 것입니다.
각 영역을 클릭하면 그 영역이 무엇이고, 왜 중요한지 즉시 표시됩니다.

라이선스 — 모든 결정의 토대

오픈소스의 시작은 라이선스입니다. 라이선스가 없는 코드는 GitHub에 공개되어 있어도 법적으로 “권리 보유 전부” 입니다.

라이선스핵심 성격파생물 라이선스 제약상업 제품 사용 (closed source 포함)대표 사용처
MIT가장 자유로움 — “표시만 해 줘”없음 — 어떤 라이선스로든 재배포✅ 제약 없음React, Vue, Express, jQuery
Apache 2.0MIT + 특허권 명시 보호없음 (NOTICE 보존 필수)✅ 제약 없음 (NOTICE 포함)Kubernetes, Android, TensorFlow
BSD 2/3-ClauseMIT와 유사, 더 엄격한 표시 조항없음✅ 제약 없음 (저작권 표시 의무)FreeBSD, Go
GPL v3“이 코드를 쓴 결과물도 GPL로 공개해야 함” — 강한 카피레프트강함⚠️ 가능하나 파생물 소스 공개 의무Linux 커널, GIMP, GCC
LGPL라이브러리 링크는 자유, 라이브러리 수정 시 GPL 적용중간✅ 동적 링크 사용 자유 (라이브러리 수정 시 공개)glibc, FFmpeg(LGPL 모드)
AGPL v3GPL + “네트워크로 접근 가능하게 한 경우에도 소스 공개 의무”매우 강함⚠️ SaaS 형태도 소스 공개 의무 (사실상 closed source 불가)MongoDB(과거), Mastodon
choosealicense.com — GitHub의 공식 라이선스 가이드
https://choosealicense.com/

카피레프트(Copyleft) 는 GPL 계열의 핵심 개념입니다.
“이 코드의 파생물도 똑같은 자유를 보장해야 한다” 는 의미로, 결과적으로 상용 폐쇄 소스 와 섞기 어렵게 만듭니다.
MIT/Apache는 카피레프트가 없어 기업이 가져다 쓰기 쉽고, 그래서 산업계에 가장 널리 퍼져 있습니다.

README의 미학

좋은 README는 3분 안에 다음 질문에 답해야 합니다:

  1. 이게 무엇을 하는 도구인가? (한 줄)
  2. 왜 이걸 쓰는가? (alternatives 대비)
  3. 어떻게 빨리 설치/실행하는가?
  4. 더 자세히 알려면 어디로 가는가?

좋은 README의 시각 요소:

  • 로고 또는 hero 이미지 — 프로젝트의 정체성
  • shields.io 뱃지 — 빌드 상태, npm 다운로드 수, 라이선스, 버전
  • 데모 GIF 또는 스크린샷 — 동작이 한눈에 보임
  • 빠른 시작 코드 블록 — 복사·붙여넣기로 바로 실행
  • 상세 문서 링크 — 깊이 들어가는 사람을 위한 출구
awesome-readme — 잘 작성된 README 모음
https://github.com/matiassingers/awesome-readme

기여자 인프라 — .github/ 디렉토리 안쪽

대부분의 활발한 OSS는 저장소 루트의 .github/ 폴더에 기여자 가이드자동화 정책을 모아 둡니다.

파일역할
CONTRIBUTING.md기여 방법 — 이슈 작성, PR 양식, 커밋 컨벤션, 테스트 실행법
CODE_OF_CONDUCT.md커뮤니티 행동 강령 (보통 Contributor Covenant 1.4 또는 2.x)
ISSUE_TEMPLATE/버그 리포트, 기능 제안 등 이슈 양식
PULL_REQUEST_TEMPLATE.mdPR 양식 (체크리스트, 변경 요약, 관련 이슈 링크 등)
FUNDING.yml“Sponsor” 버튼에 연결되는 결제·후원 채널
workflows/*.ymlGitHub Actions (CI/CD)
dependabot.yml의존성 자동 업데이트 설정
CODEOWNERS파일/디렉토리별 자동 리뷰어 지정

CODEOWNERS 는 특히 자주 간과되지만 중요합니다.
“이 파일을 건드리는 PR은 자동으로 이 사람이 리뷰어로 지정된다” 는 규칙을 명시합니다.
큰 프로젝트에서 리뷰가 “올바른 사람에게” 가는 비결이 여기 있습니다.

Labels — 색깔로 분류하는 작업의 종류

자주 보이는 라벨의미
good first issue첫 기여자에게 추천 — 범위가 명확하고 작음
help wanted메인테이너가 외부 도움을 환영하는 이슈
bug / enhancement버그 / 새 기능
documentation문서 개선
breaking change호환성을 깨는 변경 — 신중하게
wontfix / invalid닫힌 사유
needs triage분류 대기

GitHub 검색에서 라벨을 활용하면 첫 이슈를 빠르게 찾을 수 있습니다:

1
is:issue is:open label:"good first issue" language:typescript

자동화 흔적들 — CI 뱃지, Dependabot, Releases

활발한 프로젝트는 README와 PR 페이지에 자동화의 흔적이 가득합니다:

  • CI 뱃지 — GitHub Actions / CircleCI / Travis 의 빌드 상태 (passing / failing)
  • Dependabot PR — 의존성 라이브러리 새 버전이 나오면 자동으로 업데이트 PR이 열림
  • Releasesv1.2.3 같은 태그, GitHub Releases 페이지에 자동 생성된 changelog
  • Semantic VersioningMAJOR.MINOR.PATCH 의 약속
  • Conventional Commitsfeat:, fix:, chore: 같은 커밋 prefix 컨벤션

이 흔적들의 활발도가 곧 프로젝트의 건강 지표 입니다.
Dependabot PR이 6개월째 쌓여 있고 CI가 빨갛다면, 메인테이너의 손이 잠시 떠난 신호일 수 있습니다.

로드맵 & 의사결정 — RFC, PEP, TC39

큰 OSS(Open Source Software)는 큰 변경을 PR 하나로 처리하지 않습니다.
사전 합의 절차 가 별도로 존재합니다.

프로세스프로젝트역할
RFCRust, React, Vue설계 제안서 — 코드 작성 전에 토론
PEPPythonPython Enhancement Proposal — 언어 변경의 공식 경로
TC39 stageJavaScriptECMAScript 표준 제안 절차 (Stage 0~4)
KEPKubernetesKubernetes Enhancement Proposal

학생들이 알아둘 점: 언어·표준에 가까울수록 PR보다 RFC가 우선입니다.
코드를 들고 가기 전에 “이 변경이 받아들여질 수 있는가” 를 먼저 글로 합의합니다.

커뮤니티 채널 — 어디서 묻나

프로젝트마다 1차 응답이 일어나는 채널이 다릅니다:

채널자주 쓰이는 곳성격
GitHub Issues거의 모든 프로젝트공식적, 검색됨, 영구 보존
GitHub Discussions점점 늘어남Q&A, 아이디어 토론
Discord프론트엔드 진영(React, Vue, Vite), 게임 엔진빠른 캐주얼 토론
Slack기업 주도 OSS, Kubernetes(CNCF 슬랙)워킹 그룹별 채널
Matrix/IRCLinux, KDE, 전통 OSS자유 소프트웨어 문화
메일링 리스트Linux kernel, GCC, Python core가장 보수적, 검색이 어렵지만 영구 보존

PR을 보내기 전에 채널에서 한 번 묻는 것 이 흔히 유효한 습관입니다.
“이 방향으로 PR을 준비하려는데 환영하시나요?” 식의 가벼운 질문은 PR이 폐기될 위험을 크게 줄여 줍니다.


Part 4 — 실제 PR 사례 워킹: Mermaid

왜 사례 워킹이 중요한가

PR 작성법을 추상적으로 설명하는 것보다 실제 머지된 PR과 거절된 PR을 한 줄씩 읽는 것 이 훨씬 강력합니다.
의사결정의 결이 코멘트 한 줄 한 줄에 드러나기 때문입니다.

이 강의에서는 Mermaid (markdown diagram 도구) 의 실제 PR을 사례로 사용합니다.

mermaid-js/mermaid
https://github.com/mermaid-js/mermaid

PR 한 사이클의 단계

%%{init: {'theme':'base','themeVariables':{'primaryColor':'#e3f2fd','primaryBorderColor':'#90caf9','lineColor':'#546e7a','textColor':'#333','mainBkg':'#fafafa','nodeBorder':'#90a4ae','clusterBkg':'#f5f5f5','clusterBorder':'#bdbdbd'}}}%% flowchart LR A["이슈 발견 또는 제안"] --> B["메인테이너 응답\n(환영 / 보류 / 거절)"] B --> C["PR 초안\n(Draft)"] C --> D["PR 공개\n(Ready for review)"] D --> E["리뷰 받기"] E --> F{"코멘트 종류"} F -- "nit / suggestion" --> G["반영 또는 거절"] F -- "request changes" --> H["수정 후 재요청"] F -- "approve" --> I["머지 대기"] G --> I H --> E I --> J["Merged 또는 Closed"] style A fill:#bbdefb,stroke:#1976d2,stroke-width:2px,rx:10,ry:10 style B fill:#bbdefb,stroke:#1976d2,stroke-width:2px,rx:10,ry:10 style C fill:#fff9c4,stroke:#f9a825,stroke-width:2px,rx:10,ry:10 style D fill:#fff9c4,stroke:#f9a825,stroke-width:2px,rx:10,ry:10 style E fill:#fff9c4,stroke:#f9a825,stroke-width:2px,rx:10,ry:10 style F fill:#eceff1,stroke:#546e7a,stroke-width:2px,rx:10,ry:10 style G fill:#fff9c4,stroke:#f9a825,stroke-width:2px,rx:10,ry:10 style H fill:#fff9c4,stroke:#f9a825,stroke-width:2px,rx:10,ry:10 style I fill:#c8e6c9,stroke:#388e3c,stroke-width:2px,rx:10,ry:10 style J fill:#c8e6c9,stroke:#388e3c,stroke-width:2px,rx:10,ry:10

인터랙티브: PR Lifecycle Walker

아래 데모에서 단계별로 진행해 보며, 각 단계에서 무엇이 일어나는지 따라가 보세요.

머지되는 PR의 패턴

라이브로 함께 읽을 예시:

PR #7711 — fix(dagre): merge flowchart and state self-loop segments before rendering
https://github.com/mermaid-js/mermaid/pull/7711

이 PR을 라이브로 함께 읽으면서, 다음 6가지 신호를 화면에서 직접 가리켜 보여 줍니다:

강사가 강조하는 신호이 PR에서 어떻게 나타나나
이슈와 PR의 연결PR 설명 상단에 Resolves #6336 — 이슈 페이지 (Self-edges/loops 가 어색하게 보이는 버그)로 클릭만 하면 이동. 양쪽이 자동으로 묶임
PR 설명문의 구조SummaryBackground (근본 원인 분석) → Before/After (GIF·스크린샷) → Design DecisionsTasks (체크리스트). “왜·무엇·어떻게” 가 명확히 분리
작은 단위약 229줄 변경. 4개 파일 (핵심 로직 1 + 단위 테스트 1 + Cypress E2E 2). 200~400줄 “평균” 범위에 정확히 들어맞음
메인테이너의 응답 속도첫 PR 제출 후 며칠 안에 리뷰어 ashishjain0512가 11개 코멘트로 첫 리뷰. 활발한 프로젝트의 모습
리뷰 코멘트의 톤“제목은 dagre인데 실제로는 flowchart와 state diagram을 다루는데, 의도가 맞나요?” — 공격이 아니라 질문. 작성자가 방어 대신 범위 확대로 응답
머지 직전 마지막 커밋두 라운드 리뷰 후 모든 지적 사항 반영. 마지막 commit이 “Cypress E2E 케이스 추가 + 코드 스타일 정리”. 리뷰를 받아들인 흔적 이 그래프에 남음

PR 페이지에서 라이브로 클릭할 정확한 지점

  1. PR 제목: 컨벤셔널 커밋 형식 (fix(dagre):) 으로 시작 — 한눈에 “버그 수정 / dagre 영역” 임을 알 수 있음
  2. PR 설명문 상단: Resolves #6336 링크 클릭 → 원본 이슈로 이동. 이슈에 사용자가 올린 GIF가 있어 문제가 시각적으로 명확
  3. Files changed 탭: 4개 파일. 코드 변경과 테스트 변경이 같은 PR 에 들어 있다는 점이 핵심
  4. Conversation 탭 중 ashishjain0512의 첫 리뷰: 인라인 코멘트 11개 → 그중 핵심 2개를 강조해서 읽어 줌
  5. Conversation 탭 끝: 작성자가 새 commit을 push 한 흔적 — 리뷰 후 어떻게 대응했는지 시간 순으로 보임
  6. 머지 직후의 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을 머지하기 전에 법적 동의 를 요구합니다.

메커니즘풀네임동작 방식
CLAContributor License Agreement처음 PR 보낼 때 봇이 자동 서명 링크를 요청 — 1회 서명하면 영구 적용
DCODeveloper 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 시연:

1
2
3
4
5
6
7
git commit -s -m "Add reset confirmation dialog"

# 결과로 생성되는 커밋 메시지:
#
# Add reset confirmation dialog
#
# Signed-off-by: Your Name <you@example.com>

-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 경험입니다.

firstcontributions/first-contributions
https://github.com/firstcontributions/first-contributions

학생이 강의 중에 따라 할 단계:

  1. 저장소 페이지 우상단 Fork 클릭 → 내 계정으로 복제
  2. 내 fork 페이지에서 Add file → Create new file (또는 Clone 후 로컬 작업)
  3. Contributors.md 의 alphabetical 위치에 본인 이름과 GitHub 링크 한 줄 추가
  4. Commit message: Add <your-name>
  5. Pull request 열기 — base: firstcontributions:main, compare: <you>:main
  6. PR 설명에 간단한 자기소개 한 줄
  7. 자동 봇이 곧 환영 메시지를 남기고, 메인테이너가 짧은 시간 내 머지

이 한 PR이 여러분의 GitHub contribution graph에 첫 초록색 칸 을 찍는 순간입니다.

강사 시연 (13분): TimeCountdown 으로 PR 한 사이클 전체

학생 실습이 끝난 직후, 강사는 본인의 실제 저장소로 양쪽 관점 을 모두 시연합니다.

CodeCompose7/TimeCountdown — 시연용 저장소
https://github.com/CodeCompose7/TimeCountdown

시연 환경

항목구성
메인 계정CodeCompose7 — TimeCountdown 저장소 소유 (메인테이너 역할)
더미 계정강사의 다른 계정 (Contributor 역할)
사전 준비TimeCountdown 저장소에 good first issue 라벨이 붙은 이슈 1개
브라우저두 계정을 동시에 보기 위해 일반창 + 시크릿창, 또는 두 개의 브라우저

Step 1 — 메인 계정 (받는 쪽): 이슈 확인

  1. github.com/CodeCompose7/TimeCountdown/issues 열기
  2. 사전 준비된 이슈를 보여 줌
    • 제목·라벨·재현 단계가 어떻게 구조화되어 있는지 강조
  3. 이슈에 적힌 good first issue 라벨, 명확한 작업 범위, 메인테이너의 사전 환영 코멘트 확인

Step 2 — 더미 계정 (보내는 쪽): Fork & Clone

  1. 더미 계정으로 로그인된 브라우저에서 같은 저장소 열기
  2. Fork 클릭 — 자기 계정으로 복제
  3. fork 페이지에서 키보드 . (마침표) 키 누르기 → 같은 저장소가 github.dev 에서 열림 (브라우저 안 VS Code 에디터)
    • URL 의 github.comgithub.dev 로 직접 바꿔도 동일
    • (또는 로컬 Clone 후 에디터 작업 — 시연에서는 빠른 흐름을 위해 web editor 추천)

Step 3 — 더미 계정: 브랜치 + 변경

  1. web editor 또는 로컬에서 fix/<issue-내용>(예시 fix/reset-confirm) 브랜치 생성
  2. 이슈에서 요구한 변경을 적용
  3. 의미 있는 commit message 작성 — 예: Add reset confirmation dialog (#3)
    • (#3) 처럼 이슈 번호를 명시하면 PR과 이슈가 자동 연결됨
  4. push

Step 4 — 더미 계정: PR 열기

  1. fork 페이지에 자동 표시되는 Compare & pull request 클릭

  2. 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 17
    
  3. base: CodeCompose7:main, compare: <더미 계정>:fix/reset-confirm 확인

  4. Create pull request 제출

Step 5 — 메인 계정 (받는 쪽): PR 알림 & 리뷰

브라우저를 메인 계정 쪽으로 전환:

  1. Notifications 또는 메일에서 PR 알림 확인 → 클릭
  2. Conversation 탭 — PR 설명문 읽기
  3. Files changed 탭 → diff 확인
  4. 변경 라인 옆 + 버튼 클릭 → 인라인 코멘트 작성 (예: “이 부분 ESC 키 처리를 별도 함수로 빼는 게 어떨까요?”)
  5. 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 는 인라인 코멘트 안에 코드 수정안을 박아 넣는 블록 입니다.

위치를 라이브로 짚어 줍니다:

  1. Files changed 탭에서 코드 라인 옆 + 클릭 → 코멘트 박스 열림
  2. 코멘트 박스 상단 툴바 의 오른쪽 끝, 종이에 +/- 가 붙은 모양의 아이콘 (호버 시 “Add a suggestion”) 클릭
  3. 코멘트 박스에 자동으로 suggestion 코드 블록 템플릿이 채워짐 — 그 라인의 현재 코드 가 먼저 들어옴
  4. 그 코드를 원하는 형태로 직접 수정한 뒤 코멘트 제출

예시:

1
2
3
4
5
6
```suggestion
function onResetClick() {
  if (!confirm('Reset the timer?')) return;
  resetTimer();
}
```

이 블록은 작성자가 Commit suggestion 버튼 하나로 즉시 반영할 수 있습니다.
리뷰어의 친절함이 코드 변경 한 줄로 도착하는 가장 매끄러운 UX 중 하나입니다.

Step 8 — 더미 계정: 변경 요청에 응답

브라우저를 더미 계정으로 전환:

  1. PR 알림 확인 → 코멘트 읽기
  2. Commit suggestion 클릭 — 리뷰어의 제안을 그대로 적용
  3. 나머지 의견에는 답글 작성 — “좋은 지적입니다. 다음 커밋에 반영하겠습니다.”
  4. 로컬(또는 web editor)에서 추가 수정 → 새 commit → push
  5. PR 화면에 자동으로 새 커밋이 표시됨

Step 9 — (선택) 컨플릭트 만들고 해결

  1. 메인 계정에서 main 브랜치에 사소한 변경을 push (의도적 컨플릭트 유발)
  2. 더미 계정의 PR 페이지 하단에 “This branch has conflicts that must be resolved” 표시
  3. Resolve conflicts 버튼 → GitHub 웹 에디터에서 <<<<<<< HEAD, =======, >>>>>>> main 마커 확인
  4. 양쪽 코드 중 어느 쪽을 살릴지 결정 → Mark as resolvedCommit merge

Step 10 — 메인 계정: 승인 & 머지

  1. Review changes → Approve 로 승인
  2. Merge pull request 버튼 옆 드롭다운 클릭 → 세 가지 옵션 시연:
옵션결과
Create a merge commit머지 커밋이 남고 브랜치 모양이 그래프에 보존
Squash and mergePR 안 모든 커밋을 1개로 압축해서 main에 머지 — “1 PR = 1 commit” 정책
Rebase and merge머지 커밋 없이 일렬로 — 깨끗한 일직선 히스토리

이번 시연에서는 Squash and merge 선택 → 머지 메시지 정리 → confirm.

Step 11 — 닫힌 후의 흐름

  1. PR이 자동으로 닫히고, 연결된 이슈 #3도 자동으로 close
  2. 더미 계정의 fork에서 fix/reset-confirm 브랜치 삭제 (정리)
  3. 더미 계정의 프로필 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가 공개 글로 강하게 경고
NetBSDAI 생성 코드 기여 명시적으로 금지 (commit policy에 기재)
GentooAI 생성 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주

  1. GitHub Skills 코스 한 개 완주

    skills.github.com
    https://skills.github.com/
  2. 관심사 프로젝트의 good first issue 5개 둘러보기

    • 평소 쓰는 라이브러리/도구 1~2개 선정
    • GitHub 검색: is:issue is:open label:"good first issue" repo:<owner>/<name>
    • “할 수 있을 것 같다” 싶은 이슈 1개 정해서 코멘트로 의사 표시
  3. 번역/문서 기여 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 2GitHub은 단순한 코드 저장소가 아니라, 권한과 역할이 다층적으로 설계된 “사회"입니다
Part 3오픈소스 프로젝트는 코드뿐 아니라 라이선스·문서·자동화로 이루어진 하나의 생명체입니다
Part 4좋은 PR과 거절되는 PR의 차이는 “코드의 품질"보다 “맥락의 전달"에 있습니다
Part 5첫 기여는 꼭 코드일 필요가 없습니다 — 번역·문서·트리아지가 더 환영받기도 합니다
Part 6PR을 보내는 쪽과 받는 쪽 양쪽을 모두 경험해야 협업의 감각이 완성됩니다
Part 7AI 시대에 “누가 코드를 썼는가"의 의미가 다시 쓰이고 있고, 메인테이너의 정책도 갈라지고 있습니다
Part 8다음 PR은 여러분이 가장 좋아하는 프로젝트의 README 오타 수정에서 시작될 수 있습니다

참고 자료

코드컴포즈

이 콘텐츠에 접근하려면 로그인이 필요합니다.