# Stacked changes

> Split big work into a chain of small branches, each on the one below. zev stack restacks them together after an edit, pushes them as one pull request each, and cleans up as they merge.

Source: https://zaryn.xyz/docs/en/stacked-changes

Big changes are hard to review. Split them into small steps that build on each other, for example the API, then the page that uses it, then the docs, and reviewers can take one at a time. That's a **stack**: a chain of branches where each one starts from the one below.

```diagram
type: history
title: A stack of three branches on main
start: main
---
branch main | accent
branch api | | from A
branch ui | | from B
branch docs | | from C
commit A main | Base
commit B api | API endpoint | info Pull request 1: api → main
commit C ui | UI page | info Pull request 2: ui → api
commit D docs | Docs | info Pull request 3: docs → ui
```

## Build one

```bash
zev stack add api        # a new branch on top of where you are, and you're on it
# …commit…
zev stack add ui         # the next one, on top of api
# …commit…
zev stack                # the whole stack: each branch, its commits, where you are
```

```text
Stack api on main, newest on top
  ▶ ui   1 commit: UI page  (you're here)
    api  1 commit: API endpoint
    main
```

`zev stack up`, `down`, `top` and `bottom` move along it.

## Change a lower branch: zev stack restack

A reviewer asks for a fix in `api`. Go down, commit the fix, and run `zev stack restack`. zev rebases each branch above onto the new version of the one below it, replaying only that branch's own commits. That's the step that goes wrong by hand in Git, where rebasing `docs` after `ui` changed replays `ui`'s old commits again unless you remember `git rebase --onto`.

```bash
zev stack bottom
# …fix and commit…
zev stack restack
✓ ui is back on top of api
✓ docs is back on top of ui
```

The whole restack is one operation, so one `zev undo` takes all of it back. If a branch conflicts, restack stops there and says which branch and what to do. Everything below it stays restacked.

## Review: zev stack push

```bash
zev stack push
✓ #12 api → main   opened
✓ #13 ui → api     opened
✓ #14 docs → ui    opened
```

Each branch is pushed and gets its own pull request, aimed at the branch below it, so each one shows only its own change. Every description lists the whole stack and marks which one you're looking at. Push again after changes and the same pull requests are updated: zev replaces its stack list and keeps whatever you wrote above it.

## Merge from the bottom: zev stack sync

Merge the bottom pull request first. Then:

```bash
zev stack sync
✓ api is merged into main: taken out of the stack
zev stack push
✓ #13 ui → main    retargeted
```

`sync` pulls the base, takes merged branches out of the stack (and deletes them locally), and restacks the rest onto the base. The next `push` points the next pull request at `main`. Repeat until the stack is empty.

## Commands

```text
zev stack                         the stack you're on
zev stack add <name>              a new branch on top of this one
zev stack up | down | top | bottom
zev stack restack                 every branch back onto the one below it
zev stack sync                    pull the base, drop merged branches, restack
zev stack push                    push all, one pull request each
zev stack remove [<name>]         take a branch out of its stack (it stays as a branch)
zev stack list                    every stack here
```

All of them take `--json` and `--brief`. An agent can split its own work into a reviewable stack and read the state of the stack in one line:

```text
$ zev stack --brief
stack api on main: api(2) > ui*(1,restack) > docs(1)
```

## How this differs from Git

Git has the pieces (`branch`, `rebase --onto`, a separate tool to open pull requests) but nothing that knows the branches belong together. You track the order yourself, rebase each branch by hand, retarget pull requests by hand after a merge, and one wrong `rebase` duplicates commits. In zev the stack is part of the repository, restack does every branch at once and correctly, and push and sync keep the pull requests in step.

See also: [Branches and merging](/docs/en/branches), [Undo anything](/docs/en/undo).
