# Branches and previews
Source: https://sovaria.in/docs/branches-and-previews

Production and its environments as branches: check one out, compare it with production, deploy it, reset it, restore its database to a moment, revert it to a commit, protect it or give it an end date — plus a preview per pull request.

A **branch** is production (`main`) or one of its [environments](https://sovaria.in/docs/environments-and-staging): staging, an [API version](https://sovaria.in/docs/api-versions) or a pull request preview. Each environment has its own database, functions, policies and API URL, and its own line of [Version history: see, undo and restore changes](https://sovaria.in/docs/version-history) that records only the changes made in it. The **Branches** page in the console lists them all with their database, data, URL, protection and end date.

(Diagram: One branch per environment — Changes are recorded on the branch of the environment they were made in; deploy is the only way into production.)

| Kind | Database | History | Gets to production by |
|---|---|---|---|
| **Production** (`main`) | The project database | Every production change | It is production |
| **Environment** (staging, API version, preview) | Its own | Changes made in it | Deploy |
| **History only** | None: uses production's | A copy of a line of history | Merge into another history-only branch (changes nothing real) |

## Check out a branch

One branch is checked out for the whole console: the top bar's branch picker, the Branches page and Version history all show and change the same one. Checking out an environment sends every request (tables, SQL, functions, policies, logs) to it; production and history-only branches use production. From code, pick the environment the same way:

CLI:
```bash
sov branches list
sov branches use staging        # later commands run against staging
sov branches use production     # back to production
```

JavaScript:
```ts
// Every call after this goes to the staging environment (X-Sovaria-Env-ID).
sovaria.setContext(orgId, projectId, stagingEnvId)
// …or point the app at the environment's own API URL (Connect, or the Branches page).
```

Python:
```python
sovaria.set_scope(org_id, project_id, env_id=staging_env_id)
```

## Create one

**New environment** on the Branches page (or the top bar's database menu): a name, staging or API version, where it starts (production, or another environment on plans that include it), what its database starts with (structure, empty, or a masked sample or all of the rows — see [Environments, staging and deploying to production](https://sovaria.in/docs/environments-and-staging#data)), an optional end date and protection. Its Version history branch is created with it, starting from production's history.

CLI:
```bash
sov branches create staging --data sample --expires-in 14 --use
sov branches create v2 --version v2 --from staging --protect
```

JavaScript:
```ts
await sovaria.api.governance.createEnvironment({
  envId: crypto.randomUUID(), name: 'staging', database: 'sample', mask: true, expiresInDays: 14,
})
```

## Compare and deploy

**Deploy** shows the schema difference between the environment's database and production's (tables, columns, indexes, constraints and row policies that would be added, changed or dropped, and any migration production has that the environment doesn't), then the migrations, functions and policies the deploy carries. Everything is checked against production with nothing written; only if it all passes is it applied, as one commit on `main`. Merging an environment's history into `main` is refused: deploy is how changes reach production.

CLI:
```bash
sov branches diff staging             # schema difference with production
sov branches deploy staging           # shows the check, asks, then applies
```

JavaScript:
```ts
const diff = await sovaria.api.data.schemaDiff({ fromEnv: stagingEnvId })
const check = await sovaria.api.data.promoteEnvironment({ fromEnvId: stagingEnvId, dryRun: true })
await sovaria.api.data.promoteEnvironment({ fromEnvId: stagingEnvId, dryRun: false })
```

HTTP:
```bash
curl "$SOVARIA_URL/api/v1/data/rel/schema/diff?from_env=$STAGING_ENV_ID" -H "Authorization: Bearer $TOKEN" \
  -H "X-Sovaria-Org-ID: $ORG" -H "X-Sovaria-Project-ID: $PROJECT"
```

## Revert a branch to a commit

In Version history, open a commit's menu and choose **Revert to this commit**. The plan lists, for that branch only, what goes back: policies, settings, functions and buckets are put back through the normal API with your own permissions, in that branch's environment. Changes made on other branches since then are listed and left alone. Two separate boxes add more:

- **Also roll back N migration(s)** — runs their down SQL after the other changes (checked first; blocked if one has no down SQL). Tables and columns they added are dropped with their data.
- **Also restore the database** — production: from the closest backup before that moment (a safety backup first, undo for 7 days); an environment: its own database put back to that moment.

The revert is recorded as new commits; history is never rewritten. The dialog shows *Recording changes…* until they arrive, then the branch's new head. If the console has another environment checked out than the branch you revert, the server refuses (`ENV_MISMATCH`): check the branch out first.

CLI:
```bash
sov branches revert 3f2a9c1e --branch staging                   # plan, confirm, apply
sov branches revert 2026-10-26T09:00:00Z --include-database       # production, with the backup
```

JavaScript:
```ts
const plan = await sovaria.chrono.restorePlan('3f2a9c1e', 'staging', { envId: stagingEnvId })
await sovaria.chrono.restore('3f2a9c1e', 'staging', { envId: stagingEnvId, includeSchema: true })
```

## Reset or restore an environment's database

- **Reset from its parent** makes the database again from the one it started from (its parent environment, else production) with the same data option; a sample or full copy is copied again, masked as before. A backup is taken first. Its functions, policies and URL stay.
- **Restore to a moment** puts the environment's database back as it was at a time in the project's point-in-time window (Pro and higher, `db.pitr_retention_days`). Production is never touched; a backup of the environment is taken first. It runs as a job you can follow.

CLI:
```bash
sov branches reset staging
sov branches restore staging --at 2026-10-26T10:00:00Z
```

## Protect it, or give it an end date

A **protected** environment can't be deleted, reset or restored until an owner or admin turns protection off (`ENVIRONMENT_PROTECTED`). An **end date** deletes the environment — database (a backup is kept), URL and history branch — automatically on that day; protected environments are never deleted this way. Changing an environment, and deleting one, is for organization owners and admins.

CLI:
```bash
sov branches protect v2
sov branches expire staging --days 7
sov branches expire staging --never
```

## A preview for every pull request

With a GitHub repository linked and previews on (Functions › GitHub), each pull request gets an environment `pr-<number>` with the PR's functions and new migrations, listed on the Branches page with its status. A migration file that was already applied and is then **edited** in the pull request is never applied again on top of the old version: the preview stops with *edited after it was applied* (add a new migration instead), or — with **Rebuild on edit** — its database is reset from production and every migration is applied again in order. A preview ends `env.preview_ttl_days` after its last push, and is deleted when the pull request closes.

## History-only branches

**New branch** in Version history copies a line of history without a database. Use it to keep a named point to compare with. It can be merged into another history-only branch; merging only combines the recorded history and changes no database, function or policy.

## Plans

|  | Free | Pro | Ultra | Team | Enterprise |
|---|---|---|---|---|---|
| Environments per project (besides production) | — | 2 | 5 | 10 | 50 |
| Start with a copy of the data | — | Sample | Sample or all | Sample or all | Sample or all |
| Protected environments | — | Yes | Yes | Yes | Yes |
| Pull request previews | — | Yes | Yes | Yes | Yes |
| A preview lives after its last push | 1 day | 7 days | 14 days | 30 days | 30 days |
| Restore an environment to a moment | — | 7 days back | 14 days back | 28 days back | 35 days back |

## Common mistakes

- Reverting production to undo a staging change: staging's changes are on staging's branch. Check out staging and revert there.
- Expecting a revert to change data: it puts configuration back. Tick the database box, or restore the environment to a moment.
- Editing a migration after it was applied to a preview: add a new migration, or turn on Rebuild on edit.
- Deleting an environment its API URL is still used by: every client on that URL stops working.
