Skip to content

Releases: SammyBytes/Deltix-Client

v0.8.16

Choose a tag to compare

@SammyBytes SammyBytes released this 07 Sep 22:57

[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_reset staging round behind the schema-only flow;
    no changes to the existing commit/push/pull pipeline for normal use.

Full Changelog: v0.8.15...v0.8.16

v0.8.15 - Git-style working-tree maintenance (deltix reset --hard / clean)

Choose a tag to compare

@SammyBytes SammyBytes released this 07 Sep 22:27

[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 (use deltix clean for 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/-n lists the untracked tables that would be
    deleted without deleting anything.
  • Both commands run against the live local dolt sql-server session 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 — no deltix stop/
    start dance. Unlike dolt checkout, the CLI dolt 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 shared normalizeStatusRows() 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; clean deletes untracked tables
    and leaves tracked working changes untouched; clean --dry-run lists
    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 lint clean
    (no errors). Manually smoke-tested the CLI end-to-end: deltix clean --dry-run → deltix reset --hard → deltix clean leaves 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

Choose a tag to compare

@SammyBytes SammyBytes released this 07 Sep 21:59

[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> and deltix branch checkout <repo> <branch>
    now fetch-and-materialize a branch that exists only on the server: pull
    its full history, recreate its tables onto origin/<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 both deltix checkout and deltix branch checkout.

Fixed

  • deltix checkout used to create a missing local branch at the wrong
    commit.
    VersioningLocalService.checkoutBranch() previously created a
    not-yet-existing branch with dolt checkout -b <branch>, which starts at
    the current head. When origin/<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: if origin/<branch>
    exists it runs dolt 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
    of checkout() (the server is stopped, checkout runs, restarted).
  • deltix branch create was 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 at deltix push to 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 to dolt branch and hit
    a dolt "invalid usage" error. It now bootstraps the replay from the
    repo's root commit — the same base deltix clone starts from — so a
    full-history pull onto a fresh origin/<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
    checkout creates the local branch at origin/<branch>'s head rather
    than the current head — the exact divergence scenario from issue #57; (2)
    a full-history applyCommits() 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 lint clean (no errors).

Full Changelog: v0.8.13...v0.8.14

v0.8.13 - Fix sync-state branch mismatch after branch self-heal

Choose a tag to compare

@github-actions github-actions released this 04 Sep 20:31

[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 so pull/fetch can 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 next pull/fetch then 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.
    Added VersioningLocalService.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 in push-pull-roundtrip.integration.test.ts and a timing/cleanup race
    in apply-commits-idempotency.integration.test.ts), both confirmed via
    git stash baseline comparison to be unrelated to this change.
  • Typecheck: no new errors versus the pre-change baseline (same
    pre-existing tsc errors on both sides, confirmed via git stash
    comparison).

v0.8.12 - Fix reconcileBranch inert when sql-server not running

Choose a tag to compare

@github-actions github-actions released this 04 Sep 20:17

[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.toml branch 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
    for deltix pull/fetch. getCurrentBranch() only ever tried the MySQL
    wire protocol against a running dolt sql-server and returned null
    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 pull reported branch: main and head: - for a
    user who was actually on sync-develop-base, because main had been
    deleted locally and the client was silently still trying to operate on
    it.
  • getCurrentBranch() now falls back to parsing dolt branch -a via the
    CLI (mirroring the fast-path/fallback split listBranches() 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,
    real dolt binary, no sql-server started) verifies getCurrentBranch()
    correctly reports the checked-out branch through the CLI fallback path,
    both on main and after switching to another branch — and returns
    null for 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
    in apply-commits-idempotency.integration.test.ts, and a Bun shell
    quoting issue in push-pull-roundtrip.integration.test.ts) were
    confirmed present on main before this change too, via git stash
    comparison, and are unrelated to this fix.

v0.8.11 - Show what pull/fetch compared against on 'already up to date'

Choose a tag to compare

@github-actions github-actions released this 04 Sep 20:05

[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-base HEAD didn't match origin/main. This is expected —
    origin/main is the remote-tracking ref for the (unrelated, previously
    corrupted-then-deleted) main branch, not for sync-develop-base.
    pull/fetch on sync-develop-base compare against
    origin/sync-develop-base (or the persisted per-branch sync state), and
    never touch origin/main. This release's new output is meant to make
    that distinction directly visible next time, instead of requiring a
    manual dolt 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 on main.

v0.8.10 - Fix 'target commit not found' on already-up-to-date pull/fetch

Choose a tag to compare

@github-actions github-actions released this 04 Sep 19:50

[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/fetch no longer fail with target commit not found on the
    "already up to date" / "no new commits" fast path.
    Root cause: both
    runPull() and runFetch() called
    local.advanceRemoteRef(identity, branch, serverHead) on that path —
    but advanceRemoteRef runs dolt branch -f origin/<branch> <hash>,
    which requires a local Dolt commit hash, while serverHead is the
    server's own commit identifier (a different value space entirely, as
    already documented in getRemoteHead()'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 advanceRemoteRef call from both
    fast paths — saveSyncState(identity, branch, serverHead) alone is
    correct and sufficient, since getRemoteHead() already prefers the
    persisted sync state over the raw origin/<branch> Dolt ref for the next
    negotiation. No other code path was affected: every other call to
    advanceRemoteRef already passes a real local Dolt commit hash (from
    applyCommits() or getBranchHead()), not a server hash.

Tests

  • Full unit suite (136 tests) passes; typecheck shows no new errors beyond
    the same pre-existing unrelated ones present on main before this
    change.

v0.8.9 - Self-heal stale branch config

Choose a tag to compare

@github-actions github-actions released this 04 Sep 19:34

[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 stale main value and operated on it — landing commits that were
    already part of the user's real history back onto main under new
    hashes, overwriting at least one column with NULL and dropping a row
    from __hbsmigrationhistory, all while reporting success (exit 0).
  • Added reconcileBranch() in src/cli/commands/remote.ts, used by
    runPull(), runFetch(), and runPush(): 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.toml to 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 on main before this change too.

v0.8.8 - Fix pull/push/fetch branch mismatch

Choose a tag to compare

@SammyBytes SammyBytes released this 04 Sep 18:46

[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 at init time (almost
    always main).
  • 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 --repo flag with no .deltix project).
  • deltix pull, deltix push, and deltix fetch now operate on
    identity.branch
    instead of a hardcoded main/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
    interrupted pull — the CLI had never actually been operating on that
    branch; it was always pulling/pushing/fetching against main, 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 clone is intentionally unchanged (a fresh clone has
    no bound project yet, so defaulting to main remains 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 (returns undefined for .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

Choose a tag to compare

@github-actions github-actions released this 04 Sep 16:59

[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 push now 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 local origin/main ref). The server compares that against
    its own main head and rejects a non-fast-forward push with a 409.
  • New NonFastForwardError surfaced as a clear message — "the remote has
    advanced. Run deltix pull first" — 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: matching from
    accepted, stale from rejected with NonFastForwardError, and absent from
    accepted for backwards compatibility.