- Published on
Which Commit Did GitHub Actions Test? PR Head vs Merge SHA
- Authors

- Name
- Mehdi Akiki
Article · Measurement
For a normal pull-request workflow, GitHub Actions may test a merge commit rather than the PR head alone. Record the PR head and the checked-out revision together. A different merge SHA can be expected; a result for a branch revision that has since changed is older evidence.
“The tests passed,” an agent reports. Suppose the linked workflow is green, but the pull request has moved on since it started.
Two new commits have appeared since the run started.
One changes an import path. The other adjusts the parser. The linked run never saw either edit. Its result may be accurate for the code it tested, but it cannot tell the reviewer whether the latest parser works.
The report needs one more sentence: “This result belongs to an earlier commit.”
Say which code passed
When someone says “passed,” we usually assume they mean the code in front of us. That assumption is easy to miss in a busy pull request, especially when an agent keeps editing while checks run.
A useful report names the commit and the checks that finished. It should also say what changed afterward. A screenshot of a green badge leaves the reviewer to find that information themselves.
For example:
Verified source: <full commit SHA>
Workflow run: <permanent run URL>
Checks completed: parser unit tests, preview integration tests
Current PR head: <full commit SHA>
Changes since verified source: parser error handling
Current head verification: pending
The report can describe unfinished work plainly. The earlier tests passed; the current version is still waiting. There is no need to turn that into a claim that the whole task is done.
The difference matters most when the newer edit touches the tested behavior. A parser change needs a new parser result. A spelling correction may need different checks under the repository's policy. Either way, the agent should explain which result applies rather than quietly reusing an old one.
Keep the link to the older run if it helps explain what happened. Just label it as an older result. A failed run can also be useful history when the next commit repairs the failure.
Use a commit link when pointing at source. A branch link can show different code after the next push. If a reviewer opens the handoff a week later, they should still land on the version the test saw. The commit link gives them a fixed starting point for comparing that version with the newer edits.
Record what CI actually checked out
The pull request's latest commit and the commit used by CI are not always the same. For a normal pull_request event, GitHub's default checkout uses a test merge of the branch and its base. That lets the workflow check how the two work together.
GitHub's event documentation describes the SHA and reference used for this event. A workflow can also override checkout, so read its configuration before assuming what it tested.
Inside a CI job after checkout, keep the related fields in one report:
- name: Record verification source
env:
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
EVENT_NAME: ${{ github.event_name }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: |
printf 'Event: %s\nPR head: %s\nEvent SHA: %s\nRun: %s\n' \
"$EVENT_NAME" "$PR_HEAD_SHA" "$GITHUB_SHA" "$RUN_URL"
printf 'Checked-out source: '
git rev-parse HEAD
The values go through environment variables and quoted arguments rather than becoming shell program text. A non-PR event may have no PR head; report that absence instead of inventing one. The actual checkout is still the final git result, since the workflow can override its default source.
Record the pull request's latest commit alongside it when the two differ. That gives a later reviewer enough information to connect the result to the proposed change.
The event matters too. A manually dispatched run can give useful evidence for a commit, but it does not satisfy a pull request's required checks in a branch ruleset. Use the repository's required-check workflow. A merge queue also needs checks triggered by merge_group. GitHub's troubleshooting guide explains both cases.
Consider these constructed labels, not actual Git hashes:
| Moment | PR head | Checked source | Interpretation |
|---|---|---|---|
| Run starts | head-B | merge-M | A merge of head-B and the base can be valid |
| Another push arrives | head-C | merge-M in the earlier run | The result still concerns head-B, not head-C |
Comparing only merge-M with head-B would wrongly suggest the first case tested the wrong change. Comparing the run's recorded PR head with the current head exposes the actual stale-result problem. If checkout used a custom reference, inspect that choice and its parents rather than assuming the example applies.
Repeated pushes can also cancel the earlier run
. Neither cancellation nor eventual success moves its source forward to the newest commit.
A release needs one more connection: the image or bundle being deployed must come from the checked source. Printing a commit in one job doesn't prove that an image downloaded in another job was built from it.
This is worth checking when a workflow downloads an artifact from another run. “Latest successful build” can point to an older commit. The job may succeed while releasing code different from the code the reviewer just approved.
Keep generated files with their run
Suppose the agent also attaches a rendered preview. It looks right, but was it generated before or after the parser edit? Does it belong to the run in the report?
Having the verification run generate and upload the preview makes those questions easier to answer. Link to the run and keep the commit next to the file. The reviewer can then inspect the code, result, and preview together.
For a recorded coding example, save the raw model responses separately from later repairs. Otherwise an editor's correction could be presented as code the model produced. The corrected example may be useful, but readers should know who changed it.
A commit link, a workflow URL, and an uploaded file are often enough for a small review. The important part is keeping their relationship clear.
GitHub's Checks API already ties each check run to a commit SHA. An agent's summary should keep that link intact.
Before handing over the parser change, update the report with its required-check run and the source that run checked out. If another edit arrives afterward, mark that result as older evidence and show what still needs checking.