Skip to content

Merge-strategy PR builds fail with "not something we can merge" after PR base branch is retargeted (stale merge_commit_sha trusted) #1534

Description

@davidjbng

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 <old-develop-tip> into PR head <head-sha>
stderr: merge: <old-develop-tip> - 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/<new-base>. 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/<base.ref> (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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions