💡 풀리퀘스트는 단순한 코드 제출이 아니라, 팀원과 대화하는 공식 채널입니다. 포크→브랜치→커밋→PR→리뷰→머지 흐름만 몸에 익히면 어떤 팀 프로젝트도 두렵지 않습니다.
처음 팀 프로젝트에 들어갔을 때의 그 막막함
풀리퀘스트, 줄여서 PR. 취업 전에 이 단어를 처음 들었을 때 솔직히 ‘그냥 코드 올리는 거 아닌가?’ 싶었습니다. 근데 막상 팀 프로젝트에 들어가 보니 이게 전혀 다른 세계더라고요.
제 주변에 개발 부트캠프를 막 졸업한 20대 중반 분이 있었는데, 처음 오픈소스 기여를 시도하다가 포크도 안 하고 원본 저장소에 직접 푸시하려다 에러를 만났다고 했습니다. “이게 왜 안 되지?” 하고 2시간을 혼자 붙잡고 있었다는 거예요. 저도 비슷한 경험이 있어서 그 답답함이 딱 와닿았습니다.
그래서 오늘은 풀리퀘스트를 중심으로 GitHub 협업 워크플로 전체를 한 번에 정리해드리려 합니다. 포크부터 머지까지, 실제로 쓰이는 순서 그대로요.
포크와 브랜치, 뭐가 다른 건가요?
💡 포크는 저장소 자체를 내 계정으로 복사하는 것, 브랜치는 같은 저장소 안에서 작업 공간을 나누는 것입니다.
여기서 반전인데, 많은 분들이 포크와 브랜치를 혼용해서 쓰다가 협업 흐름을 망가뜨리는 경우가 꽤 있습니다.
포크(Fork)는 타인의 저장소를 내 GitHub 계정으로 통째로 복사하는 행위입니다. 오픈소스 기여나 외부 프로젝트에 참여할 때 주로 씁니다. 반면 브랜치(Branch)는 같은 저장소 내에서 독립적인 작업 공간을 만드는 개념입니다. 같은 팀, 같은 저장소 내에서 기능별로 나눠 작업할 때 쓰죠.
팀 내부 프로젝트라면 대부분 브랜치 전략을 씁니다. 오픈소스처럼 외부인이 기여하는 구조라면 포크 후 PR을 올리는 흐름이 일반적이에요.
flowchart TD
A[원본 저장소\noriginal repo] -->|Fork| B[내 계정의 복사본\nforked repo]
B -->|git clone| C[로컬 PC]
C -->|브랜치 생성\ngit checkout -b feature/기능명| D[작업 브랜치]
D -->|코드 작성 후\ngit add & commit| E[로컬 커밋]
E -->|git push origin\nfeature/기능명| F[내 원격 저장소]
F -->|풀리퀘스트 생성| A
A -->|리뷰 & 승인 후| G[머지 완료]
흐름이 보이시나요? 포크를 쓰든 브랜치를 쓰든, 결국 풀리퀘스트가 최종 관문이 된다는 건 똑같습니다.
풀리퀘스트 생성, 이렇게 하면 됩니다
💡 브랜치에서 커밋을 올린 뒤 GitHub 웹에서 “Compare & pull request” 버튼을 누르는 것만으로 PR이 시작됩니다.
실제 순서를 단계별로 따라가 보겠습니다.
- 브랜치 생성:
git checkout -b feature/login-button처럼 기능 이름을 붙인 브랜치를 만듭니다. - 작업 및 커밋: 코드를 수정하고
git add .→git commit -m "로그인 버튼 UI 추가". - 원격 저장소에 푸시:
git push origin feature/login-button. - GitHub에서 PR 생성: 저장소 페이지 상단에 “Compare & pull request” 버튼이 뜨면 클릭. 안 뜨면 Pull requests 탭 → New pull request.
- PR 제목과 설명 작성: 여기가 진짜 중요합니다. 아래에서 따로 다룰게요.
잠깐, 이건 꼭 알아야 해요. PR 제목과 설명은 코드보다 먼저 읽힙니다. 리뷰어 입장에서 “이 PR이 왜 필요한지”, “어떤 변경이 있는지”를 한눈에 파악할 수 있어야 하거든요. 대충 “기능 추가”라고만 써놓으면 리뷰어가 코드를 전부 읽어야 하는 상황이 됩니다. 팀원에게 민폐가 되는 거죠.
좋은 PR 설명의 구성은 대략 이렇습니다.
- 변경 이유: 왜 이 작업을 했는가
- 변경 내용 요약: 무엇을 어떻게 바꿨는가
- 테스트 방법: 어떻게 확인할 수 있는가
- 스크린샷 (UI 변경 시): 직관적인 이해를 도움
이거 처음에 면찮아 보여도 습관 들이면 본인이 제일 편합니다. 나중에 “내가 왜 이걸 만들었더라?” 할 때 PR 히스토리 보면 다 나오거든요.
리뷰 프로세스: 받는 것도, 주는 것도 기술입니다
💡 코드 리뷰는 코드를 평가하는 게 아니라 더 나은 코드를 함께 만들어가는 대화입니다.
PR을 올리면 팀원이 코드를 검토하고 코멘트를 남깁니다. GitHub에서는 특정 줄을 클릭해서 인라인 코멘트를 달 수 있어요. 리뷰어는 최종적으로 세 가지 중 하나를 선택합니다.
Request changes를 받았을 때 기분이 상하는 분들이 꽤 있는데요. 사실 이건 “네 코드가 형편없어”가 아니라 “같이 더 좋게 만들어보자”에 더 가깝습니다. 오픈소스 프로젝트에서 베테랑 개발자들도 서로 수정 요청을 주고받는 건 일상입니다.
그런데 말이에요, 리뷰를 주는 입장도 꽤 신경 써야 합니다. “이거 왜 이렇게 했어요?”보다 “이 부분을 이렇게 바꾸면 성능이 개선될 것 같아요, 어떻게 생각하세요?”처럼 제안형으로 쓰는 게 협업 분위기에 훨씬 좋습니다. 팀 프로젝트는 결국 사람 사이의 관계니까요.
수정 요청을 반영했다면 같은 브랜치에 새 커밋을 추가하고 다시 푸시하면 됩니다. 기존 PR에 자동으로 반영되니까 새 PR을 만들 필요가 없습니다.
머지와 충돌 해결, 겁먹지 않아도 됩니다
💡 충돌(Conflict)은 두 브랜치가 같은 파일의 같은 줄을 다르게 수정했을 때 발생합니다. Git이 어느 쪽을 선택할지 모르기 때문에 사람이 직접 결정해야 합니다.
승인이 완료된 PR은 머지(Merge)할 수 있습니다. GitHub에서는 머지 방식이 세 가지입니다.
- Merge commit: 기본값. 브랜치 히스토리가 그대로 보존됩니다.
- Squash and merge: 여러 커밋을 하나로 합쳐서 main에 추가. 히스토리가 깔끔해집니다.
- Rebase and merge: 커밋을 main 위에 순서대로 올립니다. 선형 히스토리 유지.
팀마다 선호하는 방식이 다르니 처음 프로젝트 합류 시 팀 컨벤션을 꼭 물어보는 게 좋습니다. (이건 진짜 꿀팁)
아 그리고, 충돌 문제. 처음 Conflict 메시지를 보면 당황스럽지만 구조만 알면 별거 없습니다.
sequenceDiagram
participant A as 개발자A의 브랜치
participant M as main 브랜치
participant B as 개발자B의 브랜치
A->>M: 먼저 머지 완료
B->>M: PR 생성 시도
M-->>B: ⚠️ Conflict 발생!
Note over B: git fetch origingit merge origin/main
B->>B: 충돌 파일 직접 수정
B->>M: 충돌 해결 후 다시 푸시
M-->>B: ✅ 머지 가능 상태
충돌이 난 파일을 열면 이런 표시가 보입니다.
<<<<<<< HEAD 아래는 현재 브랜치의 코드, ======= 아래는 병합하려는 브랜치의 코드, >>>>>>> 이후가 상대 브랜치 이름입니다. 둘 중 맞는 쪽을 남기거나 둘 다 조합해서 저장하면 됩니다. 그 다음 다시 커밋하면 충돌 해결 완료입니다.
지난주에 사이드 프로젝트에서 이 상황을 직접 겪었는데, 겁먹지 않고 파일 열어서 구분선 찾아서 수정하니까 5분 만에 해결됐습니다. 처음이 어렵지, 한 번만 해보면 “별거 아니네” 하게 됩니다.
PR 기반 협업, 이게 왜 중요한가
결국 풀리퀘스트 문화의 핵심은 모든 변경이 검토를 거친다는 원칙입니다. main 브랜치에 직접 push하는 팀과, PR을 통해 리뷰를 거치는 팀의 코드 품질은 시간이 지날수록 차이가 납니다. 이건 데이터 볼 필요도 없이 현장에서 체감하게 됩니다.
혹시 지금 팀 프로젝트에서 PR 없이 작업하고 있다면, 오늘부터라도 브랜치 전략을 도입해보는 건 어떨까요? 처음엔 번거롭게 느껴질 수 있지만, 나중에 “왜 이 코드가 이렇게 됐지?” 하는 상황이 훨씬 줄어듭니다.
포크, 브랜치, 커밋, 푸시, PR, 리뷰, 머지. 이 일곱 단계가 이제 자연스럽게 머릿속에 그려진다면, 여러분은 이미 팀 협업의 기본 흐름을 익힌 겁니다.