View as Markdown

Concepts

How Mergify Stacks maps Git commits to GitHub pull requests.


You work on one local branch with multiple commits. Mergify Stacks maps each commit to its own GitHub pull request. The PRs are chained together: each one’s base branch is the previous PR’s head branch.

main A B C PR #1 base: main PR #2 base: PR #1 PR #3 base: PR #2

Reviewers see one small, focused diff per PR instead of the accumulated changes of the entire branch.

When you run mergify stack push, each commit goes through three stages:

Local CommitsRemote BranchesGitHub PRs A: add model stack/.../add-model--a1b2c3d4 PR #1 B: add endpoint stack/.../add-endpoint--d4e5f6a7 PR #2 C: add tests stack/.../add-tests--b7c8d9e0 PR #3

Your local commits become remote branches, and each remote branch becomes a pull request. The Change-Id in each commit message is what ties all three together.

The Change-Id connects your local commits to their corresponding pull requests. It’s a unique identifier embedded as a Git trailer in each commit message:

feat: add user authentication
Implement JWT-based auth with refresh tokens.
Change-Id: Ia1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2

The Change-Id is:

  • Generated automatically by a commit-msg Git hook installed during setup

  • Persistent across rebases, amends, and history rewrites

  • The mapping key that Stacks uses to know which commit corresponds to which PR, even after you rewrite your branch

You never need to manage Change-Ids manually. They’re created once and preserved through all git operations.

When you run mergify stack push, each commit gets its own remote branch. The naming convention is:

stack/{username}/{branch-name}/{commit-slug}--{change-id}

{commit-slug} is derived from the commit title: the conventional commit prefix is stripped, stop words are removed, and common words are abbreviated. {change-id} is the first 8 hex characters of the commit’s Change-Id, which keeps names unique when commit titles repeat.

For example, if user alice pushes a branch called feat/auth with 3 commits:

Commit titleRemote Branch
feat: add user data modelstack/alice/feat/auth/add-user-data-model--a1b2c3d4
feat: add registration endpointstack/alice/feat/auth/add-registration-endpoint--d4e5f6a7
test: add registration testsstack/alice/feat/auth/add-registration-tests--b7c8d9e0

Readable branch names make git branch -a, gh pr list, and GitHub’s branch dropdown easier to scan.

You can customize the branch prefix via Git config:

Terminal window
git config mergify-cli.stack-branch-prefix "my-prefix"

Each PR targets the previous PR’s branch as its base, creating a dependency chain:

CommitPR BasePR Head
A (first)main.../add-user-data-model--a1b2c3d4
B (second).../add-user-data-model--a1b2c3d4.../add-registration-endpoint--d4e5f6a7
C (third).../add-registration-endpoint--d4e5f6a7.../add-registration-tests--b7c8d9e0

Stacks also adds a Depends-On: #NNN reference in each PR description and posts a stack comment on every PR listing the full chain:

Stack comment showing all PRs in the chain

The stack comment shows where each PR sits in the chain, with links to jump between them. This gives both authors and reviewers a clear map of the entire change.

When you push again after making changes, Stacks doesn’t recreate everything. It compares each commit’s Change-Id and SHA against what’s already on GitHub:

  • Changed commits get their PR updated (force-push to the remote branch)

  • Unchanged commits are skipped entirely

  • Removed commits (after squashing or dropping) get their orphan remote branches deleted automatically

mergify stack push is always safe to run. It only does the minimum work needed to sync your local branch with GitHub.

See Setup to install the CLI and configure your repository.

Was this page helpful?