사전 풀 리퀘스트
개념

풀 리퀘스트

gabury1고친 사람 github-actions[bot]

풀 리퀘스트는 내가 따로 고친 코드를 본래 코드에 합쳐 달라고 내는 요청입니다. 받는 쪽은 그 변경을 읽어 보고 합칠지 정합니다. 요청 하나에 바뀐 내용과 그걸 두고 오간 말이 함께 모입니다.

쉽고 빠른 이해

고친 코드를 "가져가 합쳐 주세요"라고 받는 쪽에 내는 요청입니다. 리눅스 커널에서는 이 요청을 메일 한 통으로 보냅니다. GitHub 에서는 웹 화면 하나로 엽니다. GitLab 은 같은 것을 머지 리퀘스트라고 부릅니다.

이게 없으면 본래 저장소에 쓸 권한을 모두에게 나눠 줘야 합니다. 그렇게 하면 들어오는 변경을 받는 쪽이 먼저 보고 고를 틈이 없습니다.

  1. 내 브랜치나 내 사본 저장소에서 고칩니다
  2. 그 변경을 가져가 합쳐 달라고 요청을 냅니다
  3. 받는 쪽이 짚은 곳을 더 고쳐 올립니다. GitHub 에서는 다시 올리면 요청에 담긴 변경도 따라 바뀝니다
  4. 받아들이면 합쳐집니다. 접으면 합치지 않고 닫힙니다

대가는 합치는 손이 받는 쪽에 몰린다는 것입니다. 읽고 시험하고 합치는 일을 받는 쪽이 맡습니다. 승인이나 자동 검사를 조건으로 걸어 두면 그 조건을 채울 때까지 합칠 수 없습니다.

상세

여럿이 함께 쓰는 문서에서 글을 바로 고치지 않고 「수정 제안」으로 남겨 본 적이 있을 겁니다. 고친 내용은 제안으로 붙어 있습니다. 문서를 맡은 사람이 그 제안을 읽어 보고 받아들이거나 거절합니다. 제안 옆에는 왜 그렇게 고쳤는지 묻고 답한 댓글이 같이 달립니다.

풀 리퀘스트(Pull Request, 줄여서 PR)는 한쪽에 쌓아 둔 코드 변경을 다른 쪽으로 가져가 합쳐 달라고 내는 요청입니다. 합칠지 말지는 받는 쪽이 정합니다. 이 문서에서 「요청」이라고만 적으면 풀 리퀘스트를 가리킵니다.

변경이 쌓이는 곳은 저장소의 브랜치입니다. 저장소는 파일과 그 변경 이력을 함께 담아 두는 곳입니다. 브랜치는 그 저장소 안에서 이력을 갈라 따로 쌓는 줄기입니다.

저장소마다 본래 줄기가 되는 브랜치가 하나 있습니다. 그 브랜치에는 흔히 master 나 main 이라는 이름을 붙입니다. 기능 하나를 손볼 때는 본래 줄기를 건드리지 않으려고 브랜치를 따로 만들어 씁니다.

브랜치에 쌓이는 낱개 단위는 커밋입니다. 커밋은 고친 것을 한 덩이로 묶어 이력에 남긴 기록입니다. 두 브랜치의 이력을 하나로 잇는 일은 병합이라고 합니다. 풀 리퀘스트는 병합하기 전에 요청을 한 번 거치게 합니다.

저장소는 여러 벌일 수 있습니다. 네트워크 너머에 있는 저장소를 원격 저장소라고 합니다. 원격 저장소를 내 컴퓨터로 복사해 오는 일은 클론입니다. 내 커밋을 원격 저장소에 올리는 일은 푸시입니다.

요청을 받아 무엇을 합칠지 정하는 사람을 메인테이너라고 부릅니다. 요청을 내는 사람은 기여자입니다. 변경을 읽고 의견을 남기는 사람은 리뷰어라고 부릅니다. 한 사람이 둘 이상을 겸하기도 합니다.

남의 저장소를 내 저장소에 원격 저장소로 더해 둘 수도 있습니다. 더한다는 것은 그 저장소의 주소에 이름을 붙여 내 저장소에 등록해 두는 일입니다. 등록해 두면 그 저장소의 커밋을 내 쪽으로 가져올 수 있습니다. 메일로 요청을 받은 메인테이너는 이렇게 기여자의 변경을 가져갑니다.

요청 하나에 담기는 것

요청은 아래 넷을 한데 묶습니다.

담는 것 무엇인가
받는 쪽 변경을 받아 갈 브랜치. 받는 쪽 이력에 이미 있는 커밋 하나가 출발점이 된다
보내는 쪽 변경이 쌓여 있는 브랜치. 다른 저장소의 브랜치일 수도 있다. 요청에 담을 마지막 커밋을 이 문서는 끝 커밋이라 부른다
변경 묶음 출발점 이후 끝 커밋까지 보내는 쪽에 쌓인 커밋 목록과, 그 커밋들이 만든 줄 단위 차이
설명 무엇을 왜 바꿨는지 기여자가 쓴 글

표에서 눈여겨볼 것은 세 번째 줄입니다. 변경 묶음은 파일 사본이 아니라 두 브랜치의 차이입니다. 보내는 쪽 브랜치는 출발점에서 갈라져 나갑니다. 그 뒤로 보내는 쪽에만 쌓인 커밋이 변경 묶음입니다.

flowchart TD
    subgraph 받는["받는 쪽 브랜치"]
        R1["앞선 커밋"] --> S["출발점 · 받는 쪽 이력에 이미 있는 커밋"]
    end
    subgraph 묶음["보내는 쪽 브랜치 · 변경 묶음"]
        C1["커밋"] --> C2["커밋"] --> E["끝 커밋"]
    end
    S -->|여기서 갈라진다| C1

출발점은 받는 쪽 이력에 이미 있는 커밋이어야 합니다. 요청은 그 커밋 이후에 생긴 변경만 합쳐 달라고 합니다.

끝 커밋이 언제 정해지는지는 요청을 내는 방식마다 다릅니다. 메일로 내는 요청은 보낼 때의 끝 커밋을 본문에 적어 둡니다. 그 뒤에 올린 커밋은 그 요청에 담기지 않습니다. 웹 화면에서 여는 요청이 다시 올린 커밋을 어떻게 받는지는 동작 절의 「열려 있는 동안」에서 봅니다.

요청을 연 다음에는 리뷰어가 남긴 말과 거기 달린 답이 요청에 붙어 쌓입니다. 몇 달 뒤 "이 줄이 왜 이렇게 돼 있지"를 물을 때 그 요청을 펴면 그때 오간 말을 볼 수 있습니다.

배경

여럿이 한 프로젝트에 변경을 보태는 가장 단순한 방식은 저장소 하나를 두고 팀 모두에게 푸시 권한을 주는 것입니다. 모두가 같은 저장소에 각자 올립니다. 팀이 이런 중앙 집중식 방식에 이미 익숙하다면 요청 없이 이 방식을 이어 쓸 수 있습니다. 대신 들어오는 변경을 메인테이너가 먼저 보고 고르는 단계가 없습니다.

다른 방식은 저장소를 여럿 두는 것입니다. 이 방식에서는 변경을 내려는 사람마다 본래 저장소의 푸시 권한을 나눠 줄 필요가 없습니다. 기여자는 각자 자기 공개 저장소에만 쓸 권한을 갖습니다. 남의 저장소는 읽기만 합니다.

기여자는 본래 저장소를 클론해 와서 고친 뒤 자기 공개 저장소에 푸시합니다. 그다음 메인테이너에게 내 변경을 끌어가 달라고 요청을 보냅니다. 메인테이너는 그 저장소를 원격 저장소로 더해 가져온 뒤 자기 컴퓨터에서 시험하고 합칩니다. 합친 것은 본래 저장소에 푸시합니다.

sequenceDiagram
    participant 메인테이너
    participant 본래 as 본래 저장소
    participant 기여자
    participant 공개 as 기여자의 공개 저장소
    메인테이너->>본래: 푸시한다
    기여자->>본래: 클론해 와서 고친다
    기여자->>공개: 고친 것을 푸시한다
    기여자->>메인테이너: 끌어가 달라고 메일을 보낸다
    메인테이너->>공개: 원격 저장소로 더해 가져온다
    Note over 메인테이너: 자기 컴퓨터에서 시험하고 합친다
    메인테이너->>본래: 합친 것을 푸시한다

합치는 일을 메인테이너가 맡는 대신 기여자는 요청을 보낸 뒤에도 기다리지 않고 제 속도로 일을 이어 갈 수 있습니다. 메인테이너도 언제든 그 변경을 끌어갈 수 있습니다.

요청이 하는 말은 "내 저장소에서 변경을 끌어가(pull) 달라"입니다. 풀 리퀘스트라는 이름도 이 말을 옮긴 것입니다. 기여자가 본래 저장소에 미는 그림이 아니라, 메인테이너가 기여자 쪽에서 끌어가는 그림입니다.

예시

풀 리퀘스트의 실물 넷을 듭니다. 리눅스 커널에 가는 메일 한 통, GitHub 와 GitLab 의 요청 화면, 그리고 요청을 거쳐야만 합칠 수 있게 막는 설정 하나입니다.

리눅스 커널의 풀 리퀘스트 메일

리눅스 커널에서는 한 메인테이너가 자기 저장소에 모은 변경을 다른 메인테이너의 저장소로 넘길 때 풀 리퀘스트를 메일로 보냅니다. char-misc 저장소에서 보내는 요청이 이렇게 만들어집니다.

git tag -s char-misc-4.15-rc1 char-misc-next
git push origin char-misc-4.15-rc1
git request-pull master git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git/ char-misc-4.15-rc1

첫 줄은 char-misc-next 브랜치의 마지막 커밋에 char-misc-4.15-rc1 이라는 태그를 붙입니다. 태그는 커밋 하나에 붙이는 이름표입니다.

-s 는 그 태그에 서명하라는 뜻입니다. 서명에는 GPG(GNU Privacy Guard) 키를 씁니다. 둘째 줄은 그 태그를 원격 저장소에 올립니다.

셋째 줄이 요청 메일의 본문을 만듭니다. 이 명령은 태그가 가리키는 커밋과 master 브랜치 끝을 견줍니다. 끌어갈 저장소 주소는 git:// 로 적습니다.

이 예에서 master 브랜치의 끝은 리누스 토르발스의 저장소에서 갈라져 나온 마지막 지점을 가리킵니다. 상세의 그림으로 보면 이 지점이 출발점입니다. 태그가 가리키는 커밋은 끝 커밋입니다. 갈라져 나온 지점은 대개 시험판(rc, release candidate)입니다.

git request-pull 이 찍는 본문은 이렇게 시작합니다. 꺾쇠 안은 그 요청의 값이 들어가는 칸입니다.

The following changes since commit <출발점 커밋 해시>:

  <그 커밋의 제목> (<날짜>)

are available in the Git repository at:

  <끌어갈 저장소 주소> <브랜치나 태그>

for you to fetch changes up to <마지막 커밋 해시>:

  <그 커밋의 제목> (<날짜>)

----------------------------------------------------------------

커밋 해시는 커밋마다 붙는 고유한 식별 값입니다. 본문은 출발점 커밋과 끝 커밋을 이 해시로 밝힙니다. 두 커밋 사이에 끌어갈 저장소 주소가 옵니다.

그 아래에는 태그에 적은 설명 전문이 붙습니다. 파일마다 몇 줄이 바뀌었는지 요약한 diffstat 과 커밋 제목을 모은 shortlog 도 붙습니다. 이 본문을 메일 본문에 바로 넣어 메인테이너에게 보냅니다. 참조에는 LKML(Linux Kernel Mailing List, 리눅스 커널 메일링 리스트)과 필요한 하위 시스템 메일링 리스트를 겁니다.

메일링 리스트는 한 주소로 보낸 메일을 구독자 모두에게 나눠 주는 목록입니다. 리누스 토르발스에게 가는 요청은 대개 [GIT PULL] <subsystem> changes for v4.15-rc1 같은 제목을 답니다.

GitHub 의 풀 리퀘스트 화면

GitHub 에서는 풀 리퀘스트가 웹 화면 하나입니다. 리뷰어가 변경을 이해하는 데 필요한 것을 탭으로 나눠 모읍니다.

탭 보여 주는 것
Conversation 설명 · 지나온 일의 시간순 기록 · 댓글 · 리뷰
Commits 요청의 브랜치가 시간에 따라 어떻게 바뀌어 왔나
Checks 자동 테스트 · 빌드 · 그 밖의 자동 검증
Files changed 리뷰어가 읽는 변경의 차이
Findings 코드 스캐닝 경고 같은 자동 코드 리뷰 결과

탭과 따로, 병합 상태 표시가 요청 머리와 병합 버튼 상자에 뜹니다. 병합을 막는 것 · 빠진 승인 · 그 밖에 병합 전에 채워야 할 조건을 여기서 보여 줍니다. 상세의 표가 말한 넷 가운데 설명은 Conversation 에, 변경 묶음은 Commits 와 Files changed 에 나뉘어 담깁니다.

GitLab 의 머지 리퀘스트

GitLab 은 같은 일을 머지 리퀘스트라는 이름으로 합니다. 쓰기 권한이 있으면 브랜치를 만들어 커밋을 올립니다. 그리고 그 브랜치에서 master 나 다른 브랜치로 머지 리퀘스트를 엽니다.

쓰기 권한이 없으면 저장소를 포크합니다. 포크는 본래 저장소를 복사해 내 이름 아래 둔 사본입니다. 그 사본에 커밋을 올립니다. 그리고 사본에서 본래 프로젝트로 머지 리퀘스트를 엽니다.

머지 리퀘스트 하나를 열면 설명 · 코드 변경과 줄 단위 리뷰 · CI/CD(Continuous Integration/Continuous Delivery, 지속적 통합과 지속적 전달) 파이프라인 정보 · 병합 가능 여부 보고 · 댓글 · 커밋 목록이 보입니다.

머지 리퀘스트에 붙는 역할은 둘입니다. Assignee 는 요청을 맡아 끝까지 끌고 가는 사람입니다. 대개 작성자가 Assignee 입니다. Reviewer 는 변경을 읽고 의견을 남깁니다. 고쳐 달라고 요구하거나, 자격이 있으면 승인합니다.

풀 리퀘스트 없이는 못 합치게 하는 설정

GitHub 의 보호 브랜치 규칙에는 「Require pull request reviews before merging」이라는 항목이 있습니다. 보호 브랜치는 누가 어떻게 바꿀 수 있는지 조건을 걸어 둔 브랜치입니다.

협업자는 저장소에 푸시할 권한을 받은 사람입니다. 이 항목을 켜면 협업자도 정해 둔 수만큼 승인을 받은 풀 리퀘스트로만 보호 브랜치에 변경을 넣을 수 있습니다.

승인으로 세는 것은 저장소에 쓰기 권한이 있는 리뷰어의 승인입니다. 지정된 코드 소유자의 승인을 받도록 정할 수도 있습니다. 코드 소유자는 저장소의 특정 파일을 맡도록 지정해 둔 사람입니다.

승인이 덜 됐거나 고쳐 달라는 요구가 남은 요청을 보호 브랜치에 합치려 하면 이런 오류를 받습니다.

remote: error: GH006: Protected branch update failed for refs/heads/main.
remote: error: Changes have been requested.

여기에 하나를 더 걸 수 있습니다. 승인 뒤에 요청의 차이를 바꾸는 커밋이 올라오면 그 승인을 낡은 것으로 보고 지우는 선택입니다.

GitHub 는 승인한 때의 차이를 기록해 둡니다. 차이가 그 기록과 달라지면 승인을 거둡니다. 그 뒤로는 누군가 다시 승인할 때까지 합칠 수 없습니다.

동작

요청 하나는 열림에서 시작해 병합되거나, 합치지 않고 닫히는 것으로 끝납니다. 그 사이에 거치는 상태와 갈림을 차례로 적습니다. 세부는 서비스마다 조금씩 다르므로 GitHub 와 GitLab 이 갈리는 대목은 나눠 적습니다.

stateDiagram-v2
    [*] --> 열림: 요청을 연다
    state 열림 {
        state "리뷰 준비" as 준비
        [*] --> 초안: 초안으로 연다
        [*] --> 준비: 바로 연다
        초안 --> 준비: 리뷰 준비를 표시한다
        준비 --> 초안: 초안으로 돌린다 · GitHub 에서
    }
    열림 --> 병합됨: 초안이 아니고 조건을 채우면 합친다
    열림 --> 닫힘: 합치지 않고 접는다
    닫힘 --> 열림: 다시 연다 · GitLab 에서
    병합됨 --> [*]
    닫힘 --> [*]

GitLab 은 요청을 고를 때 상태를 Open · Merged · Closed 로 가릅니다. 그림의 열림 · 병합됨 · 닫힘이 이 셋입니다. 초안은 이 셋과 별개로 열린 요청에 붙는 표시입니다. 그래서 그림에서 초안은 열림 안에 들어 있습니다.

꼬리표에 서비스 이름이 붙은 화살표는 그 서비스의 동작입니다. 다른 서비스도 같은지는 자료에 없습니다(미확인).

초안

요청을 처음부터 초안으로 열 수 있습니다. 초안은 아직 합칠 준비가 안 된 요청입니다. 초안인 동안은 합칠 수 없습니다.

GitHub 는 초안이면 코드 소유자에게 리뷰를 자동으로 청하지 않습니다. 리뷰 준비를 표시하면 그때 코드 소유자에게 리뷰를 청합니다. 열린 요청은 언제든 초안으로 돌릴 수도 있습니다.

GitLab 은 초안 표시를 떼기 전에는 다른 병합 조건을 다 채워도 합치지 않습니다. 준비됐다고 표시하면 요청에 참여한 사람과 지켜보는 사람에게 알립니다.

열려 있는 동안

GitHub 의 열린 요청을 두고 메인테이너는 합치거나, 거절하거나, 의견을 남깁니다. 기여자는 의견을 받으면 요청의 브랜치에 커밋을 더 올립니다. 그 브랜치에 커밋을 다시 푸시하면 요청이 저절로 갱신됩니다.

메일링 리스트로 기여를 받는 프로젝트는 사정이 다릅니다. 이런 프로젝트는 대개 패치 묶음으로 기여를 받습니다. 패치는 변경을 줄 단위 차이로 적은 텍스트입니다. 고칠 것이 생기면 패치 묶음을 새로 만들어 메일링 리스트에 다시 보내야 할 수 있습니다.

이 패치 메일은 저장소 주소를 적어 끌어가 달라고 하는 요청 메일과 다른 것입니다. 요청 메일은 상세에서 본 대로 보낼 때의 끝 커밋까지만 담습니다. 요청 메일은 갈래 절의 「메일로 보내는 요청」에서 다시 봅니다.

GitHub 의 요청은 연 뒤에도 브랜치에 계속 푸시할 수 있습니다. 공개 프로젝트에서는 기여자가 변경을 다 마친 뒤에 요청을 내는 일이 흔합니다. 내부 프로젝트에서는 개발 초기에 요청을 일찍 열어 두는 일도 잦습니다. 팀이 한 요청 안에서 함께 고쳐 나가는 데 씁니다.

GitHub 에서는 받는 브랜치를 잘못 골랐을 때 요청을 닫았다가 새로 열 필요 없이 받는 브랜치만 바꿀 수 있습니다.

병합

GitHub 에서는 제안한 변경이 준비되고 저장소가 건 조건을 다 채웠을 때 합칩니다. 저장소 규칙이나 보호 브랜치가 리뷰 · 상태 검사 · 받는 브랜치의 최신 내용 반영을 병합 조건으로 걸 수 있습니다. 상태 검사는 요청에 걸어 둔 자동 테스트나 빌드의 통과 여부입니다.

합치는 방식은 셋 가운데 고릅니다. 그 전에 낱말 둘을 짚습니다. 병합 커밋은 두 브랜치의 이력을 이었다는 기록으로 남기는 커밋입니다. 빨리 감기 병합(fast-forward)은 병합 커밋을 따로 만들지 않고 받는 브랜치의 끝을 앞으로 옮기기만 하는 병합입니다.

방식 하는 일
Create a merge commit 요청의 커밋을 전부 받는 브랜치에 합치고 병합 커밋을 남긴다. --no-ff(no fast-forward, 빨리 감기를 하지 않는다) 로 합친다
Squash and merge 요청의 커밋을 커밋 하나로 뭉쳐 합친다
Rebase and merge 요청의 커밋을 하나씩 받는 브랜치 위에 다시 얹는다

뒤의 둘은 빨리 감기 병합으로 합칩니다. 요청의 브랜치를 master 에 합쳐 GitHub 에 푸시하면 요청은 저절로 닫힙니다.

GitLab 에서는 리뷰어가 변경에 만족하면 요청을 자동 병합으로 걸어 둘 수 있습니다. 병합 조건 검사 일부가 아직 실패 중이어도 걸 수 있습니다. 검사가 모두 통과하면 따로 손대지 않아도 합쳐집니다.

GitLab 은 프로젝트 구성원마다 역할을 매깁니다. Developer 이상의 역할이면 저장소에 커밋과 브랜치를 바로 푸시할 수 있습니다. Maintainer 는 Developer 보다 높은 역할입니다.

이 Maintainer 는 GitLab 의 역할 이름입니다. 상세에서 말한 메인테이너, 곧 요청을 받아 합칠지 정하는 사람과 같은 말이 아닙니다.

기본 브랜치는 저장소의 본래 줄기 브랜치입니다. GitLab 의 기본 설정에서 병합 권한은 이렇습니다.

  • 기본 브랜치는 보호돼 있습니다. 그 이름은 대개 main 입니다
  • 기본 브랜치에 합칠 수 있는 것은 Maintainer 이상의 역할뿐입니다
  • Developer 는 보호되지 않은 브랜치로 가는 요청을 합칠 수 있습니다

병합 없이 닫기

합치지 않기로 하면 요청을 닫습니다. GitHub 에서는 필요 없어진 변경을 정리하거나 다른 브랜치의 다른 해법으로 가기로 했을 때 요청을 합치지 않고 닫습니다. GitLab 에서는 작업을 영영 멈추기로 했다면 요청을 지우지 않고 닫습니다. 닫아도 GitLab 은 요청과 댓글, 거기 딸린 파이프라인 기록을 남겨 둡니다.

GitLab 에서는 닫은 요청을 /reopen 명령으로 다시 엽니다.

병합된 요청 되돌리기

GitHub 에서 이미 병합된 요청을 무르려면 되돌리는 요청을 새로 냅니다. 이 새 요청은 원래 요청의 병합 커밋을 되돌리는 변경을 담습니다. 이 요청을 만들려면 저장소에 쓸 권한이 있어야 합니다. 되돌리다 충돌이 나면 그 충돌도 이 새 요청 안에서 풉니다.

갈래

풀 리퀘스트는 변경이 놓인 곳과 메인테이너가 그것을 가져가는 길에 따라 셋으로 갈립니다.

갈래 기여자의 권한 변경이 놓인 곳 요청이 오가는 통로
같은 저장소의 브랜치 공유 저장소에 푸시할 수 있다 공유 저장소 안의 브랜치 호스팅 서비스의 요청 화면
포크 본래 저장소를 읽을 수만 있다 내 포크 안의 브랜치 호스팅 서비스의 요청 화면
메일로 보내는 요청 본래 저장소에 쓸 수 없다 내 공개 저장소의 브랜치나 태그 메일

같은 저장소의 브랜치

GitHub 는 이 갈래를 공유 저장소 모델이라고 부릅니다. 협업자 모두가 저장소 하나에 푸시할 수 있습니다. 고칠 일이 생기면 그 저장소 안에 토픽 브랜치를 만듭니다. 토픽 브랜치는 기능 하나나 고칠 거리 하나만 담으려고 만든 브랜치입니다.

flowchart TD
    subgraph 공유["공유 저장소 · 협업자 모두 푸시한다"]
        M["받는 브랜치"]
        T["토픽 브랜치"]
    end
    M -->|갈라 만든다| T
    T -->|풀 리퀘스트를 연다| M

포크할 필요가 없습니다. 쓸 권한이 다 있는데도 요청을 거치는 까닭은 합치기 전에 코드 리뷰와 논의를 시작하기 위해서입니다. 코드 리뷰는 합치기 전에 다른 사람이 변경을 읽고 의견을 남기는 일입니다. 작은 팀이나 조직이 비공개 프로젝트를 함께할 때 더 흔한 방식입니다.

GitLab 에서도 Developer 이상의 역할이면 커밋과 브랜치를 저장소에 바로 푸시합니다. 그리고 그 브랜치에서 머지 리퀘스트를 엽니다.

포크

본래 저장소에 푸시할 권한이 없으면 포크를 씁니다. 앞에서 본 대로 포크는 본래 저장소를 복사해 내 이름 아래 둔 사본입니다. 그 사본에는 내가 푸시할 수 있습니다.

GitHub 는 이 갈래를 포크 앤 풀 모델이라고 부릅니다. 본래 저장소를 읽을 수 있고 주인이 허락했다면 누구나 포크할 수 있습니다. 내가 만든 포크에 푸시하는 데는 본래 저장소의 허락이 필요 없습니다.

flowchart TD
    subgraph 원본["본래 저장소 · 기여자는 읽기만 한다"]
        M["받는 브랜치"]
    end
    subgraph 포크["기여자의 포크 · 기여자가 푸시한다"]
        F["고친 브랜치"]
    end
    M -->|포크해 온다| F
    F -->|풀 리퀘스트를 연다| M

요청은 내 포크의 브랜치에서 본래 저장소의 브랜치로 엽니다. 본래 저장소는 기여자를 협업자로 들여 푸시 권한을 줄 필요 없이 변경만 받아 갑니다. 새 기여자가 미리 맞추지 않고도 혼자 일을 시작할 수 있어 오픈 소스 프로젝트에서 널리 씁니다.

메일로 보내는 요청

호스팅 서비스 없이 메일로 내는 방식입니다. 기여자는 먼저 남이 볼 수 있는 자기 공개 저장소에 변경을 푸시합니다. 그다음 git request-pull 로 요청 본문을 만들어 메일로 보냅니다. v1.0 판 위에 master 브랜치로 작업했다면 이렇게 합니다.

git push https://git.ko.xz/project master
git request-pull v1.0 https://git.ko.xz/project master

이 본문은 v1.0 이후 master 까지 쌓인 변경을 요약합니다. 그 변경을 어느 저장소에서 끌어가면 되는지도 적습니다. 출발점인 v1.0 커밋은 받는 쪽 이력에 이미 있어야 합니다. 메인테이너는 그 저장소를 원격 저장소로 더해 가져와 자기 컴퓨터에서 합칩니다.

앞의 두 갈래는 대체로 이 흐름에서 메일 대신 웹 화면으로 변경을 주고받으며 리뷰하는 방식입니다.

서명된 태그는 만든 사람이 자기 키로 서명해 둔 태그입니다. 리눅스 커널에서 리누스 토르발스는 서명된 태그를 바탕으로 한 요청만 받습니다. 다른 메인테이너는 다를 수 있습니다. 태그에 적은 설명은 메인테이너가 요청을 합치면 병합 커밋에 들어가 커널 이력에 영영 남습니다.

관련 항목

풀 리퀘스트를 올리기까지 거치는 단계

클론 · 브랜치 · 토픽 브랜치 · 커밋 · 푸시 · 포크 · 원격 저장소

풀 리퀘스트를 받아들이는 병합 방식

병합 · 병합 커밋 · 빨리 감기 병합 · 스쿼시 병합 · 리베이스 · 충돌 해소 · git revert

풀 리퀘스트 안에서 오가는 검토 활동

코드 리뷰 · 코드 소유자 · 리뷰어 · 초안 풀 리퀘스트 · 커밋 메시지

풀 리퀘스트의 병합을 막아 세우는 조건과 검사

보호 브랜치 · 병합 전 검사 · 지속적 통합 · CI/CD 파이프라인 · 자동 테스트 · 코드 스캐닝 · 자동 병합

풀 리퀘스트를 메일로 내는 데 쓰는 도구

git request-pull · 태그 · 서명된 태그 · GPG · 패치 · 메일링 리스트 · LKML · git shortlog · diffstat

풀 리퀘스트를 여는 방식을 정하는 협업 워크플로

중앙 집중식 워크플로 · 통합 관리자 워크플로 · GitHub Flow · 공유 저장소 모델 · 포크 앤 풀 모델

풀 리퀘스트를 주고받는 저장소 서비스와 프로젝트

Git · GitHub · GitLab · 리눅스 커널 · 오픈 소스

다른 이름: PR · Pull Request · pull request · 풀리퀘스트 · 머지 리퀘스트 · merge request