Why a scheduled merge should pin the commit you approved
Imagine you review a pull request at 5 p.m. and schedule the merge for 11 p.m. At 10:50 someone pushes one more commit to the branch. A naive scheduler merges whatever is on the branch at 11, so code nobody reviewed goes live.
Why branch protection alone may not save you
Some repositories dismiss approvals when new commits arrive, and some do not. Check your branch protection setting that dismisses stale approvals when new commits are pushed. If it is off, or if the person pushing can approve their own work, the merge can still go through.
The fix: merge only if the head is what you reviewed
GitHub's merge API accepts an optional sha value. When it is given, the merge goes ahead only if the pull request's head commit matches it; otherwise the call is refused with a conflict error. A scheduler that records the head commit when you schedule, and passes it when it merges, cannot merge anything else.
What a good scheduler does when the head changed
- It skips the merge instead of merging the new code.
- It tells you why: new commits were pushed after you scheduled.
- It lets you review the new commit and schedule again.
Other checks at merge time
- Required checks and approvals still pass.
- There are no new merge conflicts.
- The base branch is the one you expected.
How Merge Scheduler does it
Merge Scheduler records the head commit when you schedule, re-runs the prechecks right before merging, and passes the commit to GitHub when it merges. If the head changed, the release is skipped and the reason is shown on the release page and in the email.
Related: How to schedule a GitHub pull request merge (4 ways) · Releasing outside business hours: a checklist for small teams