Pull Requests — Creating, Reviewing, and Merging

9 min read

A pull request (PR) is a proposal: "I want to merge my branch into yours — please review." Despite the misleading name, no code is "pulled" — Git itself doesn't have pull requests at all. The concept is GitHub's invention, and it's now the central ritual of every team Git workflow on earth. PRs are where code review happens, where CI runs your tests, and where a junior QA engineer first earns the trust of their team. This lesson walks through creating, reviewing, and merging one end to end.

Why QA engineers care deeply about PRs

PRs are not a developer-only ceremony. As a QA engineer:

  • Your test code goes through PRs. Every new test, every framework change, every fixture update gets reviewed before it lands. Mistakes in test code (false positives, flaky timing, broken selectors) hide real bugs — review catches them.
  • You review developer PRs. Did they include tests for the new behaviour? Are there regression risks they didn't think of? Did they update the affected fixtures? Your review is the QA quality gate before merge.
  • PRs are CI's trigger. Every push to a PR branch fires the CI pipeline: unit tests, integration tests, your e2e suite. The PR shows green checks if everything passes, red Xs if not.

A QA engineer who treats PR review as a chore is leaving their best leverage on the floor.

Creating a pull request

Start from a feature branch you've been working on:

git switch -c feature/search-tests
# ...write tests, commit a few times...
git push -u origin feature/search-tests
remote:
remote: Create a pull request for 'feature/search-tests' on GitHub by visiting:
remote:      https://github.com/acme/webapp-tests/pull/new/feature/search-tests
remote:

Two ways to open the PR:

  1. Click that URL directly from the terminal output. GitHub takes you straight to a pre-filled PR creation page.
  2. Visit the repo on GitHub. A yellow banner says "feature/search-tests had recent pushes — Compare & pull request." Click it.

You're now on the PR creation page. Fill in:

  • Base branch — usually main. The branch you're merging into.
  • Compare branch — your feature/search-tests. The branch you're merging from.
  • Title — short, scannable. "Add 5 search regression tests for empty/special-char/pagination cases."
  • Description — the meat (see template below).
  • Reviewers — at least one teammate. Devs reviewing your test code, QA leads reviewing your test design.
  • Labelstests, qa, regression, etc. Helps triage in busy repos.
  • Linked issuesCloses #142 auto-closes the linked issue when the PR merges.

Click Create pull request.

A PR description template for test code

A weak PR description forces reviewers to read every diff to understand intent. A strong one tells them what to look for in 30 seconds. For a test PR, cover four points:

## What this PR does
Adds 5 new Cypress tests for the search feature covering:
- Empty search input
- Special characters (apostrophes, quotes, emoji)
- Pagination beyond first page
- No-results state
- Search-while-typing debounce
 
## Why
QA-1342: search regression suite was missing edge cases that bit us in
last sprint's hotfix.
 
## How to run locally
npm install
npx cypress run --spec "tests/search/**"
 
## Test data dependencies
Uses the existing `searchFixtures.json` — no new fixtures needed.
The "no-results" test relies on `nonexistent-product-slug-zzz` not
existing in the staging DB; if that ever changes, update the test.

A reviewer reading that knows immediately: what changed, why it matters, how to reproduce, and what could go wrong later. That's the bar.

Reviewing a pull request

GitHub's review interface has three tabs:

  • Conversation — the running thread of comments, status checks, and approval state.
  • Commits — the individual commits that make up the PR.
  • Files changed — the unified diff. This is where review happens.

In Files changed:

  • Hover over any line and click the blue + icon to leave a comment on that line.
  • Use the Suggest option to propose a literal code edit the author can accept with one click.
  • Click Review changes at the top. Pick Approve, Request changes, or Comment.

What QA engineers should look for

Reviewing a developer's PR with a QA hat on — five questions worth asking on every PR:

  1. Did they add tests? A feature without tests is a regression waiting to happen. If there are no test changes, ask why.
  2. Do existing tests still pass? Look at the CI status. A red e2e suite is your problem too.
  3. Are edge cases covered? Empty inputs, unicode, max lengths, slow networks, error responses. The test design techniques cheat sheet is a great prompt list.
  4. Is test data handled correctly? New feature using a fixture? Did they update the fixture? Will the test work against staging and localhost?
  5. Could this break a flaky test? Changing a selector, an animation, or a network call can silently destabilise existing tests. Flag it before merge, not after.

Leave the comment, hit Request changes if it must change, Comment if it's a question, Approve if you're satisfied. Don't approve out of social pressure — that defeats the entire ritual.

Addressing review feedback

The author makes more commits on the same branch and pushes:

# ...edit the test file...
git add tests/search.spec.js
git commit -m "Address review: switch to data-testid selector"
git push

The new commit appears in the PR automatically — no second PR, no re-creation. CI re-runs. Reviewers re-look. This back-and-forth continues until everyone's happy.

Merging the PR

Once approved and CI is green, click Merge pull request. GitHub offers three merge strategies:

  • Create a merge commit — preserves every commit on the branch and adds a merge commit. Full history, slightly noisy.
  • Squash and merge — combines all commits on the branch into a single commit on main. Tidy history; loses fine-grained commit messages. Most popular for teams that prize a linear main.
  • Rebase and merge — replays each commit onto main without a merge commit. Linear history, full granularity. Demands clean commits to be readable.

Most modern teams default to Squash and merge for feature branches because the individual commits inside the branch ("WIP", "fix typo", "fix flake") add noise to main.

After merging, delete the branch (GitHub offers a one-click button). Locally, follow up:

git switch main
git pull                                    # bring the merge down
git branch -d feature/search-tests          # delete the now-merged local branch

The full PR lifecycle

Step 1 of 7

Branch + commit + push

git switch -c feature/foo; commit your work; git push -u origin feature/foo.

A complete QA scenario

You wrote 5 search tests, pushed the branch, opened a PR titled "Add 5 search regression tests for empty/special-char/pagination cases." CI runs — your suite passes, but the lint job fails because Prettier wasn't happy. You fix it locally, commit, push. CI now green. Your reviewer leaves two comments: one suggesting a data-testid instead of a CSS class for stability, another asking whether the debounce test would work on a slow runner. You change the selector, add a longer wait for the debounce test, push again. Reviewer approves. You squash-and-merge, delete the branch, and pull main locally. The PR is closed; the tests are live.

⚠️ Common mistakes

  • Approving without reading the diff. A "👍 LGTM" without engagement is worse than no review — it adds false confidence. If you don't have time, say so; don't fake it.
  • Letting PRs sit for days. A PR rotting for a week is a merge-conflict factory by Monday. Aim to review within a workday; aim to address feedback within an hour or two of receiving it. Short feedback loops keep teams shipping.
  • Reusing one PR branch for unrelated work. Once a PR is open, that branch is "the search tests PR." Don't tack on the timeout config fix you happened to also do — open a separate PR. Reviewers can't review two unrelated changes in one place.

🎯 Practice task

Go through a full PR cycle on a real repo. 30 minutes.

  1. In a repo where you have push access (your own GitHub repo, or your qa-sandbox), branch off main: git switch -c feature/sample-pr.
  2. Add a one-line change — a new line in README.md or a new placeholder test file. Commit with a clear message. git push -u origin feature/sample-pr.
  3. On GitHub, open the PR. Write a description with the four sections (What / Why / How to run / Test data dependencies). Even for a tiny change, follow the template.
  4. Review your own PR (Files changed). Leave one self-comment on a specific line. (Yes, you can comment on your own PR — useful for explaining tradeoffs to future reviewers.)
  5. Add a second commit responding to the comment. Push. Watch the PR auto-update.
  6. Merge with each of the three strategies on three different practice branches: Merge commit, Squash and merge, Rebase and merge. Run git log --oneline --graph --all after each. Compare the shapes of main's history.
  7. Stretch: find an open PR on a public repo (e.g., cypress-io/cypress) and read it as if you were the reviewer. Could you tell what changed and why in 60 seconds? What's missing? What's well done?

The next lesson takes the PR concept across repository boundaries — into the open-source world, where you don't have write access at all.

// tip to track lessons you complete and pick up where you left off across devices.