Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

Stacked PR keeps a stale head after its branch is rewritten server-side: merge box spins on "loading stack status", and both update-branch and merge refuse

Đang mở
#519 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

Đánh giá

Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức phù hợp với người mới
48/100
Loại issue
Lỗi
Độ rõ ràng
Khá rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
git, github, go, graphql
Lĩnh vực
backend-api-design, cli

Hướng nghiên cứu

Trace stack status handling and the update-branch, merge, and merge-async entry points, using the reported branch-ref and pull-request-head mismatch as the starting case. Reproduce the server-side rewrite followed by the stale stacked pull request, then verify that the head follows the branch or that a supported recovery route remains available. Confirm that the UI leaves the loading state and that merging reports its completed result.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

Summary

A stacked pull request got its branch rewritten by a GitHub-side operation, but the pull request head never followed. The branch ref and refs/pull/<n>/head then pointed at different commits, and the pull request was wedged: the merge box spun on loading stack status indefinitely, mergeable stayed UNKNOWN, and both REST routes out of the state were refused because the pull request is stacked.

Environment

  • Native stack feature (stack created in the web UI, not via gh stack).
  • Private organization repository.
  • Default branch protected by classic branch protection: 6 required status checks (GitHub Actions), strict (branch must be up to date). No rulesets, no merge queue, no required reviews, no CODEOWNERS.
  • Stack has 2 entries, base = default branch. Position 1 was merged about four weeks earlier; position 2 stayed open. The stack still reports "open": true and still lists the merged pull request as a member.
  • Both stack members target the default branch directly (base.ref = default branch for each).

Reproduction

  1. Create a 2-entry stack on the default branch.
  2. Merge the bottom pull request. The stack stays open and keeps the merged pull request as position 1.
  3. Let the default branch advance by several commits over the following weeks.
  4. Have the remaining branch rewritten through GitHub — the resulting commits carry committer GitHub, so the rewrite happened server-side, not from a local push.

Observed

After step 4 the branch ref and the pull request disagreed, and stayed that way for ~15 hours until manually unstuck:

refs/heads/<branch>           = B    rewritten, committer "GitHub", day 2 15:38
refs/pull/<n>/head            = A    pre-rewrite,  committer "GitHub", day 2 01:10
GET /repos/{o}/{r}/pulls/{n}  ->  head.sha = A
default branch   --o--o--o--o--o--o--o   (advanced while the PR sat open)
                       \
  refs/pull/<n>/head    *A     <- what the PR, the API and the merge box see
                          \
  refs/heads/<branch>      *B  <- what the server-side rewrite actually wrote

The pull request was unmergeable from every direction:

  • UI: merge box stuck on loading stack status; the spinner never resolved. No Merge button, no Update branch button, no error text.
  • REST / GraphQL: mergeable: null / UNKNOWN, mergeable_state: "unknown", mergeStateStatus: UNKNOWN — stable across repeated polls spread over many minutes. (Polling normally forces the background recomputation; here it never converged.)
  • statusCheckRollup reported SUCCESS — but for the stale head A.

Both REST escape hatches refused, each citing the stack:

PUT /repos/{owner}/{repo}/pulls/{n}/update-branch
403 {"message": "Updating a stacked PR's branch via this endpoint is not supported."}

PUT /repos/{owner}/{repo}/pulls/{n}/merge
403 {"message": "Merging stacked PRs via this endpoint is not supported. Use the asynchronous merge endpoint instead."}

The asynchronous endpoint that the second message points to accepted the request and then failed against the stale head:

PUT /repos/{owner}/{repo}/pulls/{n}/merge-async
{"merge_method": "squash", "merge_action": "direct_merge"}
-> {"status": "pending", "details": {"uuid": "...", "expected_head_sha": "A"}}

GET /repos/{owner}/{repo}/pulls/{n}/merge-async/{uuid}
-> {"status": "failed", "details": {"message": "6 of 6 required status checks are expected."}}

All six required checks had completed successfully on A — the very sha the endpoint echoed back as expected_head_sha. So the failure message is doubly misleading: the checks are neither missing nor pending on the head it claims to be merging.

Expected

When a stack rewrites a member branch, the pull request head follows the branch ref, exactly as an ordinary force-push does, and the merge box recovers.

Failing that, at least one route out of the state should stay open. update-branch and merge should not both refuse a stack whose only unmerged member targets the default branch directly — that combination leaves no supported way to fix a stale head, from the UI or the API.

Actual

The pull request was unmergeable from the UI and from every REST route, with no diagnostic anywhere — only an endless loading stack status spinner. Nothing in the UI indicated that the pull request was looking at a different commit than its own branch.

Workaround

Push any new commit to the branch. I merged the default branch into it with a plain local git merge + git push (no force). The synchronize event resynced the pull request head within seconds: mergeable flipped to true, mergeable_state went blocked -> unstable as the required checks re-ran on the new head, and the merge then completed normally.

One more UI symptom, after the merge

Clicking Merge on the recovered pull request also appeared to hang — the merge box kept spinning with no confirmation. The merge had in fact already succeeded: the API reported merged: true with a merge commit sha, and the commit was on the default branch. The merge box simply never updated.

Related but distinct

  • #485 — a partial stack merge leaves a stale stack base sha, and Rebase stack replays already-merged commits. Here it is the pull request head that is stale, and no merge queue is involved.
  • #450 — the stack view shows stale readiness while the API reports the pull requests clean. Here the API itself is the one reporting UNKNOWN.

Both of those and this one share a theme: a stack that has had part of it merged keeps stale state somewhere, and the UI surfaces it as an unexplained spinner or an unexplained "not ready".

Ngôn ngữ chính
Go
Star
1.5k
Fork
73
Merge trung bình
1 ngày 8 giờ
Pull request đã merge (30 ngày)
7

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của github/gh-stack

Tất cả issue của github/gh-stack

Issue tương tự

Thêm issue về Go

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.