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

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions