Skip to content
This page has been auto-translated and may contain errors.View in English

풀 리퀘스트 플로우

docs.scrimba.com

자신의 브랜치에서 기능 작업을 완료했습니다. 프로젝트는 공유 중입니다: 다른 사람들도 커밋합니다. 따라서 main에 직접 푸시해서 운을 바라지는 않습니다. 변경 사항을 검토받고, 필요하면 논의하고, 팀 전체가 볼 수 있는 방식으로 머지하길 원합니다. 자신의 머신의 브랜치에서 코드가 main에 적용되는 전체 경로가 바로 풀 리퀘스트 플로우이며, 이는 GitHub의 거의 모든 팀이 변경 사항을 적용하는 방식입니다. Git 측면에서는 이전 장의 명령어들만 사용합니다: 브랜치, 커밋, 푸시:

bash
$ git switch -c add-five-day-forecast
Switched to a new branch 'add-five-day-forecast'
$ git add src/forecast.js
$ git commit -m "5일 예보 패널 추가"
$ git push -u origin add-five-day-forecast
Branch 'add-five-day-forecast' set up to track 'origin/add-five-day-forecast'.

이 푸시는 브랜치를 GitHub로 보냅니다. 아직 머지되지 않았고, 검토를 위해 제안조차 되지 않았습니다. 다음 단계인 풀 리퀘스트 오픈은 GitHub 웹사이트에서 이루어집니다.

풀 리퀘스트를 오픈할 때 일어나는 일

GitHub에서 위와 같은 푸시 후, 새 브랜치를 main과 비교하는 것을 제안하는 배너가 표시됩니다. 이를 클릭하고 제목과 변경 사항 및 이유에 대한 짧은 설명을 작성한 후 페이지를 오픈합니다. 이 페이지가 바로 **풀 리퀘스트**이며, 종종 PR로 약칭됩니다: 한 브랜치를 다른 브랜치로 머지하는 요청이며, 이에 붙어 있는 지속적인 대화입니다.

풀 리퀘스트는 머지를 제안하고 승인을 기다립니다. 누군가 (당신일 수도, 팀 동료일 수도) 변경 사항을 읽고, 의견을 남기고, 문제없어 보일 때만 머지합니다. 그때까지 브랜치와 main은 페이지를 오픈하기 전과 정확히 같은 상태입니다.

기능이 완료될 때까지 기다릴 필요가 없습니다. 많은 팀들은 일찍 PR을 오픈하고 드래프트로 표시합니다. 이는 "아직 검토 준비가 안 됨"을 나타내면서 동시에 작업이 끝나기 전에 리뷰어가 방향에 대해 의견을 남길 수 있는 장소를 제공합니다. 좋은 설명은 관련 이슈를 연결하고 테스트한 내용을 언급하므로, 리뷰어가 diff만으로 그것을 재구성할 필요가 없습니다.

GitHub는 PR의 브랜치를 자신의 저장소에 추가하기 전에도 원격의 모든 풀 리퀘스트에 대한 참조를 유지합니다: refs/pull/<number>/head. 이를 직접 페치하여 포크를 원격으로 추가하지 않고도 팀 동료의 PR을 자신의 머신에서 체크아웃할 수 있습니다.

bash
$ git fetch origin pull/42/head:pr-42
From github.com:김민준/weather-app
 * [new ref]         refs/pull/42/head -> pr-42
$ git switch pr-42
Switched to branch 'pr-42'

이제 pr-42는 풀 리퀘스트 번호 42로부터 빌드된 실제 로컬 브랜치이며, 한 줄의 의견을 남기기 전에 실행하고 테스트할 준비가 되어 있습니다.

Juno풀 리퀘스트를 오픈할 때 일어나는 일 풀 리퀘스트는 브랜치를 다른 브랜치로 머지하는 요청이며, 푸시 후 GitHub에서 오픈됩니다. 누군가 먼저 변경 사항을 검토하고, 그 후에야 머지됩니다. 일상적인 루프는 브랜치 생성, 푸시, 풀 리퀘스트 오픈, 코드 리뷰, 머지입니다.
Juno풀 리퀘스트를 오픈할 때 일어나는 일 PR은 머지를 제안하고 이에 대한 대화를 유지하며, 작업이 완료되기 전에 피드백을 받기 위해 드래프트로 일찍 오픈할 수 있습니다. 실제로 읽을 리뷰어처럼 설명을 작성하세요: 무엇이 변경되었는지, 왜, 그리고 무엇을 테스트했는지.
Juno풀 리퀘스트를 오픈할 때 일어나는 일 GitHub는 모든 풀 리퀘스트에 대한 숨겨진 참조 refs/pull/<number>/head를 유지하므로, git fetch origin pull/42/head:pr-42를 사용하여 팀 동료의 PR을 포크를 원격으로 추가하지 않고도 직접 머신으로 페치할 수 있습니다. 첫 번째 의견을 남기기 전에 로컬에서 변경 사항을 테스트하세요.

포크 vs 브랜치

저장소에 대한 쓰기 액세스 권한이 있을 때 브랜치에서 풀 리퀘스트를 오픈하는 것이 작동합니다. 이는 자신의 팀 프로젝트에서 정상적인 경우입니다. 쓰기 액세스 권한이 없는 프로젝트에 기여하려면 추가 단계가 필요합니다: 포크, 자신의 GitHub 계정 아래의 저장소 자신의 복사본입니다.

포크 내에서 정확히 소유한 프로젝트에서 했을 것처럼 브랜치를 만들고 커밋하고, 포크로 푸시한 다음, 포크의 브랜치에서 원본 저장소로 풀 리퀘스트를 오픈합니다. GitHub는 한 저장소 내의 두 브랜치를 비교하는 것과 동일한 방식으로 두 저장소를 비교하므로, 검토 및 머지 플로우는 어느 쪽이든 동일하게 보입니다.

포크한 프로젝트에 하나 이상의 PR을 보낼 계획이라면, 원본 저장소를 두 번째 원격으로 추가하는 것이 도움이 됩니다. 보통 upstream으로 명명되며, origin은 자신의 포크를 가리킵니다. git fetch upstream을 실행하고 브랜치에 upstream/main을 머지하여 포크 이후 진행된 프로젝트를 따라잡으면, 원격 및 GitHub 장이 모든 원격에 대해 다루는 동일한 단계를 사용합니다.

Juno포크 vs 브랜치 저장소에 대한 쓰기 액세스 권한이 있을 때 직접 브랜치를 만드세요. 자신의 팀 프로젝트에서 말입니다. 그렇지 않을 때는 포크를 사용하세요: 포크는 다른 사람의 저장소를 자신의 계정 아래에 복사한 것이며, 풀 리퀘스트를 원본으로 다시 오픈하기 전에 포크 내에서 브랜치를 만들고 푸시합니다.
Juno포크 vs 브랜치 포크는 계정 아래의 저장소 전체 복사본이며, 쓰기 액세스 권한이 없는 곳에 기여할 때 사용됩니다. 정상처럼 포크 내에서 브랜치를 만들고, 커밋하고, 푸시하며, GitHub는 포크의 브랜치를 원본 저장소와 비교합니다. 이는 한 프로젝트 내의 두 브랜치를 비교하는 것과 동일합니다.
Juno포크 vs 브랜치 포크된 프로젝트에 두 개의 원격을 유지하세요: origin은 자신의 포크, upstream은 원본 저장소이므로 진행하면서 그 변경 사항을 페치하고 머지할 수 있습니다. PR 자체는 여전히 포크의 브랜치를 원본 저장소의 기본 브랜치와 비교합니다.

풀 리퀘스트 리뷰 진행하기

PR이 오픈되면, diff에 대한 진행 중인 대화가 되어집니다. 리뷰어가 변경 사항을 읽고, 특정 줄에 의견을 남기고, 승인하거나 변경을 요청합니다. 변경이 요청될 때, 같은 브랜치로 계속 커밋하고 푸시하세요: 모든 푸시가 새로운 것을 만드는 대신 같은 PR을 업데이트합니다. 리뷰어가 승인하고 필요한 모든 확인이 통과되면, PR은 머지할 준비가 되어 있습니다.

GitHub는 리뷰를 세 가지 상태 중 하나로 추적합니다: 승인됨, 변경 요청됨, 또는 의견 표시됨 (평결 없이 피드백). 의견을 다루면서 답변하고 대화를 해결된 것으로 표시하여 리뷰어가 남은 것이 무엇인지 한눈에 볼 수 있도록 하세요. 특정 의견에 대한 수정을 푸시한다면, 커밋 메시지나 답변에서 그렇게 말하면 도움이 됩니다. 긴 PR을 진행 중인 리뷰어는 정확히 그것을 스캔하고 있기 때문입니다.

PR이 몇 개의 승인이 필요한지, 모든 의견 스레드가 머지 버튼이 잠금 해제되기 전에 해결된 것으로 표시되어야 하는지 여부는 보통 잘 운영되는 프로젝트에서 기본 브랜치 자체에 첨부된 규칙입니다.

Juno풀 리퀘스트 리뷰 진행하기 리뷰어가 풀 리퀘스트에 의견을 남기고 변경을 요청할 수 있습니다. 같은 브랜치로 더 많은 작업을 커밋하고 푸시하여 이를 해결하면, PR이 자동으로 업데이트됩니다. 누군가 승인하면 머지가 발생합니다.
Juno풀 리퀘스트 리뷰 진행하기 리뷰는 세 가지 상태 중 하나로 표시됩니다: 승인됨, 변경 요청됨, 또는 의견 표시됨. 같은 브랜치로 수정을 푸시하여 PR을 업데이트하고, 의견을 해결하면서 답변하고, 긴 스레드에서 리뷰어를 지향하게 하세요.
Juno풀 리퀘스트 리뷰 진행하기 리뷰 상태는 머지 버튼이 잠금 해제되는지 여부를 결정하지만, 정확한 기준인 몇 개의 승인이 필요한지, 모든 의견 스레드가 해결되어야 하는지 여부는 보통 잘 운영되는 프로젝트에서 기본 브랜치 자체에 첨부된 규칙입니다.

풀 리퀘스트가 머지되지 않는 이유

때로는 PR의 머지 버튼이 회색으로 표시되고, GitHub는 그 대신 메시지를 표시합니다: "이 브랜치에는 해결해야 할 충돌이 있습니다" 또는 "이 브랜치는 기본 브랜치와 비교하여 오래되었습니다." 두 메시지 모두 정상적이고 고칠 수 있는 상태를 설명합니다: main은 브랜치 이후로 진행되었습니다. 보통 다른 누군가의 PR이 그 사이에 머지되었기 때문이며, 브랜치는 GitHub가 둘을 깔끔하게 결합할 수 있기 전에 따라가야 합니다. 하나 이상의 기여자가 있는 모든 프로젝트에서 이런 일이 발생하므로, 이를 두려워하기보다는 예상하세요.

로컬에서 두 브랜치를 함께 가져오는 것과 동일한 방식으로 고치세요:

bash
$ git switch add-five-day-forecast
$ git fetch origin
From github.com:김민준/weather-app
   9f8e7d6..b7c9e21  main       -> origin/main
$ git merge origin/main

아무것도 겹치지 않으면 머지가 자체적으로 완료되고 푸시하면, PR이 업데이트되고 버튼이 잠금 해제됩니다. 같은 줄이 양쪽에서 변경되면, Git이 충돌을 파일에 표시하여 정확히 머징 및 충돌에서 다루어진 대로 해결합니다: 파일을 열고, 충돌 마커를 편집하여 원하는 결과로 만든 다음, git addgit commit으로 머지를 완료하고 다시 푸시합니다.

막힌 풀 리퀘스트는 따라가거나 충돌을 해결해야 합니다.

1-2일 이상 열려 있는 PR에서는, 버튼이 블록될 때까지 기다리기보다는 때때로 브랜치로 main을 머지하는 것이 좋습니다. 1일 정도 오래된 브랜치는 보통 전혀 충돌 없이 머지됩니다; 3주 오래된 것은 두 변경 사항이 같은 줄에서 충돌할 훨씬 더 많은 표면을 가집니다. GitHub의 PR 페이지 "브랜치 업데이트" 버튼은 손으로 해결할 것이 없을 때 당신을 위해 이 같은 머지를 합니다.

일부 팀은 기능 브랜치를 main으로 리베이스하는 대신 머지합니다. 이는 모든 PR에 대한 머지 커밋을 표시하기보다는 결국 이력을 선형으로 유지하기 위해서입니다. 이 트레이드오프는 머징 및 충돌에서 다루어진 것과 동일합니다: 리베이싱은 브랜치의 커밋을 다시 쓰는데, 이는 이들의 복사본을 가진 사람이 당신뿐이라면 안전하므로, 머신에만 있고 PR만 있는 솔로 기능 브랜치는 합리적인 후보입니다. 다른 사람들이 이미 풀하고 그 위에 빌드한 브랜치를 리베이싱하는 것은 그들이 의존하고 있는 이력을 다시 쓰기 때문에 아닙니다.

Juno풀 리퀘스트가 머지되지 않는 이유 회색으로 표시된 머지 버튼은 브랜치가 main 뒤에 있거나 충돌이 있다는 의미입니다. 아무것도 깨진 게 아닙니다. 브랜치로 전환하고, 페치하고, main을 머지하여 충돌이 있으면 다른 곳에서처럼 해결한 후 다시 푸시하세요.
Juno풀 리퀘스트가 머지되지 않는 이유 GitHub가 머지 버튼을 블록할 때까지 기다리기보다는 장기 실행 브랜치에 가끔 main을 머지하세요. 더 작고 더 자주하는 따라가기는 더 작은 충돌을 의미하며, GitHub의 "브랜치 업데이트" 버튼은 충돌이 없는 경우를 처리할 수 있습니다.
Juno풀 리퀘스트가 머지되지 않는 이유 브랜치를 main으로 머지하거나 리베이싱하는 것 모두 막힌 PR을 고칠 수 있으며, 솔로 기능 브랜치는 아무도 그 커밋의 복사본을 가지지 않으므로 리베이싱이 안전합니다. 다른 사람들이 브랜치를 풀했을 때, 대신 머지를 고수하세요.

풀 리퀘스트가 무엇인지, 내부적으로

풀 리퀘스트는 Git 객체가 아니며, 풀 리퀘스트를 만드는 git 명령어는 없습니다. Git과 GitHub는 같은 것이 아닙니다: Git은 커밋, 브랜치, 그리고 다른 참조만 알고 있습니다 (참조는 커밋을 가리키는 이름입니다). GitHub는 비교하는 두 개의 참조 위에 전체 PR 페이지, 의견, 그리고 머지 버튼을 구축합니다: 브랜치 (헤드) 와 머지하려는 브랜치 (기본, 보통 main). 이 비교가 바로 GitHub의 웹사이트에서 (또는 GitHub 자신의 명령줄 도구나 API를 통해) 풀 리퀘스트를 오픈하는 이유이며, 순수 git 명령어로는 절대 하지 않는 이유입니다.

PR은 저장소의 이력과 별개로 GitHub에 있기 때문에, 그 의견과 리뷰 대화는 커밋과 함께 이동하지 않습니다. 프로젝트를 다른 호스트로 옮길 때마다, 모든 커밋은 변경되지 않은 상태로 당신을 따라 이동하지만, 풀 리퀘스트와 그 논의는 GitHub에 남아 있습니다. 이는 처음부터 Git 데이터의 일부가 아니었기 때문입니다.

GitHub는 머지 기반(merge base)을 찾아서 PR의 diff를 계산합니다. 머지 기반은 헤드 참조와 기본 참조가 공유하는 가장 최근의 커밋입니다. 그리고 현재의 main 모양과 상관없이 그 지점에 대해 헤드를 비교합니다. 브랜치로의 각 푸시는 새 비교를 만드는 대신 같은 PR에 새 버전을 추가합니다. **브랜치 보호**는 모든 이것 위에 앉아 있는 정책 계층입니다: 브랜치에 (당신 또는 조직이) 첨부하는 규칙이며, 대부분 main이며, 상태 확인이 통과되도록 요구하고, 승인하는 리뷰 세트를 요구하고, 모든 변경이 풀 리퀘스트를 통해 강제되도록 직접 푸시를 블록할 수 있습니다. Git 자체는 이 중 어느 것도 강제하지 않습니다. 터미널에서 main으로 직접 푸시하도록 할 수 있으며, GitHub의 규칙이 요청을 거절할 때까지 입니다.

Juno풀 리퀘스트가 무엇인지, 내부적으로 풀 리퀘스트는 Git 위에 계층화된 GitHub 기능입니다: Git은 커밋과 브랜치를 추적하고, GitHub는 두 개를 비교하여 PR 페이지와 머지 버튼을 추가합니다. Git과 GitHub를 머리 속으로 분리하는 것은 그렇지 않으면 마법처럼 보이는 많은 것을 설명합니다.
Juno풀 리퀘스트가 무엇인지, 내부적으로 PR은 브랜치를 기본 브랜치와 비교하고 전적으로 GitHub에 존재하므로, 저장소가 호스트를 변경할 때 그 의견과 리뷰 이력은 이동하지 않습니다. 커밋 자체가 정말로 Git인 유일한 부분입니다.
Juno풀 리퀘스트가 무엇인지, 내부적으로 PR은 GitHub가 헤드 참조를 기본 참조와 비교하는 것입니다. 각 푸시로 업데이트되는 그들의 공유 머지 기반에서부터입니다. 브랜치 보호는 머지 전에 확인이나 리뷰를 요구하는 위에 강제된 정책입니다. Git 자체는 이 중 어느 것도 강제하지 않습니다: GitHub의 규칙이 이를 중단할 때까지 main으로 직접 푸시하도록 할 수 있습니다.