Add native GitHub Stacks support (--github-stacks)#363
Open
ezyang wants to merge 1 commit into
Open
Conversation
GitHub Stacks (private preview) is a first-class REST resource: POST
/repos/{owner}/{repo}/stacks links a bottom-to-top list of PR numbers
into a native stack, /stacks/{n}/add appends, and /stacks/{n}/unstack
dissolves. This adds an opt-in flag that links the PRs ghstack submits
into such a stack, enabled per-invocation with `--github-stacks` or
persistently via `ghstack config github_stacks true`.
The feature requires --direct mode: the server requires each PR's base
ref to be the head ref of the PR below it, which is exactly what
--direct submits produce and the classic base-branch layout never
satisfies. Without --direct, a warning is logged and no stack is
linked.
After push_updates finishes updating PRs, _sync_github_stack reconciles
the server-side stack against the full local chain (all_diffs, not just
the submitted prefix, so prefix-only submits don't truncate an existing
stack): an in-sync stack is a no-op, new PRs on top are appended via
/add, and any other restructure dissolves and recreates the stack since
the API has no reorder endpoint. All stack operations are non-fatal —
a 404 (Stacks not enabled on the repository) or any other error logs a
warning and the PRs remain submitted normally.
Live testing surfaced an undocumented server rule that shaped the
design: once a PR is in a native stack, any PATCH /pulls/{n} that
includes the base field is rejected with 422, even if the value is
unchanged. Direct mode previously sent base on every update, so
resubmitting an unchanged stack would crash. To handle this, no-op
base updates are no longer sent at all, and when a resubmit genuinely
retargets a PR (e.g. inserting a commit mid-stack) the affected stack
is dissolved first via _unstack_prs and recreated afterwards.
Supporting changes: github_real's REST layer now returns None on
204 No Content (which unstack returns), and the fake GitHub endpoint
models the stacks resource — including the base-chaining rule on
create/add and the no-base-PATCH rule — so tests exercise the same
server behavior observed live. A new test covers stack creation,
idempotent resubmit, append-on-top, prefix-only submits, and mid-stack
insert (dissolve + recreate) in both direct and non-direct modes.
The README documents the feature and its --direct requirement.
[ghstack-poisoned]
Owner
Author
|
Stack from ghstack (oldest at bottom): |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
GitHub Stacks (https://github.github.com/gh-stack/, private preview) is a
first-class REST resource: POST /repos/{o}/{r}/stacks with a bottom-to-top
list of PR numbers links them into a stack, /stacks/{n}/add appends, and
/stacks/{n}/unstack dissolves. The server requires each PR's base ref to
be the head ref of the PR below it, which is exactly what --direct submits
produce (and classic base-branch layout never satisfies), so the feature
requires --direct and warns otherwise.
Enable with
ghstack --direct --github-stacksor persistently viaghstack config github_stacks true.After push_updates finishes updating PRs, _sync_github_stack reconciles
the server-side stack with the full local chain (all_diffs, not just the
submitted prefix, so prefix-only submits don't truncate an existing
stack): in-sync stacks are a no-op, new PRs on top are appended via /add,
and any other restructure is unstack + recreate since the API has no
reorder endpoint. All stack operations are non-fatal: a 404 (Stacks not
enabled) or any other error logs a warning and the PRs remain submitted
normally.
Live testing against pytorch/pytorch surfaced an undocumented rule that
shaped the design: once a PR is in a native stack, any PATCH /pulls/{n}
that includes the base field is rejected with 422, even if the value is
unchanged. Direct mode previously sent base on every update, so
resubmitting an unchanged stack would crash. Fixes: no-op base updates
are no longer sent at all, and when a resubmit genuinely retargets a PR
(e.g. inserting a commit mid-stack) the affected stack is dissolved first
(_unstack_prs) and recreated after. An alternative was to route
retargeting through a new stack-aware endpoint, but no such endpoint
exists in the API surface gh-stack v0.0.8 uses.
github_real.arest now returns None on 204 No Content (unstack returns
it). The fake endpoint models the stacks resource, including the
base-chaining rule on create/add and the no-base-PATCH rule, so the tests
exercise the same server behavior observed live.
Test Plan:
New test covers create, idempotent resubmit, append-on-top, and
mid-stack insert (dissolve + recreate) in both direct and non-direct
modes; full suite and linters pass:
Verified live against pytorch/pytorch (which has Stacks enabled) with
draft [skip ci] PRs since the fake endpoint can only mirror observed
behavior: initial submit created stack #190147 (#190145 <- #190146),
unchanged resubmit was a no-op, a third commit was appended via /add,
and a mid-stack insert dissolved and recreated the stack as #190150 with
correct order. All test PRs, branches, and stacks were cleaned up.
This PR was authored with an AI assistant.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com