Verdict
Yes
Yes, run the full test suite again on every push to main and deploy only a commit that passed there, because the pull request build tested your branch merged with an older main.
Why
- Blast radiususers
- Change frequencyconstantly
- Detectabilitysame-day
- Reversibilitywith-effort
- Test costtrivial
Yes, run the tests again on main after every merge; rule R11 gives Test. Blast radius is users, because main deploys to customers on merge, and Reversibility is with-effort, because a revert leaves behind the records the broken version wrote. Change frequency is constantly, because a team of five merges several pull requests a day. Detectability is same-day, because the next pull request build fails on a test its author never touched. Test cost is trivial: the suite exists, and a push trigger on main is one line of config.
| When | Decision | Why |
|---|---|---|
| A merge queue, or GitHub's rule that branches must be up to date before merging, makes CI test the exact commit that lands on main | Do not run the same tests again after the merge; the run before the merge tested that commit | Detectability moves to immediately and Reversibility to trivial, because a failing combination blocks the merge and nothing lands |
| The merged code calculates what customers pay at checkout | Test mandatory: make the main run a required gate for the deploy job, cover every charge path and boundary amount, and have a second person review those tests | Blast radius rises to money and Reversibility to costly, because wrong charges need refunds |
| The full suite runs on real phones for three hours, and some runs fail at random | Test minimally: after each merge run one smoke test of the main path; run the device suite on each release candidate | Test cost rises to heavy, because each extra run takes device hours and a person to sort real failures from random ones |
| A staff-only admin tool gets a few pull requests a year, merged one at a time | Test minimally: after each merge run one smoke test of the main path | Blast radius falls to internal and Change frequency to rarely, because main seldom moves under an open pull request |
| Main deploys nowhere on merge, and customers get a weekly release built from a tag | Test: run the suite on every push to main, so a broken combination is found before the release | Blast radius falls to internal and Reversibility to trivial, but Change frequency stays constantly, because main still takes several merges a day |
What breaks if you don't test
On GitHub Actions a pull_request build checks out refs/pull/<number>/merge, your branch merged with main as it was when the build started. GitHub reruns that build when the branch gets a new commit, not when main moves. If a teammate merges in between, Git combines both changes without a conflict while the code breaks: one pull request makes a field optional, the other reads that field without a check. Main now holds a commit that no build ran, and deploy on merge sends it to customers. Someone finds the break when the next pull request build fails on a test its author did not touch, often the following morning.
What you lose if you over-test
Assume a 12-minute suite and 10 merges a day: the run on main adds 120 runner minutes a day. Flaky tests cost more on main, because a red main that tested nothing new teaches the team to ignore red. With a merge queue in place, the run on main repeats a result the queue already produced for the same commit.
How to test
Run one test job on two triggers, as the GitHub Actions event reference describes:
pull_request, so each branch gets feedback before review.pushto main, so the commit that landed gets its own run.- Make the deploy job depend on the run on main.
- Alert the team when the run on main fails, and revert the merge before you debug it.
When the answer changes
- A merge queue makes CI test the exact commit that lands.
- The merged code charges customers.
- The full suite runs for hours on real devices.
Real incident + Code example
The sort order that two green builds broke
On a Node.js marketplace API I worked on, two pull requests passed CI on the same afternoon. The first changed searchListings() to sort by relevance. The second, opened a day earlier, added a "newest first" endpoint that called searchListings(), with a test that asserted date order; its build had run against the older main. Both merged, main deployed, and the endpoint returned listings in relevance order all evening. The next morning a colleague's pull request failed on the date-order test, and she spent an hour on a test she had never seen. Since then the workflow looks like this:
on:
pull_request:
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm test
deploy:
if: github.event_name == 'push'
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: ./scripts/deploy.sh
Sources
- stackoverflow.com/q/61937134
- docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#pull_request
- docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/about-protected-branches#require-status-checks-before-merging
Related questions
FAQ
- If I test a pull request build, do I need to run the same tests after merging?
Yes, run the same tests after merging unless CI tested the exact commit that lands. A pull request build tests your branch merged with main at the time of the build, and pull requests merged after that change what lands.
- Does GitHub Actions test the merge commit of a pull request?
Yes, a
pull_requestworkflow checks out a merge of the branch into the base branch at the time of the run. A later push to the base branch does not start a new run.- Does a merge queue replace the test run on main?
Yes, a merge queue tests each pull request merged with the latest main and the pull requests ahead of it, so the commit that lands has passed. On GitHub Actions the workflow needs the
merge_grouptrigger, as the merge queue guide states.