diff --git a/src/content/docs/stacks.mdx b/src/content/docs/stacks.mdx index d39fd06f97..c8610d4ca7 100644 --- a/src/content/docs/stacks.mdx +++ b/src/content/docs/stacks.mdx @@ -61,7 +61,7 @@ reviewers see the logical progression of your work. - One local branch (no juggling N branches for N PRs) - Automatic PR chaining with dependency tracking - Smart updates that only touch PRs that changed -- Standard Git, no new commands to learn +- Everyday Git for daily work: the commit and rebase commands you already use - Ships with skills for Claude Code, Cursor, and any agent supporting [skills.sh](https://skills.sh) - Complements [Merge Queue](/merge-queue) for safe, fast landing diff --git a/src/content/docs/stacks/compare/gh-stack.mdx b/src/content/docs/stacks/compare/gh-stack.mdx index bb153b18ae..990d4f2422 100644 --- a/src/content/docs/stacks/compare/gh-stack.mdx +++ b/src/content/docs/stacks/compare/gh-stack.mdx @@ -73,9 +73,9 @@ between them with `gh stack up` and `gh stack down`. | Push changes | `mergify stack push` | `gh stack push` | | Create PRs | Included in `mergify stack push` | Separate `gh stack submit` command | | View the stack | `mergify stack list` | `gh stack view` | -| Edit mid-stack | `mergify stack edit` (interactive rebase) | Checkout the branch, edit, rebase | +| Edit mid-stack | `mergify stack edit ` (targeted pause) | Checkout the branch, edit, rebase | | Reorder changes | `mergify stack reorder` or `mergify stack move` | Manual rebase + `gh stack rebase` | -| Squash changes | `mergify stack edit` (squash/fixup) | Manual | +| Squash changes | `mergify stack squash` or `mergify stack fixup` | Manual | | Cascading rebase | Automatic on push | `gh stack rebase --upstack` / `--downstack` | | Sync after merge | `mergify stack sync` | `gh stack sync` | | Open PR in browser | `mergify stack open` (interactive picker) | Links from `gh stack view` | @@ -83,7 +83,7 @@ between them with `gh stack up` and `gh stack down`. | Draft PRs | `mergify stack push --draft` | `gh stack submit --draft` | | Merge Queue | [Native Mergify integration](/merge-queue) | GitHub's built-in merge queue | | Merge a stack | Bottom-up via Merge Queue | `gh stack merge` (not yet implemented) | -| Stack visualization | Stack comment on each PR | Native GitHub UI stack map | +| Stack visualization | Stack comment + browser-extension panel | Native GitHub UI stack map | | Branch naming | Auto-generated ([configurable](/stacks/concepts#branch-mapping)) | Developer-chosen or auto-numbered | | Navigate between PRs | N/A (single branch) | `gh stack up` / `down` / `top` / `bottom` | | Unstack | Not needed (standard Git branches) | `gh stack unstack` | @@ -121,8 +121,10 @@ yet implemented. ## Where gh-stack Is Stronger **Native GitHub UI.** gh-stack gets a stack map rendered directly in the PR -interface. Mergify posts a stack comment on each PR, which works well but is -a comment rather than a native UI element. +interface. Mergify posts a stack comment on each PR and, with the +[browser extension](/merge-queue/browser-extensions) installed, renders the +stack and its revision history as an in-PR panel. Both work well, but neither +is a built-in GitHub UI element. ## Other Considerations diff --git a/src/content/docs/stacks/compare/graphite.mdx b/src/content/docs/stacks/compare/graphite.mdx index 33ea19234d..9866aabb06 100644 --- a/src/content/docs/stacks/compare/graphite.mdx +++ b/src/content/docs/stacks/compare/graphite.mdx @@ -78,11 +78,11 @@ between them with `gt up`, `gt down`, `gt top`, and `gt bottom`. | Create a stack | `mergify stack new` + commits | `gt create [name]` per branch | | Push changes | `mergify stack push` (rebase + push + PRs) | `gt submit` (force-push + PRs) | | View the stack | `mergify stack list` | `gt log` | -| Edit mid-stack | `mergify stack edit` (interactive rebase) | `gt modify` (auto-restacks) | +| Edit mid-stack | `mergify stack edit ` (targeted pause) | `gt modify` (auto-restacks) | | Absorb fixups | Not supported | `gt absorb` (auto-routes staged hunks) | | Split a commit | Not supported | `gt split` (by commit, hunk, or file) | -| Reorder changes | `mergify stack edit` (rebase -i) | `gt reorder` (interactive) | -| Squash / fold | `mergify stack edit` (squash/fixup) | `gt squash` / `gt fold` | +| Reorder changes | `mergify stack reorder` or `mergify stack move` | `gt reorder` (interactive) | +| Squash / fold | `mergify stack squash` or `mergify stack fixup` | `gt squash` / `gt fold` | | Undo | Git reflog | `gt undo` (reverts recent `gt` operations) | | Sync after merge | `mergify stack sync` | `gt sync` | | Navigate between PRs | N/A (single branch) | `gt up` / `down` / `top` / `bottom` | @@ -215,13 +215,13 @@ This installs the CLI and adds a `commit-msg` hook that generates | Graphite | Mergify Stacks | |---|---| | `gt create` (create a branch) | `git commit` (create a commit) | -| `gt modify` | `git commit --amend` or `mergify stack edit` | +| `gt modify` | `git commit --amend` or `mergify stack edit ` | | `gt submit` | `mergify stack push` | | `gt up` / `down` / `top` / `bottom` | Not needed (single branch) | | `gt restack` | Automatic on `mergify stack push` | | `gt sync` | `mergify stack sync` | | `gt log` | `mergify stack list` | -| `gt absorb` | `git commit --fixup` + `mergify stack edit` | +| `gt absorb` | No direct equivalent (amend each commit by hand) | ### Workflow before and after diff --git a/src/content/docs/stacks/reviewing.mdx b/src/content/docs/stacks/reviewing.mdx index 7b28c7aec1..1f247c1aa3 100644 --- a/src/content/docs/stacks/reviewing.mdx +++ b/src/content/docs/stacks/reviewing.mdx @@ -5,6 +5,7 @@ description: A reviewer's guide to navigating and reviewing stacked pull request import { Image } from 'astro:assets'; import StackComment from '../../images/stack-comment.png'; +import RevisionHistory from '../../images/stacks-revision-history.png'; Stacked PRs look and feel like regular pull requests, just smaller. You don't need to install anything or learn new tools to review them. @@ -55,6 +56,25 @@ Review comments work exactly like any other PR: When the author addresses your feedback, they'll rebase and push. The PR updates in place, and your review comments stay attached to the relevant lines. +## Revision History + +Each push keeps a revision-history comment on the PR, so you can see how the +commit evolved between reviews instead of guessing what changed since you last +looked. The timeline marks every revision, from the initial push through later +rebases and content edits, and links to the underlying commit SHAs: + +Mergify Stacks panel with the stack and its revision history timeline on a PR + +When the author amends a commit, they can attach a short note explaining why. +That reason shows up against the matching revision, so you don't have to diff +old and new SHAs to understand what moved. + +:::tip + The [Mergify browser extension](/merge-queue/browser-extensions) renders the + stack and its revision history directly in the GitHub pull request, as shown + above. +::: + ## Merging Stacked PRs Stacked PRs merge bottom-up. The first PR in the stack (targeting `main`) diff --git a/src/content/docs/stacks/setup.mdx b/src/content/docs/stacks/setup.mdx index faaeba6fdf..b92120a7bb 100644 --- a/src/content/docs/stacks/setup.mdx +++ b/src/content/docs/stacks/setup.mdx @@ -134,6 +134,7 @@ These optional Git config settings let you customize Stacks behavior: | `mergify-cli.stack-branch-prefix` | `stack/{username}` | Prefix for remote branch names | | `mergify-cli.stack-create-as-draft` | `false` | Create PRs as drafts by default | | `mergify-cli.stack-keep-pr-title-body` | `false` | Don't overwrite PR title/body on updates | +| `mergify-cli.stack-revision-history` | `true` | Keep a revision-history comment on each PR | Example: diff --git a/src/content/docs/stacks/updating.mdx b/src/content/docs/stacks/updating.mdx index 6d263af64c..a2dd76e855 100644 --- a/src/content/docs/stacks/updating.mdx +++ b/src/content/docs/stacks/updating.mdx @@ -9,8 +9,14 @@ After pushing a stack, you'll need to make changes: responding to review feedback, adding commits, rearranging order, or squashing. This page covers every common scenario. -In all cases, the workflow is the same: **make your changes locally, then run -`mergify stack push`** to sync with GitHub. +In all cases, the workflow is the same: **edit your stack locally, then run +`mergify stack push`** to sync with GitHub. Stacks ships dedicated commands for +every common history rewrite, so you don't have to drive `git rebase -i` by +hand. + +Each editing command accepts a commit as either a short SHA or a +[Change-Id](/stacks/concepts#change-id) prefix. Most of them also support +`--dry-run` (`-n`) to print the plan without touching your branch. ## Amend the Latest Commit @@ -31,31 +37,15 @@ Only the PR corresponding to the amended commit is updated. ## Edit a Commit Mid-Stack -To modify a commit that isn't at the top of your branch, use interactive rebase. -Stacks provides a shortcut: +To modify a commit that isn't at the top of your branch, point +`mergify stack edit` at it. Pass a short SHA or Change-Id prefix and the rebase +pauses on that commit: ```bash -mergify stack edit -``` - -This opens `git rebase -i` from the fork point of your stack. You'll see your -commits listed: - -```text -pick a1b2c3d feat: add user data model -pick d4e5f6a feat: add user registration endpoint -pick g7h8i9b test: add user registration tests -``` - -Change `pick` to `edit` for the commit you want to modify: - -```text -edit a1b2c3d feat: add user data model -pick d4e5f6a feat: add user registration endpoint -pick g7h8i9b test: add user registration tests +mergify stack edit a1b2c3d ``` -Save and close. Git pauses at that commit so you can make changes: +Git stops at the target so you can make changes: ```bash # Make your changes @@ -70,25 +60,42 @@ Then push: mergify stack push ``` +Only the amended commit's PR (and any later PRs whose content shifts) is +updated. + +## Reword a Commit Message + +To change a commit's message without touching its contents: + +```bash +mergify stack reword d4e5f6a -m "feat: add user registration API endpoint" +``` + +The Change-Id is preserved, so the PR keeps its identity. Because Stacks +derives the PR title and body from the commit message, the corresponding PR's +title and body update on the next push. + ## Reorder Commits -Open interactive rebase and change the line order: +List every commit in the order you want, by SHA or Change-Id prefix: ```bash -mergify stack edit +mergify stack reorder d4e5f6a a1b2c3d g7h8i9b ``` -```text -pick d4e5f6a feat: add user registration endpoint -pick a1b2c3d feat: add user data model -pick g7h8i9b test: add user registration tests +To move a single commit without listing the whole stack, use `move` with +`first`, `last`, `before`, or `after`: + +```bash +mergify stack move g7h8i9b first +mergify stack move a1b2c3d after d4e5f6a ``` -Save and close. The PRs re-chain automatically when you push. +The PRs re-chain automatically when you push. :::caution Reordering can cause conflicts if later commits depend on earlier ones. Git - will pause and ask you to resolve conflicts during the rebase. + pauses and asks you to resolve conflicts during the rebase. ::: ## Add a Commit @@ -105,42 +112,79 @@ correct position in the chain. ## Remove a Commit -Open interactive rebase and change `pick` to `drop` (or delete the line): +Drop one or more commits by SHA or Change-Id prefix: + +```bash +mergify stack drop d4e5f6a +``` + +On push, the orphan remote branch is deleted and the remaining PRs re-chain. + +## Squash or Fixup Commits + +To fold a commit into its parent and **drop** its message, use `fixup`: + +```bash +mergify stack fixup g7h8i9b +``` + +To combine commits into a target while **keeping** the target's message, use +`squash`. Sources go before the `into` token, the target after it: ```bash -mergify stack edit +mergify stack squash d4e5f6a into a1b2c3d ``` -```text -pick a1b2c3d feat: add user data model -drop d4e5f6a feat: add user registration endpoint -pick g7h8i9b test: add user registration tests +Pass `-m` to rewrite the resulting message instead of keeping the target's: + +```bash +mergify stack squash d4e5f6a into a1b2c3d -m "feat: add user model and endpoint" ``` -On push, the orphan remote branch is deleted and the remaining PRs re-chain. +The surviving commit keeps its Change-Id, so the corresponding PR is updated. +The absorbed commit's remote branch is cleaned up automatically. -## Squash Commits +## Preview Before You Rewrite -To combine two commits into one, use `squash` or `fixup` in interactive rebase: +The history-rewriting commands (`reword`, `reorder`, `move`, `drop`, `fixup`, +`squash`) accept `--dry-run` (`-n`) to print the resulting plan without changing +your branch: ```bash -mergify stack edit +mergify stack reorder d4e5f6a a1b2c3d g7h8i9b --dry-run ``` -```text -pick a1b2c3d feat: add user data model -squash d4e5f6a feat: add user registration endpoint -pick g7h8i9b test: add user registration tests +## Record Why You Amended + +When you amend a commit that already has a PR, reviewers see a new revision but +not the reason behind it. Attach a note before pushing to explain the change: + +```bash +git commit --amend +mergify stack note -m "address review: rename foo() to bar()" +mergify stack push ``` -The surviving commit keeps its Change-Id, so the corresponding PR is updated. The -absorbed commit's remote branch is cleaned up automatically. +The note travels with the stack and appears in the PR's revision history, so +reviewers understand what changed between revisions without diffing SHAs. See +[Reviewing Stacks](/stacks/reviewing#revision-history) for the reviewer's view. + +By default, `mergify stack push` keeps a revision-history comment on each PR up +to date. Pass `--no-revision-history` (or set +`mergify-cli.stack-revision-history` to `false`) to turn it off. ## After a PR Merges -When the bottom PR in your stack merges into `main`, the next PR's base -automatically updates to `main`. To keep your local branch in sync, just push -again: +When the bottom PR in your stack merges into `main`, bring your local branch +back in sync: + +```bash +mergify stack sync +``` + +`sync` fetches the latest `main`, detects which commits already merged, drops +them from your branch, and rebases the rest. Then push to update the remaining +PRs: ```bash mergify stack push @@ -169,5 +213,5 @@ After PR #1 merges, commit A lands on `main`. The remaining PRs re-chain: ]} /> -Stacks rebases on `main` automatically, detects that the merged commit is already -in `main`, and skips it. The remaining PRs update as needed. +`sync` rebases on `main`, detects that the merged commit is already there, and +skips it. The remaining PRs update as needed on the next push. diff --git a/src/content/images/stack-comment.png b/src/content/images/stack-comment.png index 8e2c99474d..9a2ddae9f5 100644 Binary files a/src/content/images/stack-comment.png and b/src/content/images/stack-comment.png differ diff --git a/src/content/images/stacks-revision-history.png b/src/content/images/stacks-revision-history.png new file mode 100644 index 0000000000..e2d17baac1 Binary files /dev/null and b/src/content/images/stacks-revision-history.png differ