Repository navigation
Source control: GitHub stack actions, merge and rebase (A6) #642
Description
Summary
GitHub native stack actions: merge stack and rebase stack. Phase A6 of #535. Depends on #641. Async merge first, rebase second.
Merge stack
Re-read the stack (GET repos/O/R/stacks?pull_request=N, then the stack detail) to revalidate the stack number and the affected set; reject a changed or missing expected head, a non-open target, drafts. PUT repos/O/R/pulls/N/merge-async with merge method, merge_action: default, the target's head SHA. Poll GET …/merge-async/{uuid} at 1, 2, 4, 8, 10 s then 10 s to a 5-minute deadline; keep the UUID across reconnect; pending at the deadline is an explicit ambiguous result and is never resubmitted; a 409 with an existing UUID is reconciled, not retried; failed is a rejection; merged or enqueued is success (enqueued is not "merged" and does not auto-settle). The stack UI: a stack map in the PR page's layer selector and the linked rows (every layer with its state; the merge scope is the selected layer plus every unmerged layer below it, which land together; drafts and non-open layers below are the blockers, as upstream); merge and rebase actions are offered only from a linked layer's page (a dismissed or not-linked layer shows the map with the actions disabled and the reason); the bottom layer also merges through the async stack merge; a running or unconfirmed operation is host-published state shown on every device, with the operation id in its popover; an unconfirmed merge is kept until a sync observes the result or 24 h pass; rebase has no cancel and never becomes the primary action; the host checks its Git name and email before a rebase; the stack note in the map collapses per device.
Rebase stack
Check every open layer's write permission (viewerPermission ADMIN/MAINTAIN/WRITE or maintainerCanModify) before any mutation. Scratch clone in a temp dir with the token only in a Git extra-header environment (never argv, config or URL), fetch base and layer branches, bottom old parent = merge-base(base, reviewed head), higher old parents = reviewed prior heads; rebase --onto new old per layer from a detached reviewed SHA; push each changed head with --force-with-lease=refs/heads/B:reviewedSha; 120 s per git command; stop at the first conflict, abort the scratch rebase, report the failing PR and the completed lower layers (earlier pushes remain). Does not touch the project checkout. No copied committer identity; equivalence to GitHub's server rebase (signing, approval retention) is not promised without live evidence.
Evidence required
A disposable native stack: queued vs merged; pending, deadline and reconnect; a rebase failing at layer two with a changed-head lease; completed layers reported, no automatic resubmission. Real bare-repo tests for the rebase contract (replay only each layer's own commits; lease preserves a concurrent push; conflict leaves the failing layer untouched).
Reference
T3 Code: apps/server/src/pullRequest/githubStackActions.ts, githubStackRebase.ts, their tests; GitHub docs on stacked pull requests and merge-async. Design: tmp/design/track-a6-ui.md in the maintainer's checkout.
Activity
Screenshots for #642