Skip to content
DevOps devops git 5 min read

Pull Requests & Code Review

A pull request (PR) is a proposal to merge the changes from one branch into another. You push a branch, open a PR, and your teammates review the code before it becomes part of the main project. On GitLab the same idea is called a merge request (MR) — the name is different but the workflow is identical. PRs matter because they turn merging into a conversation: nothing reaches your main branch until a human has looked at it and your automated tests have passed. This is the single most important habit for working safely in a team.

Why code review matters

Code review is the practice of having another engineer read your changes before they merge. It is not about catching you doing something wrong — it is a shared safety net. A good review catches bugs early (when they are cheap to fix), spreads knowledge so you are not the only person who understands a feature, and keeps the codebase consistent. Even solo developers benefit: opening a PR forces you to re-read your own work with fresh eyes.

The goal of review is the change, not the person. Comment on the code (“this query runs inside a loop”), never on the author (“you always do this”). Tone is part of the job.

The pull request workflow

The core loop looks the same on GitHub, GitLab, and Bitbucket. You build your work on a feature branch (a short-lived branch separate from main), push it, and open a PR against main.

# Start from an up-to-date main
git switch main
git pull origin main

# Create a feature branch
git switch -c feature/add-login-rate-limit

# ...make your changes, then stage and commit them
git add .
git commit -m "Add rate limiting to login endpoint"

# Push the branch and set its upstream
git push -u origin feature/add-login-rate-limit

Output:

Enumerating objects: 7, done.
Counting objects: 100% (7/7), done.
Writing objects: 100% (4/4), 612 bytes | 612.00 KiB/s, done.
remote: Create a pull request for 'feature/add-login-rate-limit' on GitHub by visiting:
remote:   https://github.com/acme/api/pull/new/feature/add-login-rate-limit
To github.com:acme/api.git
 * [new branch]      feature/add-login-rate-limit -> feature/add-login-rate-limit

The remote prints a link — open it to create the PR. If you have the GitHub CLI (gh, a command-line tool for GitHub) installed, you can open the PR without leaving the terminal:

sudo apt update
sudo apt install gh        # Ubuntu 22.04 / 24.04
gh auth login              # one-time browser login
gh pr create --base main --title "Add login rate limit" --body "Limits to 5 attempts/min"

From here the cycle is: reviewers comment, you push more commits to the same branch (the PR updates automatically), and once it is approved and checks pass, you merge.

Draft pull requests

A draft PR is a pull request marked “not ready to merge yet.” You open it early — even before the work is finished — so teammates can see your direction, CI can start running, and you can ask questions in context. Draft PRs cannot be merged until you mark them ready, which prevents accidents.

# Open as a draft from the CLI
gh pr create --draft --title "WIP: payment retry logic"

# Flip it to ready when you're done
gh pr ready

When to use a draft: large or risky changes, work you want early feedback on, or anything you expect to take several days. When not to: small, obvious fixes — just open a normal PR.

Required checks and CI gates

A required check is an automated test that must pass before the PR can be merged. These run in your CI (Continuous Integration — the system that automatically builds and tests every change). A typical setup blocks merging until linting, unit tests, and a build all go green.

You enforce this through branch protection rules. On GitHub: Settings → Branches → Add rule, then enable “Require status checks to pass” and “Require a pull request before merging.” Once set, the merge button is disabled until every required check passes and the required number of approvals is reached.

# .github/workflows/ci.yml — runs automatically on every PR
name: CI
on: pull_request
jobs:
  test:
    runs-on: ubuntu-24.04
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npm run lint
      - run: npm test

Never disable required checks to “just get it merged.” A red check is the system doing its job. If a check is flaky, fix the check — do not route around it.

Merge strategies

When a PR is approved, you choose how its commits land on main. The three options behave very differently.

StrategyWhat it doesResulting historyWhen to use
Merge commitKeeps all branch commits and adds one merge commitFull, branching historyYou want to preserve the exact commit-by-commit work
Squash and mergeCombines all branch commits into one new commitClean, one commit per PRMost teams’ default; tidy main history
Rebase and mergeReplays each branch commit onto main, no merge commitLinear history, all commits keptYou want every commit but a straight line

For most teams, squash and merge is the best default: each PR becomes a single, well-described commit on main, which makes the history easy to read and easy to revert. Use rebase when individual commits are meaningful (e.g. a carefully staged refactor). Use a plain merge commit when you need to record that a true branch happened.

# Squash-merge from the CLI once approved and green
gh pr merge --squash --delete-branch

Output:

✓ Squashed and merged pull request #142 (Add login rate limit)
✓ Deleted local and remote branch feature/add-login-rate-limit

Best Practices

  • Keep PRs small. A PR under ~400 changed lines gets reviewed faster and more thoroughly than a giant one. Split big work into stacked PRs.
  • Write a clear description. Say what changed, why, and how to test it. Link the issue it closes.
  • Review your own PR first. Read the diff before requesting reviewers — you will catch debug prints and stray files.
  • Respond to every comment. Resolve it, fix it, or explain why not. Silence stalls reviews.
  • Let CI gate merges. Require checks and at least one approval through branch protection, not goodwill.
  • Delete the branch after merge. Keep the branch list clean; the PR preserves the history.
  • Don’t force-push to a shared PR branch once review has started without telling reviewers — it scrambles their place in the diff.
Last updated June 15, 2026
Was this helpful?