Gitapp
Gitapp

Gitapp

Gitapp is a layered stack that lets an app store its data in a real git repository — every write is a commit, conflicts are exposed as conflicts, and any provider that speaks git over HTTPS (GitHub, Gitea, GitLab, self-hosted) is a valid backend.

The stack is split across four packages so apps can opt in to only what they need. The boundaries are stable: each layer below is implementable without knowledge of the layer above.

PackageLayerRole
@dev-bench/docstoreinterfaceDocStore contract + Zod schemas. No git knowledge.
@dev-bench/git-fs1Git/FS primitives. Browser/Node/in-memory adapters; GitHub/Gitea/GitLab REST.
@dev-bench/gitapp2Wires git-fs into a DocStore implementation: transactions, conflict policies, watch.
@dev-bench/gitapp-ui3RN + react-native-web theme, primitives, and full-fledged components driven by view-models.

Install

pnpm add @dev-bench/docstore @dev-bench/git-fs @dev-bench/gitapp
# UI is optional — peer-deps on react / react-native / react-native-svg
pnpm add @dev-bench/gitapp-ui

Conceptual model

A DocStore is a transactional document store. Every mutation goes through runTransaction, which is atomic — all mutations apply or none do — and returns a discriminated union you branch on with ts-pattern.match(...).exhaustive().

import { match } from "ts-pattern";

const result = await docStore.runTransaction({
  mutations: [
    { kind: "put", path: "todos/1.md", content: "buy milk\n", ifMatch: { kind: "any" } },
  ],
  message: "todo: add buy milk",
  onConflict: { kind: "rebase-mutations", maxAttempts: 3 },
});

match(result)
  .with({ kind: "ok" }, ({ commitOid }) => console.log("committed", commitOid))
  .with({ kind: "conflict" }, (e) => console.warn("conflict", e.paths))
  .with({ kind: "rejected" }, (e) => console.warn("validation", e.reason))
  .with({ kind: "network" }, (e) => console.warn("network", e.message))
  .exhaustive();

The ifMatch token implements optimistic concurrency. The onConflict policy decides what happens when a remote changed since the last sync — fail loud, retry after pull, or rebase the mutations onto the new HEAD.

Choose your storage

@dev-bench/git-fs ships three adapters out of the box:

  • createBrowserGitFs — LightningFS (IndexedDB) + isomorphic-git web http. Web app + Hermes (React Native).
  • createInMemoryGitFs — pure-memory fs. Tests, sandboxes, fixtures.
  • createNodeGitFs — node fs + isomorphic-git node http. CLI tools, servers.

And three management providers:

  • githubManagement — GitHub REST.
  • giteaManagement — Gitea REST.
  • gitlabManagement — GitLab REST.

Pick whichever pair fits the host environment; the DocStore you build on top is identical.

Next

  • Getting Started — wire it together end-to-end.
  • API — public exports, package by package.

On this page