# Branches

A branch is a full copy of an arc: every service, a copy of its data, and an address of its own. Use one to review a pull request against real-shaped data, rehearse a migration, or hand someone a demo they cannot break.

## Create one

```sh
omniarc arc branch create shop production preview --wait-url
```

The arguments are the arc, the branch to copy, and the new branch's name. The name takes lowercase letters, digits and hyphens, starting with a letter and ending with a letter or digit, at most 40 characters. The parent can be `production` or any other branch, so a branch of a branch works the same way.

It prints what it copied, what it anonymized, and the branch's address:

```text
shop/production → shop/preview
anonymized  db: 1 rule(s), 2 row(s)
url  https://<hex>.arc.omniarc.eu (pending)
waiting for the URL to serve (up to 180 s)...
url  https://<hex>.arc.omniarc.eu (ready)
```

A new address takes a few minutes to serve, while its certificate is issued. `--wait-url` waits for it, for up to three minutes. Without it the command returns as soon as the branch exists; ask for the address later with:

```sh
omniarc arc branch url shop preview
```

## What a branch gets

- **Every service**, run from the same release its parent runs.
- **A copy of every volume.** It starts out sharing the parent's data on disk, so a branch of a large database is made in one step and uses room only for what it changes. A writable bind mount inside your project (`./data:/var/lib/postgresql/data`) is kept with the arc and copied the same way.
- **Anonymized personal data.** A service with `contains_pii: true` has its [`anonymize`](https://docs.omniarc.eu/reference/arc-yaml/services.md#services-anonymize) rules run against the branch's copy before the branch can be reached. If a rule cannot be applied, the branch is not created.
- **Empty services where you said so.** A service with [`branch: false`](https://docs.omniarc.eu/reference/arc-yaml/services.md#services-branch) starts empty, its volumes and writable bind mounts emptied: a cache, or data you never want in a preview. Files your project had at such a path were copied in on the arc's first deploy only, so in the branch the path stays empty until the service writes to it. A service that is not deployed (`deploy: false`, or a profile that is not active) starts empty too, whatever its `branch`, and data no service binds any more is not copied.
- **The arc's `.env`**, which every branch shares. See [Env and secrets](https://docs.omniarc.eu/guides/env-and-secrets.md).

From then on the branch and its parent are independent. Nothing you write in `preview` reaches `production`.

A service that should flush its writes before it is copied, such as a database checkpoint, gets a [`quiesce`](https://docs.omniarc.eu/reference/arc-yaml/services.md#services-quiesce) command, which runs before every copy.

## Deploy new code to it

From your working copy, deploy to the branch instead of production:

```sh
omniarc deploy --branch preview
```

Its data stays; only the code and configuration change.

## A branch for every pull request

In CI, with `OMNIARC_KEY` set from your CI's secrets, when a pull request opens:

```sh
omniarc arc branch create shop production pr-42 --wait-url
omniarc deploy --branch pr-42
```

and when it closes:

```sh
omniarc arc branch destroy shop pr-42
```

Each command exits non-zero when it fails, so the job fails with it. A key with the `member` role can create and destroy branches; deploying needs `admin`.

## See them

```sh
omniarc arc show shop
```

Lists every branch with its parent, whether it is awake, and two sizes: `USED`, what the branch holds on its own, and `REFERENCED`, all the data it can see, shared data included.

## Sleep, wake and destroy

A branch you are not using can sleep: its services stop and its data stays. See [Sleep and wake](https://docs.omniarc.eu/guides/sleep-and-wake.md).

```sh
omniarc arc branch destroy shop preview
```

destroys a branch and its data. It cannot be undone, and it does not ask first.

**Example: shop/arc.yaml**

```yaml
arc: shop
edge: { service: web, port: 3000 }
resources: { cpu: "1", memory: 1Gi, disk: 5Gi }
services:
  web:
    kind: web-service
    contains_pii: false
  db:
    kind: database
    contains_pii: true
    anonymize:
      engine: postgres
      database: shop
      user: shop
      rules:
        - { table: customers, column: email, transform: fake-email }
```
