-
Notifications
You must be signed in to change notification settings - Fork 0
git
GIT versions hash-file records and is modelled on real git — the
same verbs (add, status, commit, log, diff, restore, rm,
show), the same porcelain. The only difference is the unit: a "path"
is an MVX file plus record id. The working tree is the live
records; the index is a persistent staging area; commits are
commits, in a bare repo (.recgit) in the account.
Git runs through libgit2 as native subroutines — no git binary,
any privilege tier, no shell (a commit message cannot inject).
> GIT INIT create the record repository
> GIT ADD CUST stage every record of CUST
> GIT ADD CUST C1 stage one record
> GIT STATUS
A CUST/C1 staged (added)
A CUST/C2
> GIT COMMIT -m "initial customers"
[32f57ce] initial customers
> GIT LOG
32f57ce initial customers
After changing records in the hash file, status and diff behave like git — the records are the working tree:
> GIT STATUS
M CUST/C2 modified, not staged
?? CUST/C3 untracked (new record)
> GIT DIFF CUST
diff CUST/C2
Bob
-Paris
+Berlin
> GIT RESTORE CUST revert records to HEAD (drops C3)
> GIT SHOW CUST C1 committed content of a record
Status codes match git: A staged-added, M modified, D deleted,
?? untracked, with the staged column first. GIT RM file record
unstages a record.
You do not commit a million order records — but you do commit their
schema. GITIGNORE (a record in the account, one glob per line) keeps
matching files and records out of history; GIT IGNORE pattern
appends to it. Dictionaries are addressed as DICT:
> GIT IGNORE ORDERS keep the bulk order data out
> GIT ADD ORDERS ORDERS is in GITIGNORE, nothing staged
> GIT ADD DICT ORDERS stage the ORDERS dictionary (schema)
> GIT STATUS
A ORDERS.DICT/CUST only the schema is tracked
A pattern matches a file name (ORDERS), a glob (*.TMP,
LOG*), or a file/record path (ORDERS/O*). Ignored records never
appear as untracked, so GIT STATUS stays quiet about bulk data. The
usual shape is to ignore data files and GIT ADD DICT their
dictionaries, plus GIT ADD VOC for verbs — schema and configuration
in git, data in the store.
Because record blobs are line-oriented text (attribute marks become newlines), ordinary git tooling reads the same history:
git --git-dir=.recgit log --oneline
git --git-dir=.recgit show HEAD:CUST/C1
A separate tool: EXPORT file copies records into a directory
file (file.EXP) — real files on disk to browse or feed to
non-git tools — and IMPORT file mirrors them back. Use GIT to
version records in place; use EXPORT when you want the records as
files.
| artifact | source of truth | approach |
|---|---|---|
| BP / source | the directory | git tracks the directory file natively |
| VOC / dictionaries | the hash file |
GIT ADD / COMMIT / RESTORE
|
| data files | the backend store | ignored via GITIGNORE
|
The perennial MultiValue problem — ship a stock product to many sites, let each customise, and fold good customisations back into the mainline — is git branching. The record repo makes it concrete:
stock mainline = the main branch
> GIT BRANCH site-acme deploy stock to a site (a branch)
> GIT CHECKOUT site-acme switch: the records update to match
... customise: edit verbs, dictionaries, add records ...
> GIT ADD ... ; GIT COMMIT -m "acme: custom dashboard"
roll a site feature upstream into stock:
> GIT CHECKOUT main
> GIT CHERRY-PICK site-acme apply just that commit to the mainline
push new stock down to a site:
> GIT CHECKOUT site-acme
> GIT MERGE main 3-way merge; records update
GIT CHECKOUT switches the branch and materialises its records into
the live hash files — the working tree is the data, so a checkout
updates the records (writing changes, deleting records absent from the
branch). GIT MERGE and GIT CHERRY-PICK do real 3-way merges of
records, dictionaries, and verbs: when a site and the mainline touched
different records they merge cleanly; when they touched the same
record git reports the conflict for you to resolve (edit the record,
GIT ADD, GIT COMMIT). GIT BRANCH lists or creates branches.
Because it is real git underneath, the mainline can live in a shared
repository and sites can clone/pull/push it once network
transport is added — the branching model above is what makes stock
delivery and feature round-tripping tractable across many client
sites.
An account committed to git carries its configuration — dictionaries
(as <file>.DICT directory files), BP source, VOC, PACKAGES,
FILES, GITIGNORE — but not its data (kept out of git by
GITIGNORE). After a clone you have the schema and source but no data
files. BUILD provisions a working account from what is there:
git clone <account-repo> mysite && cd mysite
mvx -a . -c BUILD # developer privilege (it catalogs)BUILD:
- ensures the account (
VOC) exists; - for each dictionary present without its data file, creates the
file — the type comes from the
FILESmanifest override, then the%FILE%control record stored in the dictionary itself, then an interactive prompt (MVXBUILD_ASK=1), then thelmdbdefault — and imports the dictionary, rebuilding indexes from%INDEXES%; - catalogs BP source into runnable verbs;
- links the packages listed in
PACKAGES.
This is why a .DICT directory with no data file is enough to
rebuild: it tells BUILD a file exists, what its schema is, and — via
the %FILE% control record CREATE-FILE stamped in — what backend to
make it on and which indexes to rebuild. A FILES manifest is only
needed to override those hints (e.g. a client putting a file on a
different backend than the vendor used). Prepare an account for
delivery by exporting each dictionary — EXPORT DICT PARTS writes
PARTS.DICT — and declaring types in FILES; the data stays in the
store. Packages are themselves account-shaped, so the same BUILD
provisions a cloned package.
GIT (above) version-controls records from inside a running account.
The git package also ships mvx-git, a native command that gives the
same power from an ordinary shell — you can alias git=mvx-git.
In an account with its own git repository — a directory carrying a
.mvx descriptor and a .git, or where you run mvx-git init to create
one — mvx-git drives the very same engine the GIT verb uses: it reads
and writes the account's live hash-file records straight to and from git
objects via libgit2. The working tree is the records, so there is no
legible export copy — the records are committed directly.
The store is the account's ordinary .git, so a host like GitHub and any
git tooling read it as a normal repository (records tracked at
<file>/<id>, attribute marks as newlines for line-oriented diffs). A
plain git clone/checkout materialises the records as files —
"incorrectly", since the real working tree is the live records — but the
committed .mvx marks the result as an account, so mvx-git clone (or
mvx-convert-acct) rebuilds it into a working account.
cd myacct
mvx-git init # create the account's .git
mvx-git add CUST # stage a file's records (mvx-git add CUST.DICT for its dict)
mvx-git status # A/M/D per record, versus HEAD and the index
mvx-git commit -m "initial"
mvx-git log
mvx-git diff CUST # line diff of unstaged record changes
mvx-git restore CUST # revert records to HEAD
mvx-git branch site # branch / checkout / merge / cherry-pick for delivery
mvx-git checkout site
mvx-git show CUST C1 # the committed content of one recordadd -A stages every on-disk directory file; name LMDB-backed files
explicitly.
Submodules. An account can carry a git submodule — for example a docs
directory pointing at the repository's wiki. Add it with plain
mvx-git submodule add <url> docs (this forwards to git, which clones it and
writes .gitmodules); mvx-git add -A then stages it as a gitlink (its
current commit), not by flattening the submodule's files into records, and a
clone restores it like any submodule. status treats the gitlink as one
entry, not a directory file.
Subdirectory accounts. An account can live inside a larger repo (a
.mvx but no .git of its own) — the bundled demo account inside the
mvx-lang repo is one. mvx-git sees the .mvx, but since the account has
no repository of its own it forwards to the enclosing repo and never
creates a nested .git; after cloning that repo, rebuild the account on
disk with mvx-convert-acct (or clone it directly with mvx-git).
Everything else is real git. Any command the engine does not
implement, and any command run outside an account with its own .git,
is forwarded verbatim to git — so mvx-git is still a drop-in git.
Clone and adoption. mvx-git clone forwards to git clone; if the
clone carries a .mvx descriptor it is adopted into a live account by
mvx-convert-acct (which builds the hash files from the checked-out
directory form). mvx-convert-acct is needed only for this — turning a
plain-git checkout into a working account — never on mvx-git's own
add/commit/checkout.
mvx-git clone git@host:acct.git myacct # git clone, then build the accountIf the cloned directory is not an account and stdin is a terminal,
mvx-git asks whether to create one (default no); MVXGIT_CREATE=1
answers yes for scripts. With no terminal and no override it never
prompts.
mvx-git compiles the record-git engine in and links the runtime and libgit2.
The real git is found on PATH.
Where it comes from. mv_git is its own repository and its own released
package, not part of the mvx tree. cmake --install downloads the published
package and installs mvx-git into <prefix>/bin and the GIT verb into the
system account, so an installed toolchain has both — see
Getting Started. MVPKG installs or upgrades it afterwards.
Building it yourself instead: the package's build-native.sh produces
bin/mvx-git, and mkpkg.sh links a package's bin/ onto the dev PATH
(build/bin).