풀 리퀘스트
고친 사람 github-actions[bot]
풀 리퀘스트는 내가 따로 고친 코드를 본래 코드에 합쳐 달라고 내는 요청입니다. 받는 쪽은 그 변경을 읽어 보고 합칠지 정합니다. 요청 하나에 바뀐 내용과 그걸 두고 오간 말이 함께 모입니다.
쉽고 빠른 이해
고친 코드를 "가져가 합쳐 주세요"라고 받는 쪽에 내는 요청입니다. 리눅스 커널에서는 이 요청을 메일 한 통으로 보냅니다. GitHub 에서는 웹 화면 하나로 엽니다. GitLab 은 같은 것을 머지 리퀘스트라고 부릅니다.
이게 없으면 본래 저장소에 쓸 권한을 모두에게 나눠 줘야 합니다. 그렇게 하면 들어오는 변경을 받는 쪽이 먼저 보고 고를 틈이 없습니다.
- 내 브랜치나 내 사본 저장소에서 고칩니다
- 그 변경을 가져가 합쳐 달라고 요청을 냅니다
- 받는 쪽이 짚은 곳을 더 고쳐 올립니다. GitHub 에서는 다시 올리면 요청에 담긴 변경도 따라 바뀝니다
- 받아들이면 합쳐집니다. 접으면 합치지 않고 닫힙니다
대가는 합치는 손이 받는 쪽에 몰린다는 것입니다. 읽고 시험하고 합치는 일을 받는 쪽이 맡습니다. 승인이나 자동 검사를 조건으로 걸어 두면 그 조건을 채울 때까지 합칠 수 없습니다.
상세
여럿이 함께 쓰는 문서에서 글을 바로 고치지 않고 「수정 제안」으로 남겨 본 적이 있을 겁니다. 고친 내용은 제안으로 붙어 있습니다. 문서를 맡은 사람이 그 제안을 읽어 보고 받아들이거나 거절합니다. 제안 옆에는 왜 그렇게 고쳤는지 묻고 답한 댓글이 같이 달립니다.
풀 리퀘스트(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 · 공유 저장소 모델 · 포크 앤 풀 모델
풀 리퀘스트를 주고받는 저장소 서비스와 프로젝트
다른 이름: PR · Pull Request · pull request · 풀리퀘스트 · 머지 리퀘스트 · merge request