The shape of it
A stack is an ordered line of changes belonging to one repository and one base branch. A change is one unit of work that names the change it sits on top of. A revision is one push to a change.
Stack: "Search pipeline" (yourhandle/project onto main)
#3 Rank results by recency r1 draft
|
#2 Plan index scans r1 r2 open
|
#1 Tokenize search queries r1 r2 r3 open
|
mainRead it from the bottom. Change #1 sits on main. Change #2 sits on #1 and assumes #1 exists. Change #3 sits on #2.
Why stack at all
Because review quality collapses with size, and because waiting is expensive. If you write four hundred lines and wait for one review, you are blocked for a day and your reviewer skims. If you write four changes of a hundred lines, the first can be reviewed while you write the second.
Every tool lets you do this in principle, by opening four pull requests that depend on each other by hand and rebasing them all whenever one changes. Nobody does it, because it is miserable. Branchwork tracks the parent for you, which is the entire difference.
Changes
A change has:
- A title and a summary, taken from the commit subject and body when you submit from the terminal.
- An author. Only the author can push to it or change its state.
- A parent, which is the change below it, or nothing if it is the bottom of the stack.
- A state: draft, open, merged, or abandoned.
- One or more revisions.
States
- draft - not ready. Push freely.
- open - asking for review.
- merged - it landed. Only possible when everything below it has merged.
- abandoned - it will not land. Kept, because the review is a record.
Revisions
Every push creates a revision, numbered from r1. Revisions are never overwritten and never deleted, which is what makes review history meaningful: a review that covered r2 still means something after r3 lands.
A revision stores the full contents of the files that push touched. Files it did not touch carry forward from the previous revision, so a revision always describes the whole change, not a delta you have to reassemble.
Pushing content identical to the current head does not create a revision. Branchwork says unchanged and moves on, because an empty revision would make somebody's incremental diff blank for no reason.
Merging is ordered
A change can only be marked merged when every change below it in the stack is merged already. This is checked on the server, not just hidden in the interface, so it holds whether you use the website, the command line tool, or the API directly.
If you need to land change #2 before #1, the honest answer is that #2 did not depend on #1 and should not have been stacked on it. Abandon and resubmit it at the bottom.
How commits map to changes
One commit is one change. The link between them is a trailer written into the commit message:
Tokenize search queries The old splitter broke on quoted phrases. Change-Id: chg_b9d22681-753
This exists because rebasing rewrites every commit hash in your stack. Without a stable id, Branchwork could not tell a rebased commit from a brand new one, and every rebase would create duplicate changes and orphan their reviews.
bw submit adds the trailer for you the first time. Running bw init installs a commit hook that adds it as you commit, which is tidier because then nothing has to be rewritten afterwards.
Rebasing
When the base branch moves, or when a change below yours merges, rebase and repush:
$ bw sync Fetching... Rebasing onto main... ok Rebased. Pushing what moved... 3f9a1c2b unchanged Tokenize search queries 7ce4d0a1 pushed to chg_7d2c Plan index scans
bw sync refuses to run with uncommitted changes. This is not negotiable and there is no flag to skip it: a tool that runs a rebase over your uncommitted work and loses it is worse than no tool at all.
If the rebase hits a conflict it stops, exactly as git would. Resolve it, run git rebase --continue, then run bw submit. To back out entirely, run git rebase --abort.
Languages
A stack page shows what it is written in, measured by bytes across the head revision of every change in it. Detection is by file extension and covers the everyday languages alongside COBOL, Fortran, Ada, JCL, Prolog, and a fair number of esoteric ones. If you push Brainfuck, it will say Brainfuck.
Anything unrecognized is grouped as Other rather than guessed at. If a language you use is missing, tell us and we will add it.
