Skip to content

Stacked changes

A stack is a chain of feature branches where each one builds on the one below it instead of on the trunk. You split a large change into reviewable pieces, keep working on top of code that hasn't merged yet, and let git-city keep the whole tower consistent for you.

git-city makes stacks first-class. Every feature records its parent in Git config, so a stack is just a path down the branch tree rooted at your trunk. You don't track that relationship by hand — new --onto writes it, tree shows it, sync --all respects it, and land repairs it.

Note

If the parent/trunk idea is new to you, read the mental model first. The short version: a trunk is long-lived and never rebased; a feature is everything you work on and it knows its parent. A stack is several features parented onto each other.


Build the stack

Start the bottom branch off the trunk, then stack each new branch onto the previous one with --onto.

git city new api
# ... work, commit ...
git city new ui --onto api
# ... work, commit ...

git city new api creates api off the trunk (main), records main as its parent, and checks it out. git city new ui --onto api then creates ui, records api as its parent, and checks ui out. You now have a two-deep stack: mainapiui.

Command What it does
git city new <name> Branch off the trunk; parent is the trunk.
git city new <name> --onto <branch> Stack <name> onto <branch>; parent is <branch>.

Tip

new moves commits, so it refuses to run on a dirty working tree — commit or stash first. Add --dry-run to any command on this page to print the exact git commands it would run without executing anything.

new


See the shape

git city tree prints the hierarchy as an indented tree. The current branch is marked with a filled dot, and each feature shows how far ahead/behind it is versus its parent.

git city tree
main  (trunk)
└─ api  ↑3 ↓0
   └─ ● ui  ↑2 ↓0

Here api has 3 commits on top of main, and ui has 2 commits on top of api. The shows you're currently on ui. The tree is read-only — it never touches your branches.

tree


Sync the whole stack

When the trunk moves on, the whole stack needs to be rebased back on top of it — and each branch needs to be rebased on top of its (now-updated) parent, in order. git city sync --all does exactly that: it syncs every feature parents before children (topological order), updating each trunk once.

git city sync --all

For each feature this fetches, brings the parent up to date (recursively), rebases the feature onto its parent — first absorbing any commits the remote has that you don't — and force-pushes with --force-with-lease. Doing it parent-first means api is settled before ui rebases onto it, so the stack stays coherent from the bottom up.

Warning

A rebase can hit a conflict. sync is resumable: it pauses, leaves the rebase in progress, and tells you what to do. Resolve the conflict, git add, then git city continue — or git city abort to roll the whole thing back to where it started.

You can also sync a single branch by name (git city sync api); without --all only that branch and its ancestors are brought up to date.

sync · conflicts


Land the bottom branch

When the bottom of the stack is ready to merge, land it. git city land fast-forwards the parent to the feature's tip (history stays linear), re-homes the feature's children onto the parent, and pushes the parent. It keeps the landed feature (tagged landed) so you can keep working on it; prune removes landed branches later, or land --delete removes it immediately.

Re-homing is the part that keeps a stack alive: when you land api into main, ui's parent is automatically changed from api to main. The next sync rebases ui cleanly onto the trunk.

git city land api

After landing api, the tree collapses by one level:

main  (trunk)
└─ ● ui  ↑2 ↓0

Note

land refuses if the feature is behind its parent — run git city sync first so the fast-forward is possible. Land the stack from the bottom up: land api, then once ui is reviewed, land ui.

land


The whole loop

git city new api               # bottom of the stack, off main
git city new ui --onto api      # stacked on api
git city tree                   # check the shape
git city sync --all             # rebase the whole stack on the latest trunk
git city land api               # merge the bottom; ui re-homes onto main

That's the full stacked workflow: branch, stack, view, sync, land — with git-city tracking parents, ordering the rebases, and repairing the tree so you never hand-edit the lineage.