Branching and Pull Requests
A pull request (PR) is a proposal to merge the commits of one branch into another, usually into main. Instead of pushing a change straight into the shared code, the developer opens a pull request: colleagues review the diff, automated tests run against it as checks, and the branch is merged only when both are satisfied. GitLab calls it a merge request.
For example, a developer commits a discount rule and its unit tests on the branch feature/CHK-231-bulk-discount and opens a pull request into main. Within minutes its page shows the changed lines, the reviewers and the checks — build, lint, unit tests, API smoke tests — each passed or failed.
Why it matters
Branching decides when a change meets the rest of the team’s work, and so which combination of changes a tester is actually testing. Branches that live for weeks collect conflicts that surface only at merge time, often just before a release.
A pull request is the last point at which a change is small, isolated and cheap to fix. Reading it is static testing, and its checks run static analysis and automated regression tests on every push, so a tester who takes part helps keep defects out of main.
Branching strategies: trunk-based development and feature branches
A branching strategy is a team’s agreement on which branches exist, how long they live and how work reaches the main branch, also called the trunk or mainline.
In trunk-based development everyone integrates into main at least daily, directly or through short-lived branches merged within about a day. Unfinished features are merged but hidden behind feature flags, switches that keep new code off until it is ready. This is the model behind continuous integration from an earlier lesson: changes stay small and main stays releasable.
With feature branches, each story or fix gets its own branch from main and returns through a pull request. The shorter a branch lives, the closer the team stays to continuous integration, which expects work to reach main at least daily; branches open for weeks drift away from main, and the merge becomes a risky event where several untested changes meet for the first time.
- Release branches such as
release/2.4stabilise a version; a fix made there must also reachmain, or the defect returns in the next release. - Heavier models such as GitFlow add a long-lived
developbranch plus hotfix branches. In any model, ask which branch and which commit a build came from.
Pull requests and code review
A pull request shows, file by file, the diff of what the source branch would bring into the target branch, and collects everything around it: description, linked ticket, commits, reviewers’ comments on individual lines and check results. A draft pull request is not ready for review yet, but its checks can already run.
Each reviewer can comment, approve or request changes; the author answers by pushing new commits to the same branch, and the checks run again. Once the required approvals and checks are in place, the branch is merged as a merge commit, as one squashed commit (all its commits combined into one) or by a rebase (its commits replayed on top of the target branch), depending on the repository’s settings.
In ISTQB terms, reviewing a pull request is static testing, usually an informal review. Its known weakness is the rubber stamp: an approval given without reading. Small pull requests and a description, usually written in Markdown, that answers four questions make a real review possible:
- What changed and why, with the ticket link.
- Which tests were added, changed or removed, and what was checked by hand.
- Risks: migrations, configuration, feature flags, shared code.
- How to try it: test data, flags, a preview environment.
Tests as pull-request checks
Each push to a pull request can trigger the CI pipeline, and each job reports a status check: pending, passed or failed. Repository rules — branch protection on GitHub, merge checks on GitLab and Bitbucket — can make checks and approvals required, which turns them into a quality gate on the way into main.
- 1Branch from
mainOne short-lived branch per story or fixfeature/CHK-231-bulk-discount - 2Commit and pushThe change together with its tests
- 3Open a pull requestDiff against
main, description, linked ticket, reviewers - 4Required checksBuild, lint, unit and API smoke tests on the change merged with
mainat the same time- 5Code reviewReviewers, the tester among them, comment, approve or request changes
Repeats: A check fails or changes are requested: push a fix to the same branch, and the checks run again
Gate: all required checks passed and approvals given
- 6Merge into
mainMerge commit, squash or rebase, per repository setting - 7Test on
mainOn a build that contains the merged change; record its commit
Illustrative: which checks are required, and how many approvals, is set per repository.
Pull-request checks should finish in minutes: build, lint, unit and component tests, and a few API or end-to-end smoke tests. Full regression usually runs after the merge or on a schedule; a later lesson covers that split.
Two details matter to a tester. The checks often run on the pull request merged with the current target branch (a GitHub Actions pull_request run checks out a temporary merge commit); if main moves on, the result can be stale, which is why some teams use a merge queue, which tests each pull request together with the ones queued ahead of it before merging. And a green check proves only what the tests assert: a skipped test, or an expected value edited to match the new output, stays green.
The first run of the discount pull request: one unit test failed, so the merge is blocked.
Pull request #482 feature/CHK-231-bulk-discount -> main
Head commit 9f3c2e1, first run
Required checks
passed build 1m 12s
passed lint and type check 48s
failed unit tests 211 passed, 1 failed
passed API smoke tests 18 passed
Reviews 0 of 2 required approvals
Merging is blocked: 1 required check failed, 2 approvals missing.Worked example: a green pull request to review
Story CHK-231: "Orders with a subtotal of 500.00 SAR or more get a 10% discount on the subtotal." After a fix, all four required checks on pull request #482 are green, one developer has approved, and the tester is the second reviewer.
Pull request #482 feature/CHK-231-bulk-discount -> main
Required checks: 4 of 4 passed Approvals: 1 of 2
Description
What: 10% discount when the subtotal is above 500.00 SAR.
Tests: unit tests for 600.00 and 400.00. API tests unchanged.
Risk: none.
src/pricing/discount.ts
+ if (subtotal > 500) {
+ return round2(subtotal * 0.9);
+ }
tests/api/checkout.api.test.ts
- expect(body.total).toBe(540.00);
+ expect(body.total).toBe(486.00);The tester’s review comments
The tester reads the description, the tests and the diff, comments on the relevant lines and chooses "request changes":
- On
discount.ts: the story says "500.00 or more", but the description says "above" and the code sayssubtotal > 500, so an order of exactly 500.00 gets no discount. A defect found by reading. - On the unit tests: 600.00 and 400.00 pass whether the operator is
>or>=. Ask for the boundary values 499.99 (no discount) and 500.00 (450.00 after the discount), as in the lesson on boundary value analysis. - On the API test: the expected total changed from 540.00 to 486.00, but the description says the API tests are unchanged. The value fits the new rule (540.00 minus 10%), but every changed expected value must be explained.
- On "Risk: none": pricing affects totals, invoices and refunds. Ask whether the discount applies before or after the delivery fee and VAT, and how 10% of 500.05 is rounded.
- After the merge, test the story on a
mainbuild that contains the merged change, and record its commit.
Try it: Boundary Value Analysis Try it: Regression Scenario Generator
Common mistakes
- Treating a green pull request as a tested one: a skipped test or an edited expected value stays green.
- Approving a pull request without reading the diff and the tests, so the review becomes a rubber stamp.
- Testing a build without knowing which branch and commit it came from, then reporting a defect already fixed on
main. - Re-running a failed check until it passes instead of finding out why; a flaky result can come from the test, the environment or a real timing defect in the product.
- Keeping feature branches open for weeks, so the merge combines several untested changes just before a release.
The QA perspective
Ask to be added as a reviewer on the pull requests for the stories you will test. Read the description, then the tests, then the code: is every acceptance criterion covered, are boundaries and negative cases there, was any test skipped, deleted or changed, does the description match the diff? Request changes only for real problems, so your reviews keep their weight.
Agree with the team which tests are required checks and who acts when one fails. For a defect found after a merge, record the branch, commit and pull request number and link the defect to the pull request; a defect found in review is usually a review comment resolved before the merge.
Practice exercise
Review a pull request and decide whether it can merge
The required checks are the build, unit tests and API smoke tests. Story CHK-245 says: "Users can cancel an order while its status is Placed or Paid. Cancelling a Paid order refunds the full amount." The pull request below passed all its required checks.
Write your review comments, decide whether to approve, and say what you will test after the merge.
Pull request #517 fix/CHK-245-cancel-order -> main
Required checks: 3 of 3 passed
Description
What: allow cancelling Placed and Paid orders; Paid orders are refunded.
Tests: unit test for cancelling a Placed order.
src/orders/cancel.ts
- if (order.status !== 'Placed') throw new CancelNotAllowed();
+ if (!['Placed', 'Paid', 'Shipped'].includes(order.status)) {
+ throw new CancelNotAllowed();
+ }
+ if (order.status === 'Paid') refund(order, order.total - order.deliveryFee);
tests/orders/cancel.test.ts
+ it('cancels a Placed order', ...);
- it('rejects cancelling a Shipped order', ...);- Compare the description with the story and the diff.
- List what the story requires that the tests do not cover.
- Check every changed or removed test.
- Decide, write your comments and note what you will test on
main.
Show the model answer
Request changes: the checks are green only because the tests miss what changed. The description matches the story, not the diff: it mentions neither Shipped, nor the deleted test, nor the delivery fee kept out of the refund.
Defect 1: Shipped was added to the allowed statuses, which the story does not allow, and the test rejects cancelling a Shipped order was deleted in the same pull request, so the checks still pass. Because the refund runs only for Paid, a cancelled Shipped order would not be refunded at all. Ask for Shipped to be removed and the test restored.
Defect 2: the refund is order.total - order.deliveryFee, not the full amount. Ask the product owner whether the delivery fee is refundable, then fix the code or the story.
Missing tests: cancelling a Paid order and the refunded amount; rejecting Shipped and any later status (only Placed and Paid may move to Cancelled); cancelling an order that is already cancelled.
After the merge, on a main build that contains the change: cancel a Placed and a Paid order, check the refund, try a Shipped order, record the commit and PR #517.
Frequently asked questions
Is a pull request a Git feature?
No. Git provides branches, commits and merges; the pull request is a feature of hosting platforms built on Git, such as GitHub, GitLab (where it is called a merge request), Bitbucket and Azure DevOps. Git itself has a git request-pull command, but it only prints a text request that summarises the changes and says where to pull them from, usually sent by e-mail.
Should a tester approve pull requests?
If the team adds testers as reviewers, yes, for what you can judge: how well the tests cover the acceptance criteria, the quality of the tests, testability and risk. You do not have to judge every line of production code. Say in your review what you checked, so that your approval is not read as more than it is.
Trunk-based development or feature branches: which is better for testing?
Both work when changes are small, merged within about a day, and every merge is tested automatically. Trunk-based development relies on strong automated checks and feature flags, so testers also test features with the flag on and off. Long-lived branches are the risky case in either model, because integration and its testing happen late.
References
- About pull requestsWhat a pull request is: a proposal to merge changes from one branch into another, with a place to discuss, review and run checks before the merge.
- Pro Git, 2nd Edition (Scott Chacon and Ben Straub)The Pro Git book, free to read online: Git basics, branching and merging, distributed workflows and how Git stores its data.
- Continuous Integration (Martin Fowler)The widely referenced description of continuous integration: integrate often, keep the build self-testing and fast, and fix a broken build immediately.
- Code Review Developer GuideGoogle's published code review practices: what reviewers look for, the standard for approving a change and how to write review comments.
Practise with Mutqan tools
Compare two texts line by line or word by word and highlight differences.
Perform full boundary value analysis (2-value and 3-value BVA) with equivalence classes and expected results.
Generate regression scenarios from a change description and a list of affected and related modules.
Normalise Markdown formatting (headings, lists, tables, emphasis) and preview the rendered result.
Go deeper
- CI/CD TestingQuality gates: criteria that can stop a change
- Software Review TypesInformal review
- Static TestingStatic testing in the CI/CD pipeline
- Flaky TestsWhat makes UI tests flaky — timing, shared state, data, environment, third parties — how to diagnose them, and a sane retry and quarantine policy.
Your progress on this topic
Not started
Mark the topic complete when you have studied it and done the exercise.
Sign in to track your progress
Mark topics complete, continue where you left off and unlock specialisation exams.