Summary
The merge queue rebased a commit whose parent was already the queue base. The rebase changed only the SHA: same parent, same tree. GitHub then rewrote the head of the layer above to a commit with an identical tree, which restarted a required 15-minute check. It did not put that layer back in the queue.
A fast-forward would have produced the same history, with no rewrite, no re-run and no second enqueue.
Evidence
Stack main ← #101 ← #102, queue method REBASE, both pull requests approved and green. The SHAs below are relabelled; the parent and tree relationships are verbatim.
The bottom commit needed no rebase. Its parent was the base the queue built against, gh-readonly-queue/main/pr-101-B:
queue base: B
#101 head: X parent B tree T1
landed on main as: X' parent B tree T1
The new SHA invalidated the layer above. GitHub rewrote its head to a commit with the same tree:
#102 head before: Y tree T2
#102 head after: Y' tree T2
The queue then stood empty and the required checks restarted:
13:26:16 queue=[#101] #101 inQ=true pos=1 #102 base=feature/bottom inQ=false head=Y
13:26:47 queue=[] #101 MERGED #102 base=main inQ=false head=Y'
The suite runs three times for one landing: once on #102, once after the rewrite over the same tree, and once in the queue after a manual re-enqueue. The second run cannot reuse the build cache either, because the merge that caused the rewrite also republished a container image the test tasks key on. It pays full price for a tree that was already green.
Expected
When a head's parent is already the queue base, land it as a fast-forward. The SHA then does not change, so no layer above needs a rewrite, a re-run or a second enqueue.
More generally: a rebase that keeps both the parent and the tree changes nothing, and the queue should fast-forward instead.
Actual
Under merge_method: REBASE the queue rewrites every commit, including one that is already a fast-forward. Each layer above pays for the new SHA with a full CI re-run.
Environment
gh 2.100.0, gh stack v0.0.8
- Trunk ruleset:
merge_queue: grouping_strategy HEADGREEN, merge_method REBASE,
max_entries_to_build 8, max_entries_to_merge 8,
min_entries_to_merge 1, min_entries_to_merge_wait_minutes 5,
check_response_timeout_minutes 40
pull_request: allowed_merge_methods ["rebase"], required_approving_review_count 1,
require_last_push_approval false, dismiss_stale_reviews_on_push false
delete_branch_on_merge: true, allow_auto_merge: false
- A required check that takes about 15 minutes, not a no-op job.
Reproduction
- Protect a trunk with a
REBASE merge queue and a slow required check.
- Run
gh stack link <bottom> <top>. Approve both, and rebase the bottom so its parent is the trunk tip.
- Press Enqueue stack (2).
- Compare the landed commit's parent and tree against the bottom pull request's head: same parent, same tree, new SHA. The top pull request's head is rewritten to an identical tree, its required checks restart, and
isInMergeQueue stays false.
Related
Summary
The merge queue rebased a commit whose parent was already the queue base. The rebase changed only the SHA: same parent, same tree. GitHub then rewrote the head of the layer above to a commit with an identical tree, which restarted a required 15-minute check. It did not put that layer back in the queue.
A fast-forward would have produced the same history, with no rewrite, no re-run and no second enqueue.
Evidence
Stack
main ← #101 ← #102, queue methodREBASE, both pull requests approved and green. The SHAs below are relabelled; the parent and tree relationships are verbatim.The bottom commit needed no rebase. Its parent was the base the queue built against,
gh-readonly-queue/main/pr-101-B:The new SHA invalidated the layer above. GitHub rewrote its head to a commit with the same tree:
The queue then stood empty and the required checks restarted:
The suite runs three times for one landing: once on
#102, once after the rewrite over the same tree, and once in the queue after a manual re-enqueue. The second run cannot reuse the build cache either, because the merge that caused the rewrite also republished a container image the test tasks key on. It pays full price for a tree that was already green.Expected
When a head's parent is already the queue base, land it as a fast-forward. The SHA then does not change, so no layer above needs a rewrite, a re-run or a second enqueue.
More generally: a rebase that keeps both the parent and the tree changes nothing, and the queue should fast-forward instead.
Actual
Under
merge_method: REBASEthe queue rewrites every commit, including one that is already a fast-forward. Each layer above pays for the new SHA with a full CI re-run.Environment
gh2.100.0,gh stackv0.0.8delete_branch_on_merge: true,allow_auto_merge: falseReproduction
REBASEmerge queue and a slow required check.gh stack link <bottom> <top>. Approve both, and rebase the bottom so its parent is the trunk tip.isInMergeQueuestaysfalse.Related