Pikbase Docs
Open console (opens the console)
Esc

Type to search.

Shipping and operations

Backend source control with Git

Commit schemas, properties, workflows, functions, libraries, and document templates alongside application source.

GSB backend resources can live alongside application source in the same repository and be reviewed in the same commits and pull requests. The CLI serializes tenant resources into ordinary files; Git versions those files. This is a Git-compatible source workflow, not automatic Git synchronization: the CLI does not create commits, merge branches, or push to a Git remote.

What belongs in a commit

Keep one .gsb/ directory at the repository root, with one directory per checked-out tenant. Commit deployable content and its identity/sync metadata together, not a separate .gsb/ directory inside every app.

Resource Checked-in representation
Schema definition schema/<name>/<name>.json
Columns/properties schema/<name>/properties/<property>.json, one file per property
Workflow workflows/<name>/workflow.meta.json and design.json
Workflow logic Ordered JSON files under activities/ and transitions/
Standalone function serverless/functions-std/<name>/
Workflow-only function serverless/functions-wf/<name>/
Function implementation <name>.ts, <name>.meta.json, and operation files such as op-1.json and op-1.ts
Shared library serverless/libraries/<name>.ts, metadata, and declarations when emitted
Document template docTemplates/<name>/meta.json plus per-language HTML or content.html
Test input Optional function <name>.test.json and workflow.test.json, containing only reviewed nonsensitive fixtures

A feature can commit a column, workflow transition, shared function change, and email template together. This illustrative tree uses the current folder format:

.gsb/dev1/
  schema/Order/
    Order.json
    properties/approvalStatus.json
  workflows/OrderApproval/
    workflow.meta.json
    workflow.test.json
    design.json
    activities/010-Start.json
    activities/020-Approve.json
    transitions/010-StartToApprove.json
  serverless/
    functions-std/SendApprovalEmail/
      SendApprovalEmail.ts
      SendApprovalEmail.meta.json
      SendApprovalEmail.test.json
    functions-wf/ValidateOrder/
      ValidateOrder.meta.json
      op-1.json
      op-1.ts
    libraries/OrderRules.ts
    libraries/OrderRules.meta.json
  docTemplates/OrderApproved/
    meta.json
    en_us.html
    tr_tr.html

Use actual paths emitted by your tenant checkout. Current schema folders embed identity and serverSync in definition and property documents; they do not require a separate definition metadata sidecar. Pull migrates legacy flat schemas to folders.

Workflow activities reference shared functions by name; function bodies live separately. Changing a workflow does not implicitly deploy its referenced functions. Commit and deploy related function/library changes explicitly. Preserve immutable IDs and review renames rather than generating new identities to resolve merge conflicts. Designer layout stays in design.json, separate from logic. Generated serverless declarations and editor configuration can be committed as generated support, not hand-authored code.

Exclude secrets and runtime data

Never commit .gsb/<tenant>/credentials.json, real environment values, private keys, tokens, or production session data. The repository ignores tenant credentials, build output, logs, and environment files; do not force-add them. Review fixture payloads, code, template HTML, and metadata too: source files can still contain secrets or PII.

Runtime entity rows, workflow instances, logs, and uploaded documents are not all captured by a source checkout. Promote explicitly selected data using resource packs or reviewed seeds, not a blanket export of a tenant database into Git.

Git state versus GSB sync state

Check What it compares
git status / git diff Working files, index, and Git commits
gsb status --json Current local payloads versus their last successful sync baseline
gsb push --all-changed --dry-run Resources selected for upload and applicable push preflight checks
gsb verify <artifact> --json An immutable plan's current preconditions or an apply result's persisted writes

gsb status reports clean, modified, or legacy-untracked. Its remoteComparison: "not-requested" means it does not compare current remote resource content. It is not a three-way merge or a server-drift check. Target authentication can still require a backend call even though resource comparison is local.

Successful pulls and pushes record serverSync.contentHash, with lastPull and lastPush timestamps where applicable. Hashes normalize JSON key order, ignore embedded serverSync, and normalize text line endings. Older resources without a hash use timestamp fallback until the next successful sync. Fresh Git checkouts change filesystem times; review legacy-untracked resources before bulk upload.

Successful synchronization also records the cloud row's lastUpdateDate under serverSync. Before every update, the CLI requires that committed baseline to equal the live row and atomically claims that exact (id, lastUpdateDate) revision. A Git rollback therefore cannot silently overwrite a newer tenant row, and two CLI clients cannot both win the same revision. Pull before pushing when the baseline is missing or stale; the successful write read-back records the next cloud timestamp. The CLI keeps the backend revision string unchanged, including timezone-less values, because normalizing it would break the compare-and-set contract.

An apply result with revision-claim-failed means the resource payload write did not start, but a lost response can leave the timestamp claim applied in the cloud. Pull that resource, review the resulting Git diff, and create a new plan. Do not retry the old plan or infer payload success from the changed timestamp.

Use gsb push <path> --force only for an intentional overwrite after reviewing the cloud change. The resulting operation records approval: "explicit-force" and still claims the current cloud timestamp atomically; --force does not bypass tenant, identity, create, rename, or concurrent-write checks.

Identity and metadata files belong in Git even where excluded from payload hashing. Metadata-only edits to function, workflow, library, or document-template sidecars may not select that resource for --all-changed; explicitly preview and push it when changing those fields. Use both Git diff and GSB status.

A resource can be committed but not deployed, or deployed but not yet committed. Committing does not reset its GSB sync baseline. A clean working tree does not prove the tenant matches that commit, and clean GSB status does not prove files are committed. Changed-resource selection is not a Git commit-range deployment mechanism.

Daily branch and pull-request workflow

  1. Start from reviewed source. Use a normal Git branch and explicitly select the intended tenant. Preserve local work in a commit before refreshing resources.
  2. Pull intentionally. Prefer named resources for small refreshes. Pull can overwrite local files and reconcile/remove files inside resource folders; it is not a merge with uncommitted edits. Review the resulting Git diff.
  3. Edit related resources together. Include definitions/properties, activities, transitions, functions, libraries, and document templates belonging to the feature.
  4. Validate and test. Run static checks and isolated tenant tests. gsb test runs code on the backend without saving the function; execution can still have side effects.
  5. Review both diffs. Inspect Git changes and GSB status, then preview uploads. Reject unexpected creates, renames, permissions, seed data, or tenant identities.
  6. Commit explicit paths. Use Git's normal add/commit/PR process; avoid blindly staging a whole tenant checkout containing unrelated work or sensitive fixtures.
  7. Deploy after approval. Create an immutable plan from the approved source, apply that exact artifact, and verify its apply result. Schema changes also require the matching ordered migration artifact. Review refreshed IDs, hashes, and timestamps.
  8. Retain sync updates deliberately. Commit legitimate refreshed source metadata separately when needed. Link deployment to the original reviewed commit; a follow-up metadata commit is not a second release implementation.

These examples assume dev1 is the intended tenant. Pull writes local files; use it only after protecting and reviewing existing work:

pnpm exec gsb --tenant dev1 pull --schema --workflow --function --library --doc-template
pnpm exec gsb --tenant dev1 status --json
pnpm exec gsb --tenant dev1 diff --remote --json
pnpm exec gsb --tenant dev1 push --all-changed --dry-run
pnpm exec gsb --tenant dev1 plan --output change-plan.json
pnpm exec gsb --tenant dev1 apply change-plan.json --output apply-result.json --json
pnpm exec gsb --tenant dev1 verify apply-result.json --json

Preview individual resources using their actual checked-out paths:

pnpm exec gsb --tenant dev1 push .gsb/dev1/schema/Order --schema --dry-run
pnpm exec gsb --tenant dev1 push .gsb/dev1/docTemplates/OrderApproved --doc-template --dry-run

New assets require current push creation approval; inspect gsb push --help. Do not bypass identity checks to make a branch deploy. Commit history helps manual reconciliation; remote stale-write rejection comes from the committed lastUpdateDate baseline and the atomic cloud-revision claim, not from Git history.

For a schema edit, pull immediately before editing and record its migration before creating the deployment plan:

pnpm exec gsb --tenant dev1 pull Order --schema
pnpm exec gsb --tenant dev1 migration plan .gsb/dev1/schema/Order \
  --recovery forward-repair \
  --recovery-instructions "Revert with a reviewed follow-up migration"
pnpm exec gsb --tenant dev1 migration check --json

diff --remote compares committed immutable IDs and cloud lastUpdateDate baselines with the selected tenant. It reports remote-only updates, missing rows, and name conflicts without mutating either side. It does not claim a remote payload-level diff; pull and review the resulting Git changes before replacing a stale local baseline.

Migration artifacts form a continuous hash chain for each schema. A teammate's parallel migration from the same prior revision is rejected; pull their revision and create the next migration instead. Migrations requiring data transformation remain blocked from deployment until the platform has a typed transformation runtime. Existing-schema chains include stable schema/property IDs in their fingerprints. Create-origin chains use authored-content fingerprints for their entire lifetime so IDs assigned by the server cannot create false drift or break post-apply verification. The apply result records the exact migration sequence, checksum, and hashes; verify rechecks that binding and the current authoritative schema fingerprint after read-back. Recording a migration also takes an exclusive tenant-local lock so parallel CLI processes cannot both claim the next sequence.

For a compatible metadata change that must be reversed, prepare a compensating migration and deploy it through the same controls as any other schema change:

pnpm exec gsb --tenant dev1 migration rollback <sequence> \
  --recovery-instructions "Reapply the reviewed change if needed"
pnpm exec gsb --tenant dev1 status --json
pnpm exec gsb --tenant dev1 plan --output rollback-plan.json --json
pnpm exec gsb --tenant dev1 verify rollback-plan.json --json
pnpm exec gsb --tenant dev1 apply rollback-plan.json \
  --output rollback-result.json --json
pnpm exec gsb --tenant dev1 verify rollback-result.json --json
pnpm exec gsb --tenant dev1 migration check --json

The rollback command stages source and records a new migration; it does not mutate the tenant. It requires the target to be the latest migration for that schema, an embedded pre-change snapshot, and exact local/live agreement with the target toHash. It rejects schema creation reversal, property deletion, type/data reversal, stale state, and every destructive or transformation-requiring reverse. In particular, a forward property addition cannot currently be reversed automatically because its reverse is a property deletion. Schema definitions do not support entity-version restore.

Merges, deletions, and rollback

  • Merge JSON, TypeScript, and HTML through normal Git review. Preserve IDs and valid references; do not resolve every metadata conflict by choosing one side wholesale.
  • Coordinate shared development-tenant edits. Branches do not isolate the live tenant; a developer's pull/push can observe another developer's backend changes.
  • Removing a local file is not a general remote-delete instruction. Some resource serializers replace collections, while schema/property removals require explicit contracts. Review resource-specific deletion impact before applying a change.
  • Reverting a Git commit restores source, not live schema or data. Check out or revert the reviewed source, then preview, approve, and push it again as a new forward deployment. Data and external side effects may need a snapshot restore or forward repair.
  • Tenant backup restore is destructive disaster recovery, not routine schema rollback. Restore only a verified completed backup under explicit approval, then reconcile the local migration chain with the restored authoritative schema before another deploy.
  • A dry run and later push do not reuse one immutable artifact; the later push builds a fresh plan. Use explicit plan -> apply -> verify when review must bind to exact content and preconditions. Per-resource revision claims prevent stale writes, but they are not a tenant-wide deployment lock or atomic multi-resource rollback.

Connect commits to releases

Record the reviewed source commit, exact built pack/file identity, build selection, target, installation policy, approval, job status, and verification evidence. Packs can contain assets and query-selected data beyond the CLI checkout; a commit alone does not prove complete pack contents. Confirm live packing inputs match reviewed source, then promote the same exact pack from staging to production.

Do not copy dev credentials, IDs indiscriminately, or sync baselines into production folders. A branch or copied folder is not a tenant identity-mapping mechanism. See CI/CD, deployment, and seeds for selective data promotion, installation policy, and release controls.

Contract sourcedocs/guides/cli-source-control.md