Insights·2026-08-27

PR과 MR은 무엇이 다른가

PR(Pull Request)과 MR(Merge Request)은 같은 기능이고 이름만 다르다. GitHub·Bitbucket·Gitea·Azure DevOps는 Pull Request라고 부르고, GitLab은 Merge Request라고 부른다. 브랜치 두 개의 차이를 보여 주고 리뷰를 받고 합치는 절차는 어디서나 같다. 흥미로운 것은 Git 자체에도 pull request가 있다는 점이다. git request-pull 명령이 실제로 존재한다. 다만 그 명령이 하는 일은 여기서 여기까지 가져가 달라는 요약문을 표준 출력으로 뿌리는 것뿐이고, 리뷰 화면도 승인 버튼도 열림·닫힘 같은 상태도 없다. 메일링 리스트에 붙여 보내라고 만든 명령이기 때문이다. 그러므로 우리가 매일 쓰는 PR·MR은 그 텍스트가 아니라 호스팅 서비스가 그 위에 얹은 웹 객체다. 진짜 차이는 이름이 아니라 각 서비스가 그 객체에 무엇을 붙여 뒀느냐에서 갈리고, 그 차이는 터미널에서 바로 확인된다. 승인은 GitHub에서 리뷰에 딸린 플래그 하나지만 GitLab에서는 독립 명령이며 승인 자격자 조회와 승인 철회가 따로 있다. 반대로 CI 상태는 GitHub이 PR에 붙여 뒀고 GitLab은 파이프라인을 별도 계층으로 뺐다. 팀이 두 플랫폼을 오갈 때 새로 써야 하는 것은 용어집이 아니라 승인 규칙 문서다.

PR과 MR은 같은 물건이다 — 이름만 다르고 규칙은 플랫폼이 쥔다. 나란히 놓인 두 터미널 창에 gh pr과 glab mr 라벨이 붙어 있고, GitHub은 Pull GitLab은 Merge, git request-pull은 요약문만 출력한다, 리뷰 화면·승인·상태는 플랫폼의 몫, gh pr을 glab mr로 바꾸면 그대로 된다는 네 줄이 함께 조판된 포스터

PR과 MR은 무엇이 다른가

협업으로 코드를 짜기 시작하면 곧 이 말을 듣게 된다. "PR 올렸어요." 또는 "MR 리뷰 좀 부탁해요." 회사를 옮겼더니 지금까지 PR이라고 부르던 것을 다들 MR이라고 부르고 있으면 한 번 멈칫하게 된다. 내가 배운 것이 여기서는 안 통하는 걸까 싶어서다.

결론부터 말하면 같은 것이다. GitHub이 Pull Request, GitLab이 Merge Request라고 부를 뿐이다. Bitbucket도, Gitea와 그 포크인 Forgejo도, Azure DevOps도 Pull Request 쪽이다. 어느 쪽이든 하는 일은 똑같다. 내 브랜치와 합칠 대상 브랜치의 차이를 화면에 보여 주고, 동료가 그 차이에 댓글을 달아 리뷰하고, 합의가 되면 버튼을 눌러 합친다.

이름이 갈린 것은 같은 일을 어느 쪽에서 보느냐의 차이다. pull은 요청받는 쪽의 동작이다. 내 브랜치를 당겨가 달라는 뜻이다. merge는 그 요청이 이루어진 결과다. 합쳐 달라는 뜻이다. 실제로 GitHub CLI의 gh pr create 도움말에는 지금도 대상 저장소를 포크할지 물어보는 대목이 남아 있다. 남의 저장소에 기여하는 그림이 이름에 배어 있는 셈이다.

그러니 실무에서는 섞어 써도 서로 다 알아듣는다. GitLab을 쓰는 팀에서 "PR 올렸어요"라고 해도 아무도 못 알아듣지 않는다. 용어가 문제인 경우는 거의 없다.

플랫폼부르는 이름URL 경로
GitHubPull Request (PR)/pull/123
GitLabMerge Request (MR)/-/merge_requests/123
BitbucketPull Request (PR)/pull-requests/123
Gitea · ForgejoPull Request (PR)/pulls/123
Azure DevOpsPull Request (PR)/pullrequest/123

Git에도 pull request가 있다 — git request-pull

git request-pull을 확인하고 사용법을 보는 명령이 담긴 터미널 화면. 리뷰 화면도 승인 버튼도 상태도 없고 표준 출력으로만 나온다는 설명이 아래에 붙어 있다.

여기서 많이들 놓치는 사실이 하나 있다. Git 자체에도 pull request가 있다. 비유가 아니라 진짜로 그 이름의 명령이 있다.

터미널을 열고 git request-pull이라고 쳐 보자. 인자 없이 치면 사용법이 뜬다. 시작 지점과 저장소 주소를 주면, 그 시작 지점 이후로 내가 만든 커밋들을 정리해서 여기서 가져가 달라는 요약문을 만들어 준다. 공식 문서의 표현으로는 상위 프로젝트에 내 변경을 당겨가 달라고 요청하는 글을 생성하는 명령이다.

그런데 그게 전부다. 그 명령이 만들어 주는 것은 화면에 출력되는 글자뿐이다. 리뷰 화면이 뜨지 않는다. 승인 버튼이 없다. 열림이나 닫힘 같은 상태도 없고, 댓글을 달 자리도 없고, 누가 승인했는지 기록되지도 않는다. 심지어 어디로 보내지지도 않는다. 표준 출력으로 나올 뿐이다.

원래 그렇게 쓰라고 만든 것이기 때문이다. 리눅스 커널처럼 메일링 리스트로 개발하던 방식에서는, 이 명령의 출력을 복사해 메일 본문에 붙이고 관리자에게 보냈다. 관리자는 그 메일을 읽고 직접 git pull을 쳤다. 리뷰는 메일 답장으로 오갔다.

직접 쳐 보기
# 명령이 있는지 확인 (사용법이 출력된다)
git request-pull

# 실제 형태
git request-pull <시작커밋> <저장소URL> [<끝커밋>]

# 예: main 이후 내 브랜치 커밋을 가져가 달라는 요약문
git request-pull main https://github.com/me/repo.git my-branch

# 자세한 설명
git help request-pull

그럼 우리가 매일 쓰는 PR·MR은 무엇인가

앞의 두 문단을 붙이면 답이 나온다. 우리가 매일 여는 그 화면은 Git의 기능이 아니다. 호스팅 서비스가 Git 위에 얹은 웹 객체다.

Git이 하는 일은 브랜치 두 개의 차이를 계산하는 것까지다. 그 차이를 웹 페이지로 그려 주고, 줄마다 댓글을 달게 해 주고, 누가 승인했는지 기록하고, 자동화된 검사를 붙이고, 조건을 만족했을 때만 합치기 버튼을 활성화하는 것은 전부 GitHub·GitLab 같은 제품의 몫이다. 그래서 PR·MR에는 번호가 붙고, 열림과 닫힘이라는 상태가 있고, 담당자와 라벨이 붙는다. Git에는 이런 개념이 하나도 없다.

이 구분이 실무에서 왜 중요한가. 로컬 Git 지식만으로는 팀의 협업 규칙을 알 수 없기 때문이다. git merge를 아무리 잘 알아도, 우리 팀에서 몇 명이 승인해야 합칠 수 있는지는 Git이 아니라 플랫폼 설정에 있다. 그리고 바로 그 설정이 GitHub과 GitLab에서 다르게 생겼다.

터미널에서 드러나는 진짜 차이 — gh pr과 glab mr

두 플랫폼의 차이를 가장 빠르게 확인하는 방법은 각 회사가 만든 공식 CLI의 서브커맨드 목록을 나란히 놓아 보는 것이다. 제품이 무엇을 1급 개념으로 취급하는지가 명령 구조에 그대로 드러난다.

GitHub CLI에서 승인은 리뷰의 플래그 하나다. gh pr review --approve라고 쓴다. 승인·댓글·변경요청이 모두 review라는 한 명령의 옵션이다. 반면 GitLab CLI에서 승인은 그 자체로 독립 명령이다. glab mr approve가 있고, 그 옆에 승인 자격이 있는 사람을 조회하는 approvers와 이미 한 승인을 되돌리는 revoke가 따로 있다.

CI 상태는 반대다. GitHub은 파이프라인 결과를 PR에 붙여 뒀다. gh pr checks를 치면 그 PR의 검사 결과가 나온다. GitLab에는 glab mr checks 같은 것이 없다. 대신 glab ci라는 별도의 최상위 명령 계층이 있고 파이프라인은 거기서 다룬다.

그 밖에도 결이 다른 명령이 몇 개 보인다. GitLab에는 소스 브랜치를 대상 브랜치 위로 다시 얹는 glab mr rebase가 있고, 이슈에서 곧장 MR을 만드는 glab mr for가 있다. GitHub에는 브랜치를 최신으로 맞추는 gh pr update-branch, 합친 PR을 되돌리는 gh pr revert, 리뷰 준비가 끝났다고 표시하는 gh pr ready가 있다.

하려는 일GitHub (gh)GitLab (glab)
만들기gh pr createglab mr create
목록 보기gh pr listglab mr list
로컬로 받기gh pr checkoutglab mr checkout
변경 보기gh pr diffglab mr diff
승인하기gh pr review --approveglab mr approve
승인 되돌리기(리뷰 다시 제출)glab mr revoke
승인 자격자 조회(전용 명령 없음)glab mr approvers
CI 상태 보기gh pr checksglab ci (별도 계층)
합치기gh pr mergeglab mr merge
서브커맨드 목록 직접 비교하기
# GitHub CLI
gh pr --help

# GitLab CLI
glab mr --help

# 승인이 어디에 붙어 있는지 확인
gh pr review --help      # --approve 플래그로 나온다
glab mr approve --help   # 독립 명령으로 나온다

처음 올려 보는 순서 — GitHub과 GitLab 양쪽

GitHub에 PR을 올리는 명령과 GitLab에 MR을 올리는 명령을 위아래 두 터미널에 나란히 놓아, 설치·로그인·푸시·생성·머지 순서가 양쪽에서 대칭임을 보여 주는 그림.

이름이 다를 뿐 절차가 같다는 말은, 실제로 명령을 쳐 보면 곧바로 확인된다. 아래 순서는 양쪽이 완전히 대칭이다. 명령의 pr을 mr로, gh를 glab으로 바꾸면 그대로 GitLab이 된다.

먼저 CLI를 설치하고 로그인한다. 맥이라면 둘 다 Homebrew로 설치된다. 로그인은 각각 gh auth login과 glab auth login이고, 브라우저가 열려 계정 인증을 받는다. 이 과정은 한 번만 하면 된다.

그다음은 평소 Git 작업과 같다. 작업할 브랜치를 만들고, 커밋하고, 원격에 올린다. 여기까지는 GitHub이든 GitLab이든 순수 Git이라 차이가 없다.

마지막에 PR·MR을 만든다. 양쪽 CLI 모두 --fill 옵션이 있어서 커밋 메시지에서 제목과 본문을 자동으로 채워 준다. 아직 리뷰받을 준비가 안 됐다면 --draft를 붙여 초안으로 올린다. 초안은 합치기 버튼이 잠긴 상태로 열리므로, 작업 중인 것을 미리 공유하고 싶을 때 쓴다.

올린 뒤에는 브라우저를 열 필요 없이 터미널에서 확인할 수 있다. gh pr view --web처럼 --web을 붙이면 브라우저로 열리고, 그냥 view만 치면 제목과 본문과 상태가 터미널에 출력된다.

GitHub에 PR 올리기
# 최초 1회
brew install gh
gh auth login

# 작업
git switch -c fix-login
git commit -am "로그인 실패 시 메시지 수정"
git push -u origin fix-login

# PR 만들기 (커밋에서 제목·본문 자동 채움)
gh pr create --fill

# 초안으로 올리기
gh pr create --fill --draft

# 확인하고 합치기
gh pr view
gh pr checks
gh pr merge --squash
GitLab에 MR 올리기 (같은 순서)
# 최초 1회
brew install glab
glab auth login

# 작업
git switch -c fix-login
git commit -am "로그인 실패 시 메시지 수정"
git push -u origin fix-login

# MR 만들기 (커밋에서 제목·본문 자동 채움)
glab mr create --fill

# 초안으로 올리기
glab mr create --fill --draft

# 확인하고 합치기
glab mr view
glab mr approve
glab mr merge

팀을 옮길 때 다시 써야 하는 문서

그래서 팀이 GitHub에서 GitLab으로, 또는 그 반대로 옮길 때 실제로 손이 가는 곳은 어디인가. 용어집이 아니다. PR을 MR로 바꿔 쓰는 것은 하루면 익숙해진다.

다시 써야 하는 것은 승인 규칙 문서다. 몇 명이 승인해야 합칠 수 있는지, 코드 소유자의 승인이 필수인지, 새 커밋이 올라오면 기존 승인이 무효가 되는지, 승인을 되돌릴 수 있는지. 이 규칙들이 두 플랫폼에서 서로 다른 이름과 다른 화면에 흩어져 있다. 앞에서 본 CLI 구조가 그 차이의 요약이다. GitLab이 승인 자격자 조회와 승인 철회를 독립 명령으로 두고 있다는 것은, 그 개념이 제품 안에서 그만큼 두껍게 다뤄진다는 뜻이다.

함께 확인할 것이 하나 더 있다. 합치는 방식이다. 커밋을 하나로 뭉치는 스쿼시를 기본으로 할지, 리베이스 후 병합할지, 병합 커밋을 남길지를 팀마다 정해 두는데 이 설정도 플랫폼마다 이름과 위치가 다르다. 옮기는 김에 이것도 문서에 적어 두면 좋다.

정리하면 이렇다. PR과 MR은 같은 물건이다. 다른 것은 이름이 아니라 그 물건에 붙은 규칙이고, 그 규칙은 Git이 아니라 플랫폼이 쥐고 있다.