# Branch a world

A variant for a feature, a teammate, a CI shard.

This page is executed as written by `packages/cli/src/journeys/tutorials.test.ts`; the recording
is made from the same run.

![Branch a world, recorded](../media/branch-a-world/branch-a-world.gif)

## The app

```json file=package.json
{ "name": "acme-web", "private": true, "dependencies": { "stripe": "^17" } }
```

```text file=.env.example
STRIPE_SECRET_KEY=
```

```js file=signup.mjs
import Stripe from 'stripe';

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
const customer = await stripe.customers.create({ email: 'ada@example.com', name: 'Ada' });
console.log(`created ${customer.id}`);
```

```bash
npm install
npm install -g @volter/world
npm install -D @volter/twin-stripe
volter world init
volter world up
volter world run -- node signup.mjs
```

```text
created cus_twin_1
```

## Make one

```bash
volter world branch payments-v2
```

```text
branch  payments-v2  from main
```

The new branch starts exactly where the one you were on stands: the same history, the customer
included. It is a pointer into that history, not a copy, and it records its own changes from
here, so what your app does on it stays on it. The new branch is checked out and running; the
old one stopped.

```bash
volter world log
volter world diff
```

```text
stripe   customer.create   customer:cus_twin_1
stripe   event.record     event:evt_twin_1
0 changes since branch payments-v2
```

`volter world branch` with no name lists the branches and marks the current one:

```bash
volter world branch
```

```text
  acme-web
* payments-v2
```

## Switch

```bash
volter world checkout acme-web
```

```text
Switched to branch acme-web
```

`checkout` stops the branch you are on and resumes the one you name, with its state intact. One
branch runs at a time in a world, because your app's env names one set of twins.

```bash
volter world status
```

```text
World acme-web on branch acme-web: running
  branches:  *acme-web payments-v2
```

```bash
volter world log
```

```text
stripe customer.create customer:cus_twin_1
```

## What a branch is for

- **A feature.** Develop against a branch, break its data freely, `volter world reset` it or
  delete it when the feature ships. The main branch keeps the state you rely on.
- **A test suite.** Give a suite that needs specific data its own branch and never reset the
  branch you develop on.
- **A CI shard.** Each shard is its own checkout, so each shard's branch is its own world; see
  [use in CI](./use-in-ci.md).
- **A teammate.** Two people cloning the same remote each get their own local branches over the
  same history; nothing is shared until one of them pushes.

## Carry changes across

Changes made on one branch do not appear on another. To move them, cut a changeset on the source
branch and replay it into the target:

```bash
volter world changeset -m "Ada's signup"
```

```text
changeset  adas-signup  2 changes
```

```bash
volter world replay adas-signup --into payments-v2
volter world checkout payments-v2
volter world log
```

```text
stripe customer.create customer:cus_twin_1
```

Replay feeds the recorded writes back through the target's twins, in order, with the same ids,
so replaying twice is a no-op.

## Delete one

`--branch` acts on a branch other than the checked-out one; `--purge` deletes its data. The
branch's name is free again.

```bash
volter world checkout acme-web
volter world down --purge --branch payments-v2
```

```text
Stopped payments-v2 (state forgotten)
```

```bash
volter world branch
```

```text
* acme-web
```

## Branch as it was

A branch can start from any point in the history, not only the head: an instant, or a position
per twin. The branch references that position in its parent’s history. Keep the parent available
while the branch depends on it. Pin
the clock so the instants are known, make two more customers an hour apart, and branch from the
half hour between them.

```bash
volter world clock set 2027-01-01T09:00:00Z
volter world run -- node signup.mjs
volter world clock set 2027-01-01T10:00:00Z
volter world run -- node signup.mjs
volter world branch as-of-nine-thirty --at 2027-01-01T09:30:00Z
volter world log | grep -c customer.create
```

```text
branch  as-of-nine-thirty  from main  at 2027-01-01T09:30:00Z
2
```

The branch holds the first two customers and not the third. `--at github@12,jira@7` names a
position per twin instead of an instant; `volter world log --json` shows every entry's position.

A World served to a browser (`volter world view`, a host, or the hosted product) has the same on its
dashboard's **Branches** page: **New branch** makes one as of now or a moment you pick, for as long
as you say, and opens it read-only in that tab. Each branch's menu compares it with its parent (what
it changed since it branched), resets it to its parent as it is now, or deletes it.

```bash
volter world down
```

<!-- playback:BEGIN — GENERATED by `bun scripts/docs-media.ts`; do not edit between markers -->

## Playback

Each command above, as the recording shows it.

<details><summary><code>npm install</code></summary>

![step 1](../media/branch-a-world/step-01.png)

</details>
<details><summary><code>npm install -g @volter/world</code></summary>

![step 2](../media/branch-a-world/step-02.png)

</details>
<details><summary><code>npm install -D @volter/twin-stripe</code></summary>

![step 3](../media/branch-a-world/step-03.png)

</details>
<details><summary><code>volter world init</code></summary>

![step 4](../media/branch-a-world/step-04.png)

</details>
<details><summary><code>volter world up</code></summary>

![step 5](../media/branch-a-world/step-05.png)

</details>
<details><summary><code>volter world run -- node signup.mjs</code></summary>

![step 6](../media/branch-a-world/step-06.png)

</details>
<details><summary><code>volter world branch payments-v2</code></summary>

![step 7](../media/branch-a-world/step-07.png)

</details>
<details><summary><code>volter world log</code></summary>

![step 8](../media/branch-a-world/step-08.png)

</details>
<details><summary><code>volter world diff</code></summary>

![step 9](../media/branch-a-world/step-09.png)

</details>
<details><summary><code>volter world branch</code></summary>

![step 10](../media/branch-a-world/step-10.png)

</details>
<details><summary><code>volter world checkout acme-web</code></summary>

![step 11](../media/branch-a-world/step-11.png)

</details>
<details><summary><code>volter world status</code></summary>

![step 12](../media/branch-a-world/step-12.png)

</details>
<details><summary><code>volter world log</code></summary>

![step 13](../media/branch-a-world/step-13.png)

</details>
<details><summary><code>volter world changeset -m "Ada's signup"</code></summary>

![step 14](../media/branch-a-world/step-14.png)

</details>
<details><summary><code>volter world replay adas-signup --into payments-v2</code></summary>

![step 15](../media/branch-a-world/step-15.png)

</details>
<details><summary><code>volter world checkout payments-v2</code></summary>

![step 16](../media/branch-a-world/step-16.png)

</details>
<details><summary><code>volter world log</code></summary>

![step 17](../media/branch-a-world/step-17.png)

</details>
<details><summary><code>volter world checkout acme-web</code></summary>

![step 18](../media/branch-a-world/step-18.png)

</details>
<details><summary><code>volter world down --purge --branch payments-v2</code></summary>

![step 19](../media/branch-a-world/step-19.png)

</details>
<details><summary><code>volter world branch</code></summary>

![step 20](../media/branch-a-world/step-20.png)

</details>
<details><summary><code>volter world clock set 2027-01-01T09:00:00Z</code></summary>

![step 21](../media/branch-a-world/step-21.png)

</details>
<details><summary><code>volter world run -- node signup.mjs</code></summary>

![step 22](../media/branch-a-world/step-22.png)

</details>
<details><summary><code>volter world clock set 2027-01-01T10:00:00Z</code></summary>

![step 23](../media/branch-a-world/step-23.png)

</details>
<details><summary><code>volter world run -- node signup.mjs</code></summary>

![step 24](../media/branch-a-world/step-24.png)

</details>
<details><summary><code>volter world branch as-of-nine-thirty --at 2027-01-01T09:30:00Z</code></summary>

![step 25](../media/branch-a-world/step-25.png)

</details>
<details><summary><code>volter world log | grep -c customer.create</code></summary>

![step 26](../media/branch-a-world/step-26.png)

</details>
<details><summary><code>volter world down</code></summary>

![step 27](../media/branch-a-world/step-27.png)

</details>

<!-- playback:END -->
