When a stacked pull request is merged into its own base branch (the layer below it) rather than the stack's trunk, its timeline says it was merged into the trunk: "merged commit <sha> into main". The trunk never received the commit. GitHub records the merge correctly (MergedEvent.mergeRefName is the layer below), so only the displayed branch is wrong.
The effect is that an unmerged change looks like it landed on the default branch.
Reproduction
-
Create a two-PR stack: PR A (feature-a → main) and PR B (feature-b → feature-a), with feature-b built on feature-a.
-
Fast-forward the bottom branch to the top branch's head with a plain push (no force push, no gh stack):
git push origin <feature-b head>:refs/heads/feature-a
-
GitHub marks PR B merged within a second, and deletes feature-b if "Automatically delete head branches" is on.
Actual
- PR B's timeline reads "merged commit
<feature-b head> into main".
main does not contain that commit (GET /repos/{owner}/{repo}/compare/main...<sha> shows it ahead of main).
- PR A is still open against
main, so the stack is left with its top layer merged and its bottom layer open.
Expected
The timeline names the branch PR B was merged into, feature-a. GitHub already stores it:
query {
repository(owner: "OWNER", name: "REPO") {
pullRequest(number: 2) { # PR B
baseRefName # "feature-a"
stack { baseRefName } # "main"
timelineItems(itemTypes: [MERGED_EVENT], first: 1) {
nodes { ... on MergedEvent { mergeRefName } } # "feature-a"
}
}
}
}
Public example
unicode-org/icu4x-docs#85, (taken from the stacked PRs feedback discussion) is the same case. It is the second layer of a stack whose trunk is main, and its base is script-improvements. It was marked merged when its base branch was pushed to include its head (base_ref_force_pushed in the same second as merged, and the recorded merge commit is the PR's head). Its timeline reads "merged commit b1ec50a into main", while MergedEvent.mergeRefName is script-improvements, and b1ec50a is not in main.
Related
When a stacked pull request is merged into its own base branch (the layer below it) rather than the stack's trunk, its timeline says it was merged into the trunk: "merged commit
<sha>into main". The trunk never received the commit. GitHub records the merge correctly (MergedEvent.mergeRefNameis the layer below), so only the displayed branch is wrong.The effect is that an unmerged change looks like it landed on the default branch.
Reproduction
Create a two-PR stack: PR A (
feature-a→main) and PR B (feature-b→feature-a), withfeature-bbuilt onfeature-a.Fast-forward the bottom branch to the top branch's head with a plain push (no force push, no
gh stack):GitHub marks PR B merged within a second, and deletes
feature-bif "Automatically delete head branches" is on.Actual
<feature-b head>intomain".maindoes not contain that commit (GET /repos/{owner}/{repo}/compare/main...<sha>shows it ahead ofmain).main, so the stack is left with its top layer merged and its bottom layer open.Expected
The timeline names the branch PR B was merged into,
feature-a. GitHub already stores it:Public example
unicode-org/icu4x-docs#85, (taken from the stacked PRs feedback discussion) is the same case. It is the second layer of a stack whose trunk is
main, and its base isscript-improvements. It was marked merged when its base branch was pushed to include its head (base_ref_force_pushedin the same second asmerged, and the recorded merge commit is the PR's head). Its timeline reads "merged commit b1ec50a into main", whileMergedEvent.mergeRefNameisscript-improvements, andb1ec50ais not inmain.Related
main.