Blog

Pull request vs merge request: GitHub and GitLab compared

Pull request vs merge request: the same thing under two names. See how GitHub and GitLab differ on drafts, approvals, merge methods and queues.

Alex Mercer

A pull request and a merge request are the same thing: a request to merge one branch into another, with the diff, the review and the CI results on one page. GitHub and Bitbucket call it a pull request (PR), and GitLab calls it a merge request (MR).

The basic workflow matches too. You push a branch, open the request, get it reviewed and merge it. The differences are in what each platform builds around that, such as drafts, approval rules, merge methods and merge queues. If you're new to the idea, start with what a pull request is and how it moves from draft to merge.

Why one is a pull and the other a merge

GitLab explained the split on the GitLab Flow page of its archived documentation for GitLab 15.11, from April 2023: "Tools such as GitHub and Bitbucket choose the name 'pull request', because the first manual action is to pull the feature branch. Tools such as GitLab and others choose the name 'merge request', because the final action is to merge the feature branch."

The pull wording is older than both platforms. Git has a git request-pull command that generates "a request asking your upstream project to pull changes into their tree," and Linux kernel maintainers still send pull requests to each other by email. GitHub's own glossary meets GitLab halfway: it says a pull request "can be thought of as a request to merge."

Other tools use other names for the same unit of review:

Pull request vs merge request at a glance


GitHub pull request

GitLab merge request

Short form

PR

MR

Branch names

Head (or compare) branch into base branch

Source branch into target branch

Drafts

A draft state; Ready for review or gh pr ready

Draft: title prefix, Mark as draft, /draft and /ready

Review decisions

Comment, Approve or Request changes

Approve; reviewers can also request changes

Required approvals

Branch protection rules or rulesets

Optional on Free; approval rules on Premium and Ultimate

Code owners

CODEOWNERS requests reviews; approval can be required

Code Owners on Premium and Ultimate

Approvals after new commits

Kept, unless the branch dismisses stale approvals

Removed by default (Premium and Ultimate setting)

Merge methods

Merge commit, squash and merge, rebase and merge

Merge commit, merge commit with semi-linear history, fast-forward; squash is a separate setting

Merge once checks pass

Auto-merge

Set to auto-merge

Merging in order

Merge queue

Merge trains (Premium and Ultimate)

CLI

gh pr create

glab mr create

If you're moving a team from one platform to the other, those rows are the settings to recreate.

Drafts

Both platforms let you open a request before it's ready, and neither will merge a draft.

On GitHub, a draft is a separate state. You pick Create draft pull request when you open it, or run gh pr create --draft. GitHub doesn't automatically request reviews from code owners on a draft. When the work is ready, click Ready for review or run gh pr ready, which requests reviews from any code owners. You can convert a pull request back to a draft at any time.

On GitLab, a merge request becomes a draft in several ways. You can add [Draft], Draft: or (Draft) to the start of the title, select Mark as draft, comment with the /draft quick action, or push a commit whose message starts with draft: or fixup!. A draft merge request can't merge until you remove the draft flag, even if it meets every other merge requirement. To clear it, select Mark as ready, remove the title prefix, or comment /ready, and GitLab notifies the merge request's participants and watchers.

Approvals and approval rules

Both platforms record approvals. They differ in what each plan includes and in a few defaults.

GitHub

A review on GitHub ends with Comment, Approve or Request changes. Authors can't approve their own pull requests, and Request changes doesn't block anything on its own unless a ruleset or branch protection rule requires a pull request before merging.

To require approvals, protect the branch with a branch protection rule or a ruleset. You can require a number of approving reviews, require review from code owners, dismiss approvals when new commits change the diff, and require the latest push to be approved by someone other than the person who pushed it. Protected branches are available in public repositories on GitHub Free, and in public and private repositories on GitHub Pro, Team, Enterprise Cloud and Enterprise Server. For the reviewer's side, see how to review a pull request on GitHub.

GitLab

On GitLab, eligible approvers select Approve in the merge request widget or comment /approve. On GitLab Free, approvals are optional and don't prevent merging. Premium and Ultimate add approval rules, which set how many approvals a merge request needs and from whom, and Code Owners, which can require approval from the owners in a CODEOWNERS file before a merge request merges into a protected branch. Depending on the project's configuration, a reviewer can also block a merge request by selecting Request changes.

The approval settings on Premium and Ultimate have defaults to check. Authors can't approve their own merge requests, and approvals are removed when new commits are added. People who add commits to a merge request can still approve it unless you turn on Prevent approvals by users who add commits.

GitLab also gives every merge request two roles. The assignee owns the merge request and is responsible for its progress, and is usually the author. Reviewers review the changes and give feedback.

The CODEOWNERS guide covers how to set up code owners, and what LGTM means covers what an approval should stand for. Whatever the platform calls it, an approval is only as good as the review behind it. An AI reviewer such as cubic reviews pull requests on GitHub, finds bugs and learns your team's rules, so AI code review gives human approvers a first pass to build on.

Merge methods

GitHub has three merge methods, and each repository chooses which ones to allow:

  • Create a merge commit keeps every commit and adds a merge commit (--no-ff).

  • Squash and merge combines the pull request into one commit.

  • Rebase and merge adds each commit onto the base branch without a merge commit, and always creates new commit SHAs.

GitLab sets one merge method per project and treats squashing as a separate setting:

  • Merge commit creates a merge commit for every merge, the same as git merge --no-ff.

  • Merge commit with semi-linear history also creates a merge commit, but only merges when a fast-forward merge is possible.

  • Fast-forward merge keeps a linear history without merge commits.

When a fast-forward merge isn't possible, GitLab gives the user the option to rebase. The squash setting has four options: Do not allow, Allow (off by default, user can change it), Encourage (on by default, user can change it) and Require.

Bitbucket Cloud offers merge commit, fast forward, squash, squash with fast-forward only, and two rebase strategies: rebase then merge, and rebase then fast-forward.

For a linear history, the closest matches are GitHub's rebase and merge and GitLab's fast-forward merge, and squash exists on all three platforms.

Merge queues, merge trains and auto-merge

When many requests merge into the same branch, two of them can each pass CI and still break the branch together. GitLab's merge trains docs describe the problem this way: "Two merge requests can each pass their own pipeline, but their combined changes can still conflict." Both platforms have a fix:

  • GitHub's merge queue automates merges into a busy branch and makes sure incompatible changes never break it. It gives the same protection as requiring branches to be up to date before merging, without making authors update their branch and wait for checks. It's available in public repositories owned by organizations and in private organization repositories on GitHub Enterprise Cloud. On a branch that requires a merge queue, gh pr merge adds the pull request to the queue if required checks have passed.

  • GitLab's merge trains test each merge request against the combined changes of every merge request ahead of it in the queue. Selecting Merge or Set to auto-merge on a merge request starts a train, or adds the merge request to the train already running. Merge trains are available on GitLab Premium and Ultimate.

Both platforms can also merge for you once everything passes. GitHub's auto-merge merges a pull request after all required reviews and status checks pass, once the repository enables it. GitLab's Set to auto-merge merges a merge request when all required checks complete successfully. If you script it with push options, note that GitLab deprecated merge_request.merge_when_pipeline_succeeds in GitLab 17.11 in favor of merge_request.auto_merge.

Opening one from the command line

GitHub has gh and GitLab has glab, and GitLab can also open a merge request as part of a git push:

# GitHub: open a draft pull request from the current branch
gh pr create --base main --fill --draft

# GitLab: open a draft merge request from the current branch
glab mr create --target-branch main --fill --draft

# GitLab: create the merge request while you push
git push -o merge_request.create -o merge_request.target=main -o

# GitHub: open a draft pull request from the current branch
gh pr create --base main --fill --draft

# GitLab: open a draft merge request from the current branch
glab mr create --target-branch main --fill --draft

# GitLab: create the merge request while you push
git push -o merge_request.create -o merge_request.target=main -o

# GitHub: open a draft pull request from the current branch
gh pr create --base main --fill --draft

# GitLab: open a draft merge request from the current branch
glab mr create --target-branch main --fill --draft

# GitLab: create the merge request while you push
git push -o merge_request.create -o merge_request.target=main -o

--fill uses your commit messages for the title and description on both CLIs, and glab mr create --fill also pushes the branch. GitLab's push options need Git 2.10 or later, and the short -o form needs Git 2.18 or later.

Related terms

  • Base branch, target branch, destination branch: where the changes go, on GitHub, GitLab and Bitbucket.

  • Head (or compare) branch, source branch: where the changes come from.

  • Assignee and reviewer: on GitLab, the assignee owns the merge request and reviewers give feedback.

  • Quick actions: GitLab commands you type in a comment, such as /approve, /draft and /ready.

  • Merge queue and merge train: GitHub's and GitLab's names for testing and merging requests in order.

  • Merged results pipeline: a GitLab pipeline that tests one merge request's changes combined with the target branch, without accounting for other merge requests merging at the same time.

FAQ

Are PR and MR the same?

Yes. A pull request (PR) on GitHub or Bitbucket and a merge request (MR) on GitLab are both requests to merge one branch into another after review. The platforms differ in the features around them, such as approval rules, merge methods and merge trains.

Why is it called a pull request instead of a merge request?

GitLab's explanation, in its archived docs for GitLab 15.11, is that GitHub and Bitbucket named the feature after the first manual action, pulling the feature branch, while GitLab named it after the final action, merging it. The pull wording also matches git's own git request-pull command, which asks an upstream project to pull changes into their tree.

Is git pull just fetch and merge?

Close, but not by default. In the current git documentation, git pull runs git fetch and then integrates the fetched branch. The default is --ff-only, which fails if your local branch has diverged, while git pull --no-rebase runs git merge and git pull --rebase runs git rebase. It's a local git command, separate from a pull request on GitHub.

What happens when you merge a pull request?

The base branch gets the changes as a merge commit, a single squashed commit or rebased commits, depending on the method. On GitHub, an issue linked with a closing keyword closes when the base is the default branch, and you can delete the head branch. On GitLab, the merge request merges with the project's merge method, and you can delete the source branch as part of the merge.

Table of contents