Repository navigation
Releases: SammyBytes/Deltix-Client
Release list
v0.8.16
[0.8.16] - 2026-09-07
In plain terms: the app keeps its own runtime bookkeeping (log rows,
sync stamps, scratch tables) inside the same database you publish, so a
normal "publish my changes" also dragged that bookkeeping up to the server —
often leaving it as messy half-states that are hard to undo. This release
separates the two worlds: you can now publish only the schema (table
structures and columns) and leave the runtime rows behind, and you can
throw away just the rows while keeping any schema edits you're working
on. When a normal publish is about to include runtime-row bookkeeping, the
app now warns you first so you can choose.
deltix commit --schema-only <message>— publishes only DDL changes
(new/changed/dropped tables and columns) and leaves row-only changes
uncommitted, so publication no longer ships runtime/scratch rows.
New tables are published with their schema and initial rows.deltix commit <message>now warns when it's about to publish row changes
in data-only tables (runtime/stamp tables), pointing at--schema-only
or an explicit table list.deltix reset --data— discards working-set rows and restores them to
the last committed snapshot while keeping every pending schema change
(unlike--hard, which would also wipe structural edits).- Added
dolt_add/dolt_resetstaging round behind the schema-only flow;
no changes to the existingcommit/push/pullpipeline for normal use.
Full Changelog: v0.8.15...v0.8.16
v0.8.15 - Git-style working-tree maintenance (deltix reset --hard / clean)
[0.8.15] - 2026-09-07
In plain terms: to publish your changes, you sometimes have to clear away
working data that was never meant to go to the server — for example the
scratch/runtime rows a database silently accumulates. Before, that meant
stopping the app and running low-level database commands by hand, which is
exactly the kind of manual repair steps this project is trying to eliminate.
Now the app has its own deltix reset and deltix clean commands, just like
git: one throws away uncommitted changes to tracked data (with a preview mode
for the untracked-tables cleaner so you can double-check before anything is
permanently deleted). No stopping the app, no hand-written database commands.
Added
deltix reset [<repo>] [--hard]— git-style working-tree reset on the
local Dolt data dir. Mixed (no flag): unstages staged changes while
keeping the working values (dolt reset).--hard: discards every
uncommitted change to tracked tables and reverts the working tree to the
current branch HEAD (dolt reset --hard <HEAD>). Untracked new tables are
intentionally left alone (usedeltix cleanfor those), matching git.deltix clean [<repo>] [--dry-run|-n]— git-style clean: permanently
deletes tables that exist only in the working set (untracked, dolt status
"new table"), leaving tracked tables and their uncommitted changes
untouched.--dry-run/-nlists the untracked tables that would be
deleted without deleting anything.- Both commands run against the live local
dolt sql-serversession via the
MySQL wire (CALL DOLT_RESET(...),CALL DOLT_CLEAN()), so the in-memory
working set the app sees is the one that gets reset — nodeltix stop/
startdance. Unlikedolt checkout, the CLIdolt reset/dolt clean
are not blocked while a server runs (verified on dolt 2.3.1), so the CLI
fallback works with or without a server. - New service methods
VersioningLocalService.resetWorkingSet()and
cleanWorkingSet()(fast-path MySQL → CLI fallback, same pattern as
createBranch), and a sharednormalizeStatusRows()helper.
Tests
- New integration tests (real dolt, guarded) cover the four behaviors: hard
reset discards tracked changes but not untracked tables; mixed reset
unstages while keeping working values;cleandeletes untracked tables
and leaves tracked working changes untouched;clean --dry-runlists
without deleting. A fifth case asserts a hard reset on a clean repo
reports no tables. - 148 client unit tests pass (143 previous + 5 new);
bun run lintclean
(no errors). Manually smoke-tested the CLI end-to-end:deltix clean --dry-run→deltix reset --hard→deltix cleanleaves a "working tree
clean" repo with only the intended table.
Full Changelog: v0.8.14...v0.8.15
v0.8.14 - Local-first branches with git-style DWIM checkout
[0.8.14] - 2026-09-07
In plain terms: branches are now handled the same way git does — mostly
on your own computer first, not on the server. Before, creating or checking
out a branch told the server about it before it existed locally, and if a
branch existed on the server but not on your machine, the app quietly made
a "stand-in" local branch in the wrong place, so your work and the server's
history could drift apart and the next push could get stuck. Now: a branch
is always created locally first and only appears on the server the first
time you push it; if you check out a branch that lives only on the server,
it is downloaded and recreated exactly; and the server side (which shipped
with Deltix-Server v0.9.3) creates the branch on its end the first time
you push to it. The "remote branch without local branch" situation that
started the recent sync incidents is now impossible, and there is no need
for any manual repair step.
Added
deltix checkout <branch>anddeltix branch checkout <repo> <branch>
now fetch-and-materialize a branch that exists only on the server: pull
its full history, recreate its tables ontoorigin/<branch>(git fetch),
then create the local branch at that ref and switch to it (git DWIM).
This is the fix for the "remote branch without local branch" state from
issue #57 — the client never needs a manual recovery path to publish.- New shared helper
checkout-branch.ts(checkoutBranchLocalFirst()) used
by bothdeltix checkoutanddeltix branch checkout.
Fixed
deltix checkoutused to create a missing local branch at the wrong
commit.VersioningLocalService.checkoutBranch()previously created a
not-yet-existing branch withdolt checkout -b <branch>, which starts at
the current head. Whenorigin/<branch>had already been materialized
(a previous fetch/pull/push of that branch), the new local branch
diverged from its remote from the very first commit — reproducing the
remote-vs-local drift. It now does git-style DWIM: iforigin/<branch>
exists it runsdolt checkout -b <branch> origin/<branch>, and only
falls back to the current-head create when the branch exists nowhere on
the machine. The same DWIM is used by the "sql-server is running" branch
ofcheckout()(the server is stopped, checkout runs, restarted).deltix branch createwas server-first. It created the branch on the
server and only fell back to a local create when the server was
unreachable — the very flow that left a branch existing remotely with no
local counterpart. It is now local-first (git-style): only the local
branch is created, and the message points atdeltix pushto publish it.
A server-only create remains as a fallback only when the repo has never
been cloned/pulled locally (no local data dir).- Applying a pull onto a branch that had never existed locally failed.
applyCommits()passed the missing branch head todolt branchand hit
a dolt "invalid usage" error. It now bootstraps the replay from the
repo's root commit — the same basedeltix clonestarts from — so a
full-history pull onto a freshorigin/<branch>re-creates the branch as
a clean line of commits that can then be DWIM-checked out.
Tests
- New integration tests (real dolt, guarded) prove both fixes: (1) DWIM
checkoutcreates the local branch atorigin/<branch>'s head rather
than the current head — the exact divergence scenario from issue #57; (2)
a full-historyapplyCommits()onto a never-materialized branch followed
by DWIM checkout yields the correct table rows on the new branch. - 143 client unit tests pass;
bun run lintclean (no errors).
Full Changelog: v0.8.13...v0.8.14
v0.8.13 - Fix sync-state branch mismatch after branch self-heal
[0.8.13] - 2026-09-04
In plain terms: when the app noticed your project's saved branch name was
wrong and fixed it (the improvement from the last release), it forgot to
also update a second, related record that keeps track of "what you already
have downloaded." That mismatch made the app think you'd never synced at
all, so on your next pull it downloaded and replayed your entire commit
history again under brand-new IDs — even though you already had all of it.
Usually the data still ended up correct by luck, but it's wasteful and, in
rarer cases, risky. This is fixed: both records are now corrected together,
so a corrected branch name no longer resets your sync history.
Fixed
- Root cause of the "entire history replayed with new commit hashes"
behavior reported repeatedly on issue #57 (referred to there as "bug #5"),
for the specific case where it followed a branch self-heal: the persisted
sync state (.deltix-sync-state, which records the last known server
commit sopull/fetchcan ask the server "what's new since this point"
instead of "give me everything") is stored keyed by branch name. When
reconcileBranch()(added in 0.8.9) corrected a stale branch name in
.deltix/config.toml, it updated the config but never updated this
sync-state file to match. The very nextpull/fetchthen looked up the
sync state under the new (correct) branch name, found nothing, and
treated the client as never having synced — causing the server to send,
and the client to reapply, the complete commit history under new hashes.
AddedVersioningLocalService.renameSyncStateBranch()and wired it into
reconcileBranch()so the sync state now migrates alongside the branch
correction, keeping the two records in lockstep.
Tests
- New unit tests for
renameSyncStateBranch(): re-keys existing state from
the old branch to the new one while preserving the recorded server head;
is a no-op when there is no state file yet; is a no-op when the state is
keyed under a branch other than the one being renamed; is a no-op when
old and new branch names are identical. - New unit test on
reconcileBranch()asserting it calls
renameSyncStateBranch()with the exact old/new branch pair whenever it
corrects a mismatched branch, as a direct regression guard for this bug. - Full unit suite: 141/141 passing (up from 136, +5 new tests this release).
- Full integration suite run: only the two previously-documented,
environment-dependent pre-existing failures observed (a Bun shell-quoting
bug inpush-pull-roundtrip.integration.test.tsand a timing/cleanup race
inapply-commits-idempotency.integration.test.ts), both confirmed via
git stashbaseline comparison to be unrelated to this change. - Typecheck: no new errors versus the pre-change baseline (same
pre-existingtscerrors on both sides, confirmed viagit stash
comparison).
v0.8.12 - Fix reconcileBranch inert when sql-server not running
[0.8.12] - 2026-09-04
In plain terms: the "self-heal your branch settings" fix from 0.8.9 had
a hidden requirement that was never actually true in practice: it only
worked while a specific background database process happened to be
running. In the real world that process usually isn't running when you
type deltix pull, so the self-heal silently never kicked in — the CLI
kept quietly trusting old, incorrect branch settings indefinitely, even
though it looked like it should have fixed itself. Fixed: the CLI now has
a second, reliable way to figure out your real current branch that doesn't
depend on that background process being up, so the self-heal from 0.8.9
finally works the way it was supposed to from the start.
Fixed
reconcileBranch()(the v0.8.9 self-heal for stale
.deltix/config.tomlbranch values) was silently inert whenever the
local embedded Dolt server wasn't already running — which, per the
user's real-world testing on issue #57, is apparently the common case
fordeltix pull/fetch.getCurrentBranch()only ever tried the MySQL
wire protocol against a runningdolt sql-serverand returnednull
unconditionally on any connection failure, with no fallback — so
reconcileBranch()always fell back to the (possibly stale) persisted
config branch, defeating the whole point of the fix. Confirmed via a
real repro:deltix pullreportedbranch: mainandhead: -for a
user who was actually onsync-develop-base, becausemainhad been
deleted locally and the client was silently still trying to operate on
it.getCurrentBranch()now falls back to parsingdolt branch -avia the
CLI (mirroring the fast-path/fallback splitlistBranches()already
used) whenever the sql-server isn't reachable, so the actual checked-out
branch is found either way.
Tests
- New integration test
(tests/integration/versioning-local/get-current-branch.integration.test.ts,
realdoltbinary, no sql-server started) verifiesgetCurrentBranch()
correctly reports the checked-out branch through the CLI fallback path,
both onmainand after switching to another branch — and returns
nullfor a repo with no local data dir. Full unit suite (136 tests)
passes; typecheck shows no new errors. Two pre-existing, unrelated
integration-test flakiness issues (real-Dolt-binary timing/cleanup races
inapply-commits-idempotency.integration.test.ts, and a Bun shell
quoting issue inpush-pull-roundtrip.integration.test.ts) were
confirmed present onmainbefore this change too, viagit stash
comparison, and are unrelated to this fix.
v0.8.11 - Show what pull/fetch compared against on 'already up to date'
[0.8.11] - 2026-09-04
In plain terms: when pull/fetch say "already up to date", there was
no way to double-check whether that was actually true — you had to just
trust it. This made a real corrupted-tracking-ref scenario look
suspicious/unverifiable from the outside during testing. Fixed: pull and
fetch now show exactly which local branch and which commit they compared
against whenever they report "up to date" / "no new commits", so this can
be checked independently instead of taken on faith.
Changed
deltix pull/deltix fetch's "Already up to date" / "No new commits"
messages now print the branch name, the local branch head, and the
hash they compared it against (comparedAgainst), instead of a bare
informational line. This doesn't change any sync logic — it only makes
an already-correct decision visible for verification.
Investigation note (issue #57)
- A follow-up report claimed a "false positive up to date": the user's
sync-develop-baseHEAD didn't matchorigin/main. This is expected —
origin/mainis the remote-tracking ref for the (unrelated, previously
corrupted-then-deleted)mainbranch, not forsync-develop-base.
pull/fetchonsync-develop-basecompare against
origin/sync-develop-base(or the persisted per-branch sync state), and
never touchorigin/main. This release's new output is meant to make
that distinction directly visible next time, instead of requiring a
manualdolt log <ref>cross-check against the wrong ref.
Tests
- Full unit suite (136 tests) passes; no new typecheck errors beyond the
same pre-existing unrelated ones already present onmain.
v0.8.10 - Fix 'target commit not found' on already-up-to-date pull/fetch
[0.8.10] - 2026-09-04
In plain terms: even after the 0.8.9 self-heal fix, pull/fetch could
still fail with target commit not found on repos where nothing new had
happened since the last sync ("already up to date"). This was a leftover
bug from before both prior fixes: on that specific "nothing new" path,
the CLI accidentally tried to save the server's own commit ID as if it
were a local one, which Dolt doesn't understand — so it errored out. Fixed:
that redundant, wrong step is now removed; the correct bookkeeping (used by
every other code path already) is all that's needed here too.
Fixed
pull/fetchno longer fail withtarget commit not foundon the
"already up to date" / "no new commits" fast path. Root cause: both
runPull()andrunFetch()called
local.advanceRemoteRef(identity, branch, serverHead)on that path —
butadvanceRemoteRefrunsdolt branch -f origin/<branch> <hash>,
which requires a local Dolt commit hash, whileserverHeadis the
server's own commit identifier (a different value space entirely, as
already documented ingetRemoteHead()'s existing comment about exactly
this mismatch). Passing the server hash straight through reproduced the
original "target commit not found" failure whenever a pull/fetch found
no new commits to apply.- The fix simply removes that incorrect
advanceRemoteRefcall from both
fast paths —saveSyncState(identity, branch, serverHead)alone is
correct and sufficient, sincegetRemoteHead()already prefers the
persisted sync state over the raworigin/<branch>Dolt ref for the next
negotiation. No other code path was affected: every other call to
advanceRemoteRefalready passes a real local Dolt commit hash (from
applyCommits()orgetBranchHead()), not a server hash.
Tests
- Full unit suite (136 tests) passes; typecheck shows no new errors beyond
the same pre-existing unrelated ones present onmainbefore this
change.
v0.8.9 - Self-heal stale branch config
[0.8.9] - 2026-09-04
In plain terms: v0.8.8 fixed pull/push/fetch to respect whatever
branch you actually checked out — but only for branch switches made after
installing that fix. If you had switched to a non-default branch (like
sync-develop-base) before upgrading, the CLI's saved project settings
still secretly remembered the old default branch (main). After upgrading
to 0.8.8, pull stopped crashing — but it silently started operating on
main instead of your real branch, replaying old history on top of it and
overwriting data with no error at all. Fixed: the CLI now double-checks
which branch is actually active before every pull/push/fetch, and
fixes its saved settings automatically if they were out of date — so this
self-heals on your very next sync, no manual steps needed.
Fixed
- Stale pre-existing project configs no longer cause
pull/push/fetch
to silently operate on the wrong branch. Root cause: any project bound
or checked out before v0.8.8 shipped never had its real branch written
to.deltix/config.toml(that persistence was only added in 0.8.8), so
the file was left holding the schema's default value ('main') even
though the user had genuinely been working on a different branch the
whole time on disk. After upgrading to 0.8.8, the CLI faithfully read
that stalemainvalue and operated on it — landing commits that were
already part of the user's real history back ontomainunder new
hashes, overwriting at least one column withNULLand dropping a row
from__hbsmigrationhistory, all while reporting success (exit 0). - Added
reconcileBranch()insrc/cli/commands/remote.ts, used by
runPull(),runFetch(), andrunPush(): before touching any commits,
it asks the running local Dolt server what branch is actually checked
out (VersioningLocalService.getCurrentBranch(), now public) and, if
that disagrees with the saved config, trusts the real on-disk branch and
rewrites.deltix/config.tomlto match — so this only needs to happen
once per affected project, on its next sync. - If no local server is reachable, reconciliation safely no-ops and falls
back to the previously saved branch (same behavior as before this fix)
rather than failing the command.
Tests
- New unit tests (
tests/unit/cli/reconcile-branch.test.ts) cover: (1) a
stale config (branch: 'main') with a different branch actually checked
out (sync-develop-base) — asserts the real branch wins and gets
persisted for next time; (2) config already matching the real branch —
no-op; (3) no local server reachable — falls back to the saved config
value unchanged. Full unit suite (136 tests) passes; pre-existing
integration test failure in
push-pull-roundtrip.integration.test.ts(unrelated Bun shell/CLI
quoting issue) confirmed present onmainbefore this change too.
v0.8.8 - Fix pull/push/fetch branch mismatch
[0.8.8] - 2026-09-04
In plain terms: if you ever switched your project to a branch other
than the default one (for example sync-develop-base), deltix pull,
push, and fetch were silently ignoring that and working against main
instead — even though deltix branch checkout looked like it had switched
you correctly. In practice this meant your real branch could look like it
"disappeared," because nothing was actually keeping it in sync; the CLI was
quietly operating on a different branch the whole time. Fixed: the CLI now
remembers and uses the branch you actually checked out for every pull,
push, and fetch.
Fixed
deltix branch checkout <repo> <name>now persists the checked-out
branch to.deltix/config.toml(via the previously-unused
LocalProjectService.setBranch()). Before this fix the checkout only
changed the branch on the Dolt server/working copy — the CLI's project
config still remembered whatever branch was bound atinittime (almost
alwaysmain).resolveServerIdentity()now returns the project's actual bound
branch (ServerIdentity.branch), sourced from.deltix/config.toml,
instead of always resolving repo/projectRoot with no branch awareness.
Falls back to the default branch only when no project is bound in the
current directory (e.g. a bare--repoflag with no.deltixproject).deltix pull,deltix push, anddeltix fetchnow operate on
identity.branchinstead of a hardcodedmain/DEFAULT_BRANCH
literal. This was the root cause of a reported incident where a user's
real working branch (sync-develop-base) appeared to vanish after an
interruptedpull— the CLI had never actually been operating on that
branch; it was always pulling/pushing/fetching againstmain, so the
orphaned temporary branch and the migration-history row mismatch the user
observed are consistent with this branch mismatch, not a Dolt-level data
loss event.deltix cloneis intentionally unchanged (a fresh clone has
no bound project yet, so defaulting tomainremains correct).
Tests
- New unit test (
tests/unit/cli/resolve-server-identity.test.ts) verifies
resolveServerIdentity()returns the project's persisted branch after
setBranch(), and falls back to the default branch when no project is
bound. Confirmed the test fails (returnsundefinedfor.branch)
against the pre-fix code and passes after the fix (TDD). - Full existing unit suite (133 tests) and the real-Dolt-binary integration
suite (apply-commits-idempotency,import-auto-increment, etc.) re-run
clean with no regressions;push-pull-roundtrip.integration.test.ts's
pre-existing unrelated failure (a Bun shell-quoting issue with
--author=<email>) was confirmed present before this change too and is
out of scope here.
Full Changelog: v0.8.7...v0.8.8
v0.8.7 - send push base and handle non-fast-forward rejection
[0.8.7] - 2026-09-04
In plain terms: deltix push used to accept a push even when someone
else had already pushed newer work to the same repository in the meantime —
and that could quietly overwrite or orphan their commits with zero warning,
exactly what git protects against. Now the push behaves like git: it sends the
server the point it last pulled from, and if the remote has advanced beyond
that, the server refuses the push and deltix push clearly tells you to
deltix pull first. No more silent data loss on a shared repo.
Changed
deltix pushnow sends a push base (from) to the server — the remote
head it last pulled from (the persisted server head from.deltix-sync-state,
falling back to the localorigin/mainref). The server compares that against
its ownmainhead and rejects a non-fast-forward push with a409.- New
NonFastForwardErrorsurfaced as a clear message — "the remote has
advanced. Rundeltix pullfirst" — instead of the push silently applying.
Tests
- Unit suite passes: 131 tests, 0 failures (push service now forwards
from). - The shared round-trip integration test could not be run in this environment
(the local Bun shell mis-parses the--author=deltix <deltix@deltix.local>
redirect in the test harness — unrelated to this change). The new push-guard
logic itself is covered by the server's own unit suite: matchingfrom
accepted, stalefromrejected withNonFastForwardError, and absentfrom
accepted for backwards compatibility.