Guillermo Pérez
04/14/2026, 8:52 AM⏺ gh-stack uses two complementary mechanisms:
1. PR Base Branch Targeting (the foundation)
Each PR's base is set to the previous PR's head branch, forming a chain:
main
└─ branch-1 → PR #1 (base: main)
└─ branch-2 → PR #2 (base: branch-1)
└─ branch-3 → PR #3 (base: branch-2)
This is what makes GitHub show the correct diff (only changes from that slice of work, not the whole
stack).
2. GitHub's Native Stacks API (the registration)
After PRs are created, the tool registers the stack with GitHub's dedicated (private-preview) REST
endpoint:
POST /repos/{owner}/{repo}/cli_internal/pulls/stacks
Body: { "pull_request_numbers": [101, 102, 103] }
GitHub validates that the PRs actually form a valid base→head chain and returns a stackID. This is
what enables the native stack UI on GitHub.
The relevant code is in internal/github/github.go — look for CreateStack, UpdateStack, DeleteStack,
and ListStacks.
Local state
A .git/gh-stack JSON file (not committed) tracks which branches belong to the stack, their ordering,
the server-assigned stackID, and per-branch HEAD SHAs for rebase tracking.
It would be really great if graphite could call this api to leverage github stacks UI, and gt can also create the local state gh-stack needs so they can coexist.Pylon
04/14/2026, 12:49 PM