> ## Documentation Index
> Fetch the complete documentation index at: https://docs.reasonos.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Stacked branches

> Work in stacks of small, dependent branches with rbs stack — create, restack, absorb review feedback, and submit one change request per branch.

A **stack** is a chain of branches, each built on the one below it. Instead of one
large change request, you send several small ones that review and land in order —
and rbs keeps them sitting on top of each other while they do.

```text theme={null}
◯ add-ssh-client      #355  draft
│
◉ add-hpc-dashboard   #351  open · needs restack
│
◯ add-hpc-module      #350  merged
│
┴ main (trunk)
```

rbs records each branch's parent **in git itself** (under `refs/branch-metadata/`),
not in a service or a local database. That has three consequences you'll feel every
day:

* **A clone carries its stacks.** Push a stack and any teammate, CI runner, or
  branch node reconstructs the same graph — no account, no extra server round-trip.
* **The whole stack survives you switching machines** — `rbs stack get` rebuilds it
  from the refs alone.
* **Your teammates and the control plane see the same graph you do**, because
  `rbs stack submit` pushes the metadata along with the branches.

<Tip>
  `rbs st` is an alias for `rbs stack`, and the common subcommands have short forms
  too: `rbs st c` (create), `rbs st m` (modify), `rbs st l` (log), `rbs st co`
  (checkout).
</Tip>

## Set up once per clone

```bash theme={null}
rbs stack init
```

This records which branch is trunk (guessed from the remote's HEAD when you don't
name one) and, optionally, which control-plane project this repository maps to so
that `rbs stack submit` can open change requests:

```bash theme={null}
rbs stack init main --remote origin \
  --control-plane https://hub.example.com --project my-service
```

## The daily loop

```bash theme={null}
rbs stack create add-api -m "Add the API"     # branch off the current one and commit
rbs stack create add-ui  -m "Add the UI"      # stack another branch on top
rbs stack log                                 # see the stack
rbs stack modify -a                           # amend, then restack everything above
rbs stack sync                                # pull trunk, drop what landed, restack
rbs stack submit --stack                      # push + one change request per branch
```

### A worked example

Say you're adding an HPC dashboard, and the work naturally splits into a module, a
dashboard that uses it, and an SSH client on top.

<Steps>
  <Step title="Build the stack, one small branch at a time">
    ```bash theme={null}
    git checkout main
    rbs stack create add-hpc-module -a -m "Add the HPC module"
    # ...write the dashboard on top of it...
    rbs stack create add-hpc-dashboard -a -m "Add the HPC dashboard"
    # ...and the SSH client on top of that...
    rbs stack create add-ssh-client -a -m "Add the SSH client"
    ```

    Each `create` branches off the branch you're standing on, so the three branches
    form a chain over trunk. `rbs stack log` draws it; `rbs stack ls` lists it one
    line per branch.
  </Step>

  <Step title="Submit the whole stack for review">
    ```bash theme={null}
    rbs stack submit --stack
    ```

    Bottom-up, every branch is pushed and gets its own change request — each one
    targeting the branch *below* it, not trunk. That is what makes each request one
    small reviewable diff: the top branch shows only its own change, not the sum of
    all three. `rbs stack diff` shows you the same parent-relative diff a reviewer
    sees.
  </Step>

  <Step title="Respond to review feedback on a lower branch">
    A reviewer asks for a change in the HPC module — the *bottom* branch. Make the fix
    anywhere in the stack, stage it, and let rbs place it:

    ```bash theme={null}
    git add -p
    rbs stack absorb --dry-run   # show where each hunk would land
    rbs stack absorb             # amend it into the branch that owns those lines
    ```

    `absorb` figures out which downstack branch introduced the lines each staged hunk
    touches, amends that branch, and restacks everything above it. The feedback lands
    in the change request being reviewed instead of as a "fix review comments" commit
    on top of the stack. A hunk that could belong to more than one branch stays
    staged, with the reason listed.

    Alternatively, if you know exactly where a fix belongs:

    ```bash theme={null}
    rbs stack modify --into add-hpc-module
    ```
  </Step>

  <Step title="Land from the bottom, then sync">
    The module's change request merges. Now:

    ```bash theme={null}
    rbs stack sync
    ```

    `sync` fast-forwards trunk from the remote, refreshes what each branch's change
    request says, deletes branches whose changes are already in trunk (reparenting
    whatever was stacked on them), and restacks the rest. The dashboard branch now
    sits directly on trunk; the SSH client sits on the dashboard. Repeat until the
    stack is empty.

    A branch counts as landed when its **content** is in trunk — squash- and
    rebase-merges included, which plain commit ancestry would miss.
  </Step>
</Steps>

## Keeping a stack healthy

### Amending: `modify`

```bash theme={null}
rbs stack modify -a              # stage everything, amend, restack upstack
rbs stack modify -c -m "wip"     # add a new commit instead of amending
```

`modify` always restacks the branches above the one you amended. That is not
optional: leaving the branches above pointing at a commit that no longer exists is
how a stack rots.

### Conflicts: `continue` and `abort`

A restack that hits a conflict stops and tells you. Resolve the files in your
editor — even hours later; the paused restack survives the process ending — then:

```bash theme={null}
rbs stack continue --all   # stage everything and carry on
rbs stack abort            # unwind the rebase and stop
```

### Mistakes: `undo`

```bash theme={null}
rbs stack undo --dry-run   # show what would be restored
rbs stack undo             # restore branches + metadata to before the last mutation
```

`undo` never deletes commits — branches created since are kept, just untracked.
Running `undo` again redoes.

### Testing every branch: `test`

```bash theme={null}
rbs stack test 'rbs build //...'
rbs stack test --downstack --fail-fast 'rbs build //... && rbs query //...'
```

This checks out each branch in scope in turn and runs the command there — the way
to ask "does every change request in this stack pass on its own?". The branch you
started on is restored afterwards.

## Scope flags

Most stack-wide commands (`submit`, `restack`, `test`) take the same four scope
flags:

| Flag          | Applies to                          |
| ------------- | ----------------------------------- |
| `--stack`     | the whole stack                     |
| `--upstack`   | this branch and everything above it |
| `--downstack` | this branch and everything below it |
| `--branch`    | this branch only                    |

## Full command surface

|              |                                                                        |
| ------------ | ---------------------------------------------------------------------- |
| **Build**    | `create`, `modify`, `squash`, `split`, `edit` (interactive rebase)     |
| **Move**     | `restack`, `sync`, `move`, `reorder`, `fold`, `pop`                    |
| **Navigate** | `log`, `ls`, `info`, `diff`, `checkout`, `up`, `down`, `top`, `bottom` |
| **Graph**    | `track`, `untrack`, `rename`, `delete`                                 |
| **Share**    | `submit`, `get`                                                        |
| **Recover**  | `continue`, `abort`, `undo`                                            |

Two worth calling out:

* `rbs stack get <branch>` fetches a branch **and every branch below it**,
  reconstructing the stack from the metadata the submitter pushed. If your local
  copy of a branch has truly diverged from the remote, `get` refuses unless you
  pick `--rebase` (replay your commits on top) or `--overwrite` (discard your
  copy).
* `rbs stack log --json` emits the stack as a document, so scripts and agents can
  read the graph without scraping the drawing.

## What `submit` does, precisely

For each branch in scope, bottom-up, `rbs stack submit`:

1. pushes the branch (with a lease — a restacked branch has rewritten history by
   definition, but rbs will not clobber remote work it hasn't seen unless you pass
   `--force`),
2. opens or updates a **ReasonOS change request** targeting the branch below it,
3. records the request number in the branch's metadata,

then pushes the metadata so everyone sees the same graph. Useful variants:

```bash theme={null}
rbs stack submit --stack --draft          # open new requests as drafts
rbs stack submit --publish                # take existing drafts out of draft
rbs stack submit --update-only            # never open new requests
rbs stack submit --dry-run                # show what would happen, change nothing
```

Every branch must be restacked before submitting: a change request whose base has
moved shows a diff nobody wrote.

Two things to know:

* `submit` needs a control plane to open change requests in. Configure one with
  `rbs stack init --control-plane <url> --project <name>`, or set
  `RBS_CONTROL_PLANE_URL` and `RBS_PROJECT_NAME`.
* By default `submit` applies **downstack** — this branch and everything below
  it. Pass `--stack` to submit the whole stack from anywhere in it.

## Stacks and branch nodes

ReasonOS runs [one server per branch](/workflow/task-board#tasks-travel-with-the-branch):
each active branch gets its own branch node, and the editor connects to it. A
stack is therefore a chain of workspaces, not just a chain of refs — and because
the stack graph lives in git, every node in the chain (and the control plane,
which reads the same refs from its mirror) sees the same picture without any extra
coordination. Creating a stack with `rbs stack create` is also how you get a node
per reviewable unit of work: small branches mean small diffs *and* focused
workspaces.
