jenkinsci / jenkinsci/github-branch-source-plugin
Merge-strategy PR builds fail with "not something we can merge" after PR base branch is retargeted (stale merge_commit_sha trusted)
- Dominant language
- Java
- Stars
- 217
- Forks
- 398
- Avg merge
- 30m
- Merged PRs (30d)
- 1
Description
*Transparency: this issue was investigated and drafted with AI assistance
(Claude). All evidence was verified against a production Jenkins instance,
the GitHub REST API, and the plugin source on master*
## Environment
Jenkins 2.568, github-branch-source; the affected logic is unchanged on
current master (`GitHubSCMSource#createPullRequestSCMRevision`).
## Symptom
After changing a PR's base branch (e.g. develop → staging), the next
event-triggered build fails deterministically in checkout:
```
Merging remotes/origin/staging commit into PR head
stderr: merge: - not something we can merge
ERROR: Maximum checkout retry attempts reached, aborting
```
The fetch refspec already uses the NEW base ref, but the merge target hash
still belongs to the OLD base branch — unreachable via that refspec.
## Root cause
`createPullRequestSCMRevision()` prefers GitHub's cached `merge_commit_sha`
when `mergeable == true` and derives baseHash from its parents. GitHub
recomputes mergeability asynchronously after a retarget (documented API
behavior), so a webhook-triggered fetch arriving seconds after
`pull_request.edited` (with `changes.base`) receives the stale pre-retarget
test merge. Observed: `base_ref_changed` at 12:06:28Z; build at 12:06:46Z used
the identical `merge_commit_sha` as the last pre-retarget build and labeled
the old base branch's tip as `remotes/origin/`. The existing
fallback (`getRef("heads/" + pr.getBase().getRef())`) resolves correctly but
is only reached when the merge hash is absent or invalid.
## Proposed fix (for discussion)
a) Before trusting the merge-commit parents, verify the derived baseHash is
reachable from `heads/` (one compare API call); fall back to
the existing `getRef()` path otherwise. Costs one extra API call per
merge-PR resolution.
b) Alternatively, treat stale-looking mergeability data like
`mergeable == null` when the head's target has changed since the last
observed revision.
Happy to contribute a PR with test coverage once maintainers indicate a
preferred direction.
## Related (not duplicates)
#1191 (build merge_commit_sha directly), #1225 (merge-ref staleness,
different symptom), #991 / #1349 (rebuild triggering on base change).
## Workarounds
Repository re-scan after GitHub finishes recomputing mergeability, pushing a
commit to the PR head, or close/reopen the PR.
Contributor guide
Research direction
Start in GitHubSCMSource#createPullRequestSCMRevision and trace how merge_commit_sha parents produce baseHash before the existing getRef("heads/" + pr.getBase().getRef()) fallback. Review the GitHub API behavior described for retargeted pull requests, then add regression coverage for a stale merge target and verify the corrected checkout behavior. Confirm the preferred approach with maintainers before implementing it.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- github, java
- Domain
- api, backend, ci-cd
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100