Command Palette

Search for a command to run…

ZarynZaryn
Code hosting and version control·3 min read·

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.

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).