diff --git a/README.md b/README.md index 8855c03..a34a93b 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ Stack metadata is stored in `.git/gh-stack` (a JSON file, not committed to the r Initialize a new stack in the current repository. ``` -gh stack init [branches...] [flags] +gh stack init [flags] [branches...] ``` Creates an entry in `.git/gh-stack` to track stack state. In interactive mode (no arguments), prompts you to name branches and offers to use the current branch as the first layer. In interactive mode, you'll also be prompted to set an optional branch prefix (unless adopting existing branches). When a prefix is set, branch names you enter are automatically prefixed. When explicit branch names are given, creates any that don't already exist (branching from the trunk). The trunk defaults to the repository's default branch unless overridden with `--base`. @@ -115,7 +115,7 @@ gh stack init -p feat --numbered Add a new branch on top of the current stack. ``` -gh stack add [branch] [flags] +gh stack add [flags] [branch] ``` Creates a new branch at the current HEAD, adds it to the top of the stack, and checks it out. Must be run while on the topmost branch of a stack. If no branch name is given, prompts for one. @@ -190,7 +190,7 @@ gh stack checkout Pull from remote and do a cascading rebase across the stack. ``` -gh stack rebase [branch] [flags] +gh stack rebase [flags] [branch] ``` Fetches the latest changes from `origin`, then ensures each branch in the stack has the tip of the previous layer in its commit history. Rebases branches in order from trunk upward. If a branch's PR has been squash-merged, the rebase automatically switches to `--onto` mode to correctly replay commits on top of the merge target. @@ -331,7 +331,7 @@ gh stack view --json Remove a stack from local tracking and delete it on GitHub. Also available as `gh stack delete`. ``` -gh stack unstack [branch] [flags] +gh stack unstack [flags] [branch] ``` If no branch is specified, uses the current branch to find the stack. Deletes the stack on GitHub first, then removes local tracking. Use `--local` to only remove the local tracking entry. @@ -414,7 +414,7 @@ gh stack feedback "Support for reordering branches" Create a short command alias so you can type less. ``` -gh stack alias [name] [flags] +gh stack alias [flags] [name] ``` Installs a small wrapper script into `~/.local/bin/` that forwards all arguments to `gh stack`. The default alias name is `gs`, but you can choose any name by passing it as an argument. After setup, you can run `gs push` instead of `gh stack push`. diff --git a/cmd/feedback.go b/cmd/feedback.go index 94195c1..f1e88b3 100644 --- a/cmd/feedback.go +++ b/cmd/feedback.go @@ -9,7 +9,10 @@ import ( "github.com/spf13/cobra" ) -const feedbackBaseURL = "https://github.com/github/gh-stack/discussions/new?category=feedback" +const ( + feedbackURL = "https://gh.io/stacks-feedback" + feedbackFormURL = "https://gh.io/stacks-feedback-form" +) func FeedbackCmd(cfg *config.Config) *cobra.Command { cmd := &cobra.Command{ @@ -25,15 +28,15 @@ func FeedbackCmd(cfg *config.Config) *cobra.Command { } func runFeedback(cfg *config.Config, args []string) error { - feedbackURL := feedbackBaseURL + targetURL := feedbackURL if len(args) > 0 { title := strings.Join(args, " ") - feedbackURL += "&title=" + url.QueryEscape(title) + targetURL = feedbackFormURL + "?title=" + url.QueryEscape(title) } b := browser.New("", cfg.Out, cfg.Err) - if err := b.Browse(feedbackURL); err != nil { + if err := b.Browse(targetURL); err != nil { return err } diff --git a/cmd/submit.go b/cmd/submit.go index 97f112d..483015a 100644 --- a/cmd/submit.go +++ b/cmd/submit.go @@ -230,7 +230,7 @@ func generatePRBody(commitBody string) string { footer := fmt.Sprintf( "Stack created with GitHub Stacks CLI β€’ Give Feedback πŸ’¬", - feedbackBaseURL, + feedbackURL, ) parts = append(parts, footer) diff --git a/cmd/submit_test.go b/cmd/submit_test.go index 1b130a3..514d091 100644 --- a/cmd/submit_test.go +++ b/cmd/submit_test.go @@ -26,7 +26,7 @@ func TestGeneratePRBody(t *testing.T) { commitBody: "", wantContains: []string{ "GitHub Stacks CLI", - feedbackBaseURL, + feedbackURL, "", }, }, diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs index 30d34d5..395e4aa 100644 --- a/docs/astro.config.mjs +++ b/docs/astro.config.mjs @@ -18,6 +18,9 @@ export default defineConfig({ head: [ { tag: 'meta', attrs: { name: 'robots', content: 'noindex, nofollow' } }, ], + components: { + SocialIcons: './src/components/CustomHeader.astro', + }, customCss: [ './src/styles/custom.css', ], diff --git a/docs/src/assets/screenshots/merge-box-failing-stack-requirements.png b/docs/src/assets/screenshots/merge-box-failing-stack-requirements.png deleted file mode 100644 index 652dd51..0000000 Binary files a/docs/src/assets/screenshots/merge-box-failing-stack-requirements.png and /dev/null differ diff --git a/docs/src/assets/screenshots/stack-merge-box.png b/docs/src/assets/screenshots/stack-merge-box.png index 8484536..2a4b355 100644 Binary files a/docs/src/assets/screenshots/stack-merge-box.png and b/docs/src/assets/screenshots/stack-merge-box.png differ diff --git a/docs/src/components/CustomHeader.astro b/docs/src/components/CustomHeader.astro new file mode 100644 index 0000000..45bffde --- /dev/null +++ b/docs/src/components/CustomHeader.astro @@ -0,0 +1,172 @@ +--- +import Default from '@astrojs/starlight/components/SocialIcons.astro'; +const base = import.meta.env.BASE_URL; +--- + + + + +
+ + +
+ + + + + + diff --git a/docs/src/content.config.ts b/docs/src/content.config.ts index 86a8a08..929d922 100644 --- a/docs/src/content.config.ts +++ b/docs/src/content.config.ts @@ -1,10 +1,18 @@ -import { defineCollection } from 'astro:content'; +import { defineCollection, z } from 'astro:content'; import { docsLoader } from '@astrojs/starlight/loaders'; import { docsSchema } from '@astrojs/starlight/schema'; export const collections = { docs: defineCollection({ loader: docsLoader(), - schema: docsSchema(), + schema: docsSchema({ + extend: z.object({ + banner: z.object({ + content: z.string(), + }).default({ + content: 'Stacked PRs is currently in private preview. Sign up for the waitlist β†’', + }), + }), + }), }), }; diff --git a/docs/src/content/docs/faq.md b/docs/src/content/docs/faq.md index 5abe983..aaa4206 100644 --- a/docs/src/content/docs/faq.md +++ b/docs/src/content/docs/faq.md @@ -5,11 +5,11 @@ description: Frequently asked questions about GitHub Stacked PRs. ## Creating Stacked PRs -### What is a stacked PR? How is it different from a regular PR? +### What is a Stacked PR? How is it different from a regular PR? -A stacked PR is a pull request that is part of an ordered chain of PRs, where each PR targets the branch of the PR below it instead of targeting `main` directly. Each PR in the stack represents one focused layer of a larger change. Individually, each PR is still a regular pull request β€” it just has a different base branch and GitHub understands the relationship between the PRs in the stack. +A Stacked PR is a pull request that is part of an ordered chain of PRs, where each PR targets the branch of the PR below it instead of targeting `main` directly. Each PR in the stack represents one focused layer of a larger change. Individually, each PR is still a regular pull request β€” it just has a different base branch, and GitHub understands the relationship between the PRs in the stack. -### How do I create a stacked PR? +### How do I create a Stacked PR? You can create a stack using the `gh stack` CLI: @@ -27,13 +27,13 @@ You can also create stacks entirely from the GitHub UI β€” create the first PR n ### How do I add PRs to my stack? -Use `gh stack add ` to add a new branch on top of the current stack. When you run `gh stack submit`, a PR is created for each branch and they are linked together as a Stack on GitHub. +Use `gh stack add ` to add a new branch on top of the current stack. When you run `gh stack submit`, a PR is created for each branch, and they are linked together as a Stack on GitHub. You can also add PRs to an existing stack from the GitHub UI. See [Adding to an Existing Stack](/gh-stack/guides/ui/#adding-to-an-existing-stack) for details. ### How can I modify my stack? -Reordering or inserting branches into the middle of a stack is not currently supported. To restructure a stack, use `gh stack unstack` to tear it down and then recreate it with `gh stack init --adopt`: +Reordering or inserting branches into the middle of a stack is not currently supported. To restructure a stack, use `gh stack unstack` to tear it down and then re-create it with `gh stack init --adopt`: ```sh # 1. Remove the stack @@ -54,26 +54,26 @@ gh stack init --adopt branch-2 branch-1 branch-3 ### Can stacks be created across forks? -No, stacked PRs currently require all branches to be in the same repository. Cross-fork stacks are not supported. +No, Stacked PRs currently require all branches to be in the same repository. Cross-fork stacks are not supported. ## Checks, Rules & Requirements -### How are branch protection rules evaluated for stacked PRs? +### How are branch protection rules evaluated for Stacked PRs? Every PR in a stack is treated as if it is targeting the **base of the stack** (typically `main`), regardless of which branch it directly targets. This means: - **Required reviews** are evaluated as if the PR is targeting the stack base. - **Required status checks** are evaluated as if the PR is targeting the stack base. -- **CODEOWNERS** are evaluated from the stack base β€” changes in codeowners on a PR at the bottom of the stack will not affect PRs above it in the stack. +- **CODEOWNERS** are evaluated from the stack base β€” changes in `CODEOWNERS` on a PR at the bottom of the stack will not affect PRs above it in the stack. - **Code scanning workflows** are evaluated as if the PR is targeting the stack base. -### How do GitHub Actions work with stacked PRs? +### How do GitHub Actions work with Stacked PRs? GitHub Actions workflows trigger as if each PR in the stack is targeting the base of the stack (e.g., `main`). If you have a workflow configured to run on `pull_request` events targeting `main`, it will run for **every PR in the stack** β€” not just the bottom one. ### Do all previous PRs need to be passing checks before I can merge? -Yes. In order to merge a PR in the stack, **all PRs below it** must also have passing checks and meet all merge requirements. For example, in a stack of `main <- PR1 <- PR2 <- PR3` and you want to merge PR #3, both PR #1 and PR #2 must have passing checks, required reviews, and satisfy all branch protection rules. +Yes. In order to merge a PR in the stack, **all PRs below it** must also have passing checks and meet all merge requirements. For example, in a stack of `main <- PR1 <- PR2 <- PR3`, if you want to merge PR #3, both PR #1 and PR #2 must have passing checks, required reviews, and satisfy all branch protection rules. ### Is a linear history required? @@ -86,13 +86,13 @@ If the stack is not linear (e.g., after changes were pushed to a lower branch), ## Merging Stacked PRs -### What conditions need to be met for a stacked PR to be mergeable? +### What conditions need to be met for a Stacked PR to be mergeable? Every PR in a stack must meet the same merge requirements as a PR targeting the stack base (e.g., `main`): required reviews, passing CI checks, CODEOWNER approvals, and a linear history. All PRs below it must also meet these requirements. See the [Checks, Rules & Requirements](#checks-rules--requirements) section above for details. ### How does merging a stack of PRs differ from merging a regular PR? -Stacks must be merged **from the bottom up**. You can merge the bottom PR (and all non-merged PRs below it) in a single operation. After a PR is merged, the remaining stack is automatically rebased so the next PR targets `main` directly. +Stacks must be merged **from the bottom up**. When you merge a PR, all non-merged PRs below it in the stack are also merged. After a PR is merged, the remaining stack is automatically rebased so the next PR targets `main` directly. ### What happens when you merge a PR in the middle of the stack? @@ -114,23 +114,23 @@ With rebase merge, all of the commits from each PR in the stack are replayed ont PRs in a stack are merged sequentially, from the bottom up. When you initiate a merge, the bottom PR is merged first, and then the next PR above it, and so on. -There will not be a single push operation that adds all the commits from all the branches at once. +Commits are not all landed in a single atomic operation β€” each PR is merged individually in sequence. ### Can I merge only part of a stack? What happens to the remaining unmerged PRs? -Yes, partial stack merges are supported. After the merge, the lowest unmerged PR is updated to explicitly target the stack base (e.g. `main`). A cascading rebase is also automatically run to rebase the remaining unmerged branches. +Yes, partial stack merges are supported. After the merge, the lowest unmerged PR is updated to explicitly target the stack base (e.g., `main`). A cascading rebase is also automatically run to rebase the remaining unmerged branches. ### What happens if you close a PR in the middle of the stack? -Closing a PR in the middle of the stack will block all PRs above it from being mergeable. The stack relationship is preserved, so if you want to open a different PR or modify the stack, you will need to unstack and then recreate the stack. +Closing a PR in the middle of the stack will block all PRs above it from being mergeable. The stack relationship is preserved, so if you want to open a different PR or modify the stack, you will need to unstack and then re-create the stack. ### What happens when there is an error merging a PR in the middle of a stack? If a merge fails (e.g., due to a failing check or merge conflict), the operation stops and no subsequent PRs are merged. You'll need to resolve the issue before continuing. -### Does Stacked PRs support merge queue? +### Do Stacked PRs support merge queue? -Yes, stacked PRs fully support merging via merge queue. When you merge a stack through the merge queue: +Yes, Stacked PRs fully support merging via merge queue. When you merge a stack through the merge queue: - **All PRs in the stack are added to the queue** in the correct order, ensuring a linear sequence. - **If a PR is removed or ejected from the merge queue**, all PRs above it in the stack are also ejected and removed from the queue. @@ -154,11 +154,11 @@ No. Stacked PRs are built on standard git branches and regular pull requests. Yo ### Will this work with a different tool for stacking? -Yes, you can continue to use your tool of choice (e.g. jj, Sapling, ghstack, git-town, etc.) to manage stacks locally and push up your branches to GitHub. +Yes, you can continue to use your tool of choice (e.g., jj, Sapling, ghstack, git-town, etc.) to manage stacks locally and push up your branches to GitHub. Stacked PRs on GitHub are based on the standard pull request model β€” any tool that creates PRs with the correct base branches can work with them. The `gh stack` CLI is purpose-built for the GitHub experience, but other tools that manage branch chains should be compatible. -You can also use the GitHub CLI in conjunction with other tools to simply create a stack of PRs: +You can also use the GitHub CLI in conjunction with other tools to open your PRs as a stack: ```bash # Create a stack of branches locally using jj diff --git a/docs/src/content/docs/getting-started/quick-start.md b/docs/src/content/docs/getting-started/quick-start.md index f8f9edd..9b2e50f 100644 --- a/docs/src/content/docs/getting-started/quick-start.md +++ b/docs/src/content/docs/getting-started/quick-start.md @@ -1,6 +1,6 @@ --- title: Quick Start -description: Install the gh stack CLI and create your first stacked PR in minutes. +description: Install the gh stack CLI and create your first Stacked PR in minutes. --- ## Prerequisites diff --git a/docs/src/content/docs/guides/stacked-prs.md b/docs/src/content/docs/guides/stacked-prs.md index 5ad3203..5ff2bb7 100644 --- a/docs/src/content/docs/guides/stacked-prs.md +++ b/docs/src/content/docs/guides/stacked-prs.md @@ -5,7 +5,7 @@ description: Practical guide for reviewing, merging, and managing stacked pull r This guide covers the practical day-to-day experience of working with Stacked PRs β€” how to review them, how merging works step by step, and how to keep things in sync from the CLI. -For an introduction to what stacks are and how GitHub supports them natively, see the [Overview](/gh-stack/introduction/overview/). For a visual walkthrough of the UI, see [Using Stacks in the GitHub UI](/gh-stack/guides/ui/). +For an introduction to what stacks are and how GitHub supports them natively, see the [Overview](/gh-stack/introduction/overview/). For a visual walkthrough of the UI, see [Stacked PRs in the GitHub UI](/gh-stack/guides/ui/). ## Reviewing Stacked PRs diff --git a/docs/src/content/docs/guides/ui.md b/docs/src/content/docs/guides/ui.md index 0c74bca..8629805 100644 --- a/docs/src/content/docs/guides/ui.md +++ b/docs/src/content/docs/guides/ui.md @@ -1,6 +1,6 @@ --- title: Stacked PRs in the GitHub UI -description: A visual walkthrough of creating, navigating, merging, and managing stacked PRs directly in the GitHub pull request UI. +description: A visual walkthrough of creating, navigating, merging, and managing Stacked PRs directly in the GitHub pull request UI. --- This guide walks through the key UI components and workflows for working with Stacked PRs on GitHub. @@ -51,7 +51,7 @@ If a stack already exists and you want to add a new PR to it: ![Adding a new PR to an existing stack](../../../assets/screenshots/add-to-existing-stack.png) -2. On the following page, the base branch is automatically set to the head of the top-most PR. Select the head branch for your new PR and click **Create pull request**. +2. On the following page, the base branch is automatically set to the head of the topmost PR. Select the head branch for your new PR and click **Create pull request**. ![Selecting branch to add to stack](../../../assets/screenshots/selecting-branch-to-add.png) @@ -75,11 +75,11 @@ Before a PR in the stack can be merged, the following conditions must be met: - **The stack must be fully rebased** with a linear history - **The current PR itself** must meet all branch protection requirements for the stack base -![Merge box showing failing stack requirements](../../../assets/screenshots/merge-box-failing-stack-requirements.png) +![Merge box for a stacked pull request](../../../assets/screenshots/stack-merge-box.png) ## Unstacking -If you want to reorder or reorganize the PRs in a stack, you must first dissolve the stack and then recreate it. You can unstack PRs from the UI. +If you want to reorder or reorganize the PRs in a stack, you must first dissolve the stack and then re-create it. You can unstack PRs from the UI. ### Dissolving the Entire Stack diff --git a/docs/src/content/docs/guides/workflows.md b/docs/src/content/docs/guides/workflows.md index 4f935ff..9afa06a 100644 --- a/docs/src/content/docs/guides/workflows.md +++ b/docs/src/content/docs/guides/workflows.md @@ -33,7 +33,7 @@ gh stack rebase # 7. Push the updated branches gh stack push -# 8. When the first PR is merged, sync the stack +# 8. Sync upstream changes as PRs get merged gh stack sync ``` @@ -42,34 +42,37 @@ gh stack sync For speed, use a branch prefix with `--numbered` and the `-Am` flags to fold staging, committing, and branch creation into a single command. Branch names are auto-generated as `prefix/01`, `prefix/02`, etc. ```sh +# Alias `gh stack` as `gs` for easier use +gh stack alias + # 1. Start a stack with numbered branches -gh stack init -p feat --numbered +gs init -p feat --numbered # β†’ creates feat/01 and checks it out # 2. Write code for the first layer # ... write code ... # 3. Stage and commit on the current branch -gh stack add -Am "Auth middleware" +gs add -Am "Auth middleware" # β†’ feat/01 has no commits yet, so the commit lands here # 4. Write code for the next layer # ... write code ... # 5. Create the next branch and commit -gh stack add -Am "API routes" +gs add -Am "API routes" # β†’ feat/01 already has commits, so feat/02 is created # 6. Keep going # ... write code ... -gh stack add -Am "Frontend components" +gs add -Am "Frontend components" # β†’ creates feat/03 # 7. Push everything and create PRs -gh stack submit +gs submit ``` -Each `gh stack add -Am "..."` stages all files, commits, and (if the current branch already has commits) creates a new branch β€” no separate `git add` or `git commit` needed. +Each `gs add -Am "..."` stages all files, commits, and (if the current branch already has commits) creates a new branch β€” no separate `git add` or `git commit` needed. ## Making Mid-Stack Changes @@ -132,7 +135,7 @@ This command: 4. Pushes the updated branches 5. Syncs PR state from GitHub -If a conflict is detected during the rebase, all branches are restored to their original state and you're advised to run `gh stack rebase` to resolve conflicts interactively. +If a conflict is detected during the rebase, all branches are restored to their original state, and you're advised to run `gh stack rebase` to resolve conflicts interactively. ## Structuring Your Stack diff --git a/docs/src/content/docs/index.mdx b/docs/src/content/docs/index.mdx index 63286dd..1a05930 100644 --- a/docs/src/content/docs/index.mdx +++ b/docs/src/content/docs/index.mdx @@ -47,7 +47,7 @@ A **stack** is a series of pull requests in the same repository where each PR ta A stack of pull requests: main at the bottom, with auth-layer (PR #1), api-endpoints (PR #2), and frontend (PR #3) stacked on top -GitHub understands stacks end-to-end: the pull request UI shows a **stack map** so reviewers can navigate between layers, branch protection rules are enforced against the **final target branch** (not just the direct base), and CI runs for every PR in the stack. +GitHub understands stacks end-to-end: the pull request UI shows a **stack map** so reviewers can navigate between layers, branch protection rules are enforced against the **final target branch** (not just the direct base), and CI runs for every PR in the stack as if they were targeting the final branch.
The stack navigator in a pull request header @@ -55,9 +55,9 @@ GitHub understands stacks end-to-end: the pull request UI shows a **stack map** ## How It Works -The `gh stack` CLI handles the local workflow: creating branches, keeping them rebased, pushing to GitHub, and creating PRs with the correct base branches. On GitHub, the PR UI gives reviewers the context they need β€” a stack map for navigation, focused diffs for each layer, and proper rules enforcement. +The `gh stack` CLI handles the local workflow: creating branches, managing rebases, pushing to GitHub, and creating PRs with the correct base branches. On GitHub, the PR UI gives reviewers the context they need β€” a stack map for navigation, focused diffs for each layer, and proper rules enforcement. -When you're ready to merge, you merge from the bottom up. Each PR can be merged directly or through the merge queue. When a PR at the bottom is merged, the remaining stack is automatically rebased so the next PR targets `main` and is ready for its own merge. +When you're ready to merge, you can merge all or a part of the stack. Each PR can be merged directly or through the merge queue. After a merge, the remaining PRs in the stack are automatically rebased so the lowest unmerged PR targets the base branch. ## Get Started @@ -65,19 +65,24 @@ When you're ready to merge, you merge from the bottom up. Each PR can be merged # Install the CLI extension gh extension install github/gh-stack -# Create a stack (creates and checks out the first branch) -gh stack init auth-layer +# Alias `gh stack` as `gs` for easier use (optional) +gh stack alias + +# Start a stack (creates and checks out the first branch) +gs init auth-layer # ... make commits ... -gh stack add api-routes + +# Create new layers in the stack (creates and checks out each new branch) +gs add api-routes # ... make commits ... -gh stack add frontend +gs add frontend # ... make commits ... # Push all branches -gh stack push +gs push # Open a stack of PRs -gh stack submit +gs submit ``` Ready to dive in? Start with the [Quick Start guide](/gh-stack/getting-started/quick-start/) or read the [full overview](/gh-stack/introduction/overview/). diff --git a/docs/src/content/docs/introduction/overview.md b/docs/src/content/docs/introduction/overview.md index 20a3024..947dd07 100644 --- a/docs/src/content/docs/introduction/overview.md +++ b/docs/src/content/docs/introduction/overview.md @@ -3,7 +3,7 @@ title: Overview description: What stacked pull requests are, why they matter, and how GitHub supports them natively. --- -## The Challenge +## Why Stacks? For developers who want to break large changes into smaller, dependent parts, the experience can be painful: @@ -89,8 +89,9 @@ While the PR UI provides the review and merge experience, the `gh stack` CLI han - **Navigating the stack** β€” `gh stack up`, `down`, `top`, and `bottom` let you move between layers without remembering branch names. - **Syncing everything** β€” `gh stack sync` fetches, rebases, pushes, and updates PR state in one command. - **Tearing down stacks** β€” `gh stack unstack` removes a stack from GitHub and local tracking if you need to restructure it. +- **Checking out a stack** β€” `gh stack checkout ` pulls down a stack, with all its branches, from GitHub to your local machine. -The CLI is not required to use Stacked PRs β€” the underlying git operations are standard. But it makes the workflow dramatically simpler. +The CLI is not required to use Stacked PRs β€” the underlying git operations are standard. But it makes the workflow simpler, and you can create Stacked PRs from the CLI instead of the UI. ## Thinking About Stack Structure diff --git a/docs/src/content/docs/reference/cli.md b/docs/src/content/docs/reference/cli.md index 3146773..5853d9f 100644 --- a/docs/src/content/docs/reference/cli.md +++ b/docs/src/content/docs/reference/cli.md @@ -138,7 +138,7 @@ Check out a stack from a pull request number or branch name. gh stack checkout [ | ] ``` -When a PR number is provided (e.g. `123`), the command fetches the stack on GitHub, pulls the branches, and sets up the stack locally. If the stack already exists locally and matches, it switches to the branch. If the local and remote stacks have different compositions, you'll be prompted to resolve the conflict. +When a PR number is provided (e.g., `123`), the command fetches the stack on GitHub, pulls the branches, and sets up the stack locally. If the stack already exists locally and matches, it switches to the branch. If the local and remote stacks have different compositions, you'll be prompted to resolve the conflict. When a branch name is provided, the command resolves it against locally tracked stacks only. @@ -197,11 +197,11 @@ gh stack sync [flags] Performs a safe, non-interactive synchronization of the entire stack: -1. **Fetch** β€” fetches the latest changes from `origin` -2. **Fast-forward trunk** β€” fast-forwards the trunk branch to match the remote (skips if diverged) -3. **Cascade rebase** β€” rebases all stack branches onto their updated parents (only if trunk moved). If a conflict is detected, all branches are restored to their original state and you are advised to run `gh stack rebase` to resolve conflicts interactively -4. **Push** β€” pushes all branches (uses `--force-with-lease` if a rebase occurred) -5. **Sync PRs** β€” syncs PR state from GitHub and reports the status of each PR +1. **Fetch** β€” fetches the latest changes from `origin`. +2. **Fast-forward trunk** β€” fast-forwards the trunk branch to match the remote (skips if diverged). +3. **Cascade rebase** β€” rebases all stack branches onto their updated parents (only if trunk moved). If a conflict is detected, all branches are restored to their original state, and you are advised to run `gh stack rebase` to resolve conflicts interactively. +4. **Push** β€” pushes all branches (uses `--force-with-lease` if a rebase occurred). +5. **Sync PRs** β€” syncs PR state from GitHub and reports the status of each PR. | Flag | Description | |------|-------------| diff --git a/docs/src/styles/custom.css b/docs/src/styles/custom.css index 2cedbb5..703db78 100644 --- a/docs/src/styles/custom.css +++ b/docs/src/styles/custom.css @@ -11,3 +11,19 @@ --sl-color-accent: #4f46e5; --sl-color-accent-high: #312e81; } + +/* Show full nav by default, switch to hamburger on narrow viewports */ +@media (max-width: 900px) { + .custom-header-links { + display: none !important; + } + .tablet-nav-wrapper { + display: block !important; + } +} + +@media (min-width: 901px) { + .tablet-nav-wrapper { + display: none !important; + } +} diff --git a/skills/gh-stack/SKILL.md b/skills/gh-stack/SKILL.md index d5e2a8f..1dc3a51 100644 --- a/skills/gh-stack/SKILL.md +++ b/skills/gh-stack/SKILL.md @@ -41,18 +41,35 @@ The GitHub CLI (`gh`) v2.0+ must be installed and authenticated. Install the ext gh extension install github/gh-stack ``` +Before using `gh stack`, configure git to prevent interactive prompts: + +```bash +git config rerere.enabled true # remember conflict resolutions (skips prompt on init) +git config remote.pushDefault origin # if multiple remotes exist (skips remote picker) +``` + ## Agent rules -1. **Always supply branch names as positional arguments** to `init`, `add`, and `checkout`. +**All `gh stack` commands must be run non-interactively.** Every command invocation must include the flags and positional arguments needed to avoid prompts, TUIs, and interactive menus. If a command would prompt for input, it will hang indefinitely. + +1. **Always supply branch names as positional arguments** to `init`, `add`, and `checkout`. Running these commands without arguments triggers interactive prompts. 2. **When a prefix is set, pass only the suffix to `add`.** `gh stack add auth` with prefix `feat` β†’ `feat/auth`. Passing `feat/auth` creates `feat/feat/auth`. -3. **Always use `--auto` when pushing** to skip PR title prompts. -4. **Always use `--json` when viewing** to get structured output. -5. **Use `--remote ` when multiple remotes are configured**, or set `remote.pushDefault` in git config. +3. **Always use `--auto` with `gh stack submit`** to auto-generate PR titles. Without `--auto`, `submit` prompts for a title for each new PR. +4. **Always use `--json` with `gh stack view`.** Without `--json`, the command launches an interactive TUI that cannot be operated by agents. There is no other appropriate flag β€” always pass `--json`. +5. **Use `--remote ` when multiple remotes are configured**, or pre-configure `git config remote.pushDefault origin`. Without this, `push`, `submit`, `sync`, and `checkout` trigger an interactive remote picker. 6. **Avoid branches shared across multiple stacks.** If a branch belongs to multiple stacks, commands exit with code 6. Check out a non-shared branch first. 7. **Plan your stack layers by dependency order before writing code.** Foundational changes (models, APIs, shared utilities) go in lower branches; dependent changes (UI, consumers) go in higher branches. Think through the dependency chain before running `gh stack init`. 8. **Use standard `git add` and `git commit` for staging and committing.** This gives you full control over which changes go into each branch. The `-Am` shortcut is available but should not be the default approachβ€”stacked PRs are most effective when each branch contains a deliberate, logical set of changes. 9. **Navigate down the stack when you need to change a lower layer.** If you're working on a frontend branch and realize you need API changes, don't hack around it at the current layer. Navigate to the appropriate branch (`gh stack down`, `gh stack checkout`, or `gh stack bottom`), make and commit the changes there, run `gh stack rebase --upstack`, then navigate back up to continue. +**Never do any of the following β€” each triggers an interactive prompt or TUI that will hang:** +- ❌ `gh stack view` or `gh stack view --short` β€” always use `gh stack view --json` +- ❌ `gh stack submit` without `--auto` β€” always use `gh stack submit --auto` +- ❌ `gh stack init` without branch arguments β€” always provide branch names +- ❌ `gh stack add` without a branch name β€” always provide a branch name +- ❌ `gh stack checkout` without an argument β€” always provide a PR number or branch name +- ❌ `gh stack checkout ` when a different local stack already exists on those branches β€” this triggers an unbypassable conflict resolution prompt; use `gh stack unstack` first to remove the local stack, then retry the checkout + ## Thinking about stack structure Each branch in a stack should represent a **discrete, logical unit of work** that can be reviewed independently. The changes within a branch should be cohesiveβ€”they belong together and make sense as a single PR. @@ -378,10 +395,10 @@ gh stack init --base main --adopt new-branch-1 new-branch-2 new-branch-3 ### Initialize a stack β€” `gh stack init` -Creates a new stack. Provide branch names as positional arguments. +Creates a new stack. **Always provide at least one branch name as a positional argument** β€” running without branch arguments triggers interactive prompts that agents cannot use. ``` -gh stack init [branches...] [flags] +gh stack init [flags] ``` ```bash @@ -415,16 +432,16 @@ gh stack init --adopt branch-a branch-b branch-c - Creates any branches that don't already exist (branching from the trunk branch) - In `--adopt` mode: validates all branches exist, rejects if any is already in a stack or has an existing PR - Checks out the last branch in the list -- Enables `git rerere` so conflict resolutions are remembered across rebases +- Enables `git rerere` so conflict resolutions are remembered across rebases. On first run in a repo, this may trigger a confirmation prompt β€” pre-configure with `git config rerere.enabled true` to avoid it --- ### Add a branch β€” `gh stack add` -Add a new branch on top of the current stack. Must be run while on the topmost branch (or the trunk if the stack has no branches yet). Always provide an explicit branch name. +Add a new branch on top of the current stack. Must be run while on the topmost branch (or the trunk if the stack has no branches yet). **Always provide a branch name** β€” running without one triggers an interactive prompt. ``` -gh stack add [branch] [flags] +gh stack add [flags] ``` **Recommended workflow β€” create the branch, then use standard git:** @@ -501,14 +518,10 @@ gh stack push --remote upstream ### Submit branches and create PRs β€” `gh stack submit` -Push all stack branches and create PRs on GitHub. - -``` -gh stack submit [flags] -``` +Push all stack branches and create PRs on GitHub. **Always pass `--auto`** β€” without it, `submit` prompts for a PR title for each new branch. ```bash -# Submit and auto-title new PRs +# Submit and auto-title new PRs (required for non-interactive use) gh stack submit --auto # Submit and create PRs as drafts @@ -517,7 +530,7 @@ gh stack submit --auto --draft | Flag | Description | |------|-------------| -| `--auto` | Auto-generate PR titles without prompting | +| `--auto` | Auto-generate PR titles without prompting (**required** for non-interactive use) | | `--draft` | Create new PRs as drafts | | `--remote ` | Remote to push to (use if multiple remotes exist) | @@ -578,7 +591,7 @@ gh stack sync [flags] Pull from remote and cascade-rebase stack branches. Use this when `sync` reports a conflict or when you need finer control (e.g., rebase only part of the stack). ``` -gh stack rebase [branch] [flags] +gh stack rebase [flags] [branch] ``` ```bash @@ -620,20 +633,16 @@ gh stack rebase --abort ### View the stack β€” `gh stack view` -Display the current stack's branches, PR status, and recent commits. Use `--json` for structured output. - -``` -gh stack view [flags] -``` +Display the current stack's branches, PR status, and recent commits. **Always pass `--json`** β€” without it, this command launches an interactive TUI that agents cannot operate. ```bash -# Structured JSON output (recommended) +# Always use --json gh stack view --json ``` | Flag | Description | |------|-------------| -| `--json` | Output stack data as JSON to stdout | +| `--json` | Output stack data as JSON to stdout (**required** for non-interactive use) | **`--json` output format:** @@ -682,8 +691,6 @@ Fields per branch: - `needsRebase` β€” whether the base branch is not an ancestor (non-linear history) - `pr` β€” PR metadata (omitted if no PR exists). `state` is `"OPEN"` or `"MERGED"`. -> **Note:** `--short` outputs a compact text view with box-drawing characters and status icons. Prefer `--json` for programmatic use. - --- ### Navigate the stack @@ -705,7 +712,7 @@ Navigation clamps to stack bounds. Merged branches are skipped when navigating f ### Check out a stack β€” `gh stack checkout` -Check out a stack from a pull request number or branch name. +Check out a stack from a pull request number or branch name. **Always provide an argument** β€” running `gh stack checkout` without arguments triggers an interactive selection menu. ``` gh stack checkout @@ -719,9 +726,11 @@ gh stack checkout 42 gh stack checkout feature-auth ``` -When a PR number is provided (e.g. `123`), the command fetches the stack on GitHub, pulls the branches, and sets up the stack locally. If the stack already exists locally and matches, it switches to the branch. If the local and remote stacks have different compositions, you'll be prompted to resolve the conflict by deciding whether to replace the local stack with the remote version or delete the remote stack and keep the local version. +When a PR number is provided (e.g. `123`), the command fetches the stack on GitHub, pulls the branches, and sets up the stack locally. If the stack already exists locally and matches, it switches to the branch. + +> **⚠️ Agent warning:** If the local and remote stacks have different branch compositions, this command triggers an interactive conflict-resolution prompt that cannot be bypassed with a flag. To avoid this: run `gh stack unstack` first to remove the conflicting local stack, then retry `gh stack checkout `. -When a branch name is provided, the command resolves it against locally tracked stacks only. +When a branch name is provided, the command resolves it against locally tracked stacks only. This is always safe for non-interactive use. --- @@ -730,7 +739,7 @@ When a branch name is provided, the command resolves it against locally tracked Tear down a stack so you can restructure it β€” remove a branch, reorder branches, rename branches, or make other large changes. After unstacking, use `gh stack init` to re-create the stack with the desired structure. ``` -gh stack unstack [branch] [flags] +gh stack unstack [flags] [branch] ``` ```bash