Skip to content

Releases: Spheroman/newgit

v0.2.0

Choose a tag to compare

@github-actions github-actions released this 13 Sep 06:50
440f96d

Added

  • [[render]] on a resource substitutes per-instance values into a file the
    project commits (#10).

    [ports] reached commands as {{ports.x}} and as an env var, which assumes
    the tool takes its port on argv. Most do not: Supabase reads
    supabase/config.toml, Expo reads .env, Compose reads compose.yaml.
    Everyone who hit this wrote the same section-aware config rewriter inside
    their prepare hook.

    [[render]]
    path = "supabase/config.toml"
    replace = [
      { find = 'project_id = "faretable"', with = 'project_id = "faretable-{{branch.slug}}"' },
      { find = "port = 54321",             with = "port = {{ports.api}}" },
    ]

    There is no template file. port = 54321 is the project's working default,
    so a clone without newgit still starts on it; newgit substitutes into the
    committed content and writes the result into one workspace. find is a
    literal string, never a regex, and must match exactly once — which is
    also the drift detector: when the default changes upstream, the bind fails
    naming the file and the string instead of quietly doing nothing. A
    multi-line find disambiguates two sections sharing a value, and count = N
    declares a genuine repeat.

    A render reads committed content — HEAD, or the bound lane rev for a
    tracker-owned path — never the working file, so it is idempotent: undo
    and tracker pull re-render off the binding record and values never
    compound.

    Instance values stay out of everything downstream. Source-owned targets are
    marked --skip-worktree, so they never show in git status and git add -A
    cannot commit them; newgit export and a checkpoint's uncommitted-state
    capture both take them from HEAD; and newgit tracker capture reverses
    the substitution for tracker-owned targets, so a key you add to .env.local
    reaches the shared lane and this instance's port does not.

    On a source-owned path, skip-worktree also means real edits to that file in
    this workspace do not survive it. newgit reports that precisely rather
    than as a caveat
    : a render is a pure function of committed content and the
    binding record, so the expected bytes are recomputable, and newgit compares
    against them at checkpoint and before every re-render — naming the file and
    how many lines a re-render will discard, and saying nothing when the file is
    what the render produced.

    Replacements are simultaneous: every find is located in the committed
    content and the whole batch applies in one pass, so a replacement's output
    is never a match target and reordering the replace array cannot change the
    result. Two rules claiming overlapping text are refused by name.

  • newgit reference prints the definition format — every tracker and resource
    key with its type and default, the checkpoint/restore/ownership tables, and
    which template variables are in scope for which hook
    (#13).

    All of it was documented in newgit-v1-mvp.md, and none of it travelled:
    cargo install newgit leaves a binary and a README on disk, and the
    README's relative link to that file resolved to nothing on crates.io,
    docs.rs, or in the registry directory. Reading the crate source — or running
    strings on the binary to enumerate {{...}} variables — was the only way
    to answer what checkpoint.mode accepts. The reference now ships inside the
    binary, which is the one copy guaranteed to be wherever the definitions are,
    and init, tracker create, and resource add each name it. The README's
    links to the design documents are absolute, and say they live on GitHub.

  • newgit status <instance> --path prints that instance's workspace path and
    nothing else (#12).

    A bootstrap script, a README snippet, or an editor integration wanting the
    path had to parse table output or read .newgit/branches/<name>.toml, which
    makes the store layout someone else's API. Now:
    W=$(newgit status auth-refactor --path). The instance is inferred inside a
    workspace, and warnings stay on stderr so stdout is a path.

  • newgit remove <name> --purge and newgit cleanup --purge-archived release
    the snapshot revs an archived instance's checkpoints were pinning
    (#12).

    Cleanup never prunes a rev a checkpoint points at, which is right for a live
    instance and a dead end for a removed one: undo needs a binding record, so
    those checkpoints are unreachable while their revs are permanent. Purging
    drops the checkpoint log and its refs/newgit/checkpoints/<slug>/* store
    refs, and the same pass reclaims what they held; a purging --dry-run
    reports exactly that. It stays opt-in and never touches a live instance's
    checkpoints. Ordinary cleanup now reports how many of its retained revs
    are held only by archived instances, and remove says how many checkpoints
    it kept.

  • newgit tracker capture <tracker> --from-store seeds a lane from the store
    repo's working tree and sets the lane head, so the first spawn comes up
    with the content (#9).

    A lane starts empty and capture reads from an instance workspace, so
    adopting newgit for a tracker carrying .env files meant spawning an
    instance guaranteed to come up without them, copying the files in, capturing,
    merging, and re-running the resource action that had already failed. The
    content was in the store repo at the same relative paths the whole time.
    That bootstrap is now two commands: tracker track, then
    tracker capture --from-store.

    Declared paths with nothing behind them are reported as warnings rather than
    silently seeding a partial lane; a tracker with nothing at all on disk is an
    error, not an empty lane head. newgit tracker track now suggests
    --from-store when the paths it just added already have content.

  • .newgit/scripts/ and a {{scripts}} template variable, so a resource's
    script lives under the same rule as the definition that calls it
    (#8).

    A resource definition is read from the store, but anything its commands
    shelled out to was read from the workspace, where it is subject to source
    materialization. The two halves of one definition lived under different
    rules and only the TOML half was editable in place, so iterating on a
    prepare meant committing every attempt or copying the script into the
    workspace by hand between runs.

    {{scripts}} resolves to .newgit/scripts/ in the store. Edit a script
    and the next newgit action runs it — nothing to commit, nothing to copy,
    and it works on the first spawn. The directory is control plane and is
    listed in init's "commit these" output; init writes a README.md there
    because Git will not track an empty directory. Project-owned scripts are
    unaffected: they stay in the project tree, are read from the workspace, and
    must still be committed before a spawn that calls them.

Changed

  • The command-snapshot template's [actions.migrate] says what it is: a
    convenience command you invoke with newgit action <resource>.migrate, not
    a lifecycle hook. No stage ever ran it, and sitting beside prepare — which
    spawn and a recompute restore do run — it read like one
    (#12).

Fixed

  • A declared captures name that never appeared in an action's stdout failed
    in total silence: the command exited 0, newgit reported prepare: ok,
    marked the resource ready, and published an empty handle that went
    unnoticed until an API call returned 401
    (#7).

    Each missing capture is now warned for by name, with the log to look in and
    the convention that explains nearly every occurrence — when captures is
    set, stdout belongs to newgit, so everything else the command prints should
    go to stderr. Warnings appear at spawn, on newgit action, and during a
    recompute restore. A missing name is still not an error: a resource may
    legitimately publish a handle only on some runs. The external template's
    comments now state the stdout convention too.

  • An undo where a resource restore failed reported Restored on its first
    line and FAILED on its fourth, describing one operation two ways
    (#11). A restore command
    is not transactional — one that rebuilds a schema and then fails to load
    the rows leaves its resource in neither the pre-undo state nor the
    checkpoint state — so the summary no longer implies the instance is in a
    known state:

    Undo of `smoke` to ckpt_001 ("before agent") INCOMPLETE: 0 of 1 resources restored
      `db` may be in a partial state — a failed restore command is not rolled back
    

    newgit undo now exits non-zero when the undo was incomplete.

  • A failed undo left a pre-undo checkpoint indistinguishable from one a human
    named, so three failed attempts left three of them, each pinning its
    tracker revs. The safety checkpoint now records undo_completed once the
    undo it preceded finishes, and newgit checkpoints shows those entries as
    failed-undo rather than before-undo — they are not redo points. The
    record is annotated rather than deleted: newgit cannot know at save time
    whether the undo will succeed, and discarding the only record of a state is
    what checkpoints exist to prevent. Releasing the revs those entries pin is
    a cleanup concern, tracked in
    #12.

  • A resource whose depends_on named something that did not exist yet made
    every newgit command fail, including tracker create and tracker track
    — the commands that create the missing name. The only way...

Read more

v0.1.1

Choose a tag to compare

@github-actions github-actions released this 13 Sep 03:36

Fixed

  • newgit --version reported (unknown) instead of the commit for every
    binary installed from crates.io. The build stamp was derived by running
    git rev-parse, but a published .crate tarball ships no .git, so the
    stamp only ever worked when building from a clone — the one case where you
    can already see the commit. It now reads the sha1 that cargo publish
    records in .cargo_vcs_info.json, falling back to git for repo builds.
    A tarball packaged with --allow-dirty gets the same -dirty suffix a
    dirty clone does.

v0.1.0

Choose a tag to compare

@github-actions github-actions released this 13 Sep 01:59

First release. All seven milestones of the v1 MVP are implemented, and the
product promise holds end to end: given a source revision plus tracker and
resource definitions, newgit materializes a consistent branch instance and
can put the whole thing back.

The two primitives

  • Trackers — named, versioned lanes of file content, each with an
    audience, storage, and source-merge policy. capture, merge, pull,
    and checkout move content through content-addressed lanes; identical
    captures dedupe. source is just the default tracker, special only
    because Git owns its history.
  • Resources — lifecycle units for state that cannot travel as content:
    processes, ports, installs, databases, and things another system owns.
    Command-based hooks, deterministic port allocation, exports, dependency
    ordering, and PID-file supervision for long-running actions.

Commands

init, spawn, status, run, action, checkpoint, undo,
checkpoints, export, remove, cleanup, plus tracker and resource
subcommands for definitions. Instance names are inferred from the workspace
you are standing in.

Checkpoints and undo

One coherent snapshot across source (including uncommitted and untracked
work), every tracker lane, and every resource's state. newgit undo restores
it; it takes a safety checkpoint first, so undo is itself undoable and
running it twice is redo. Failed resource restores leave a recovery record
instead of a half-explained failure.

Export

newgit export --to <dir> writes an ordinary Git repository. Tracker
audience is the default filter and fails closed at public; --include
overrides per path and --exclude wins over everything. One commit, never
history — exporting the branch's commits would carry any file they contain,
including what the filter just withheld. Path-level filtering only; not a
concealment mechanism.

Cleanup

newgit cleanup [--dry-run] finalizes instances whose workspace is gone,
deletes unclaimed workspaces and dead process state, and prunes unreferenced
tracker snapshots. It never removes a checkpoint record, and never a snapshot
rev a checkpoint still points at. Resource [cleanup] hooks run on both
remove and cleanup, gated by ownership: project- and user-owned
resources are never torn down by per-branch teardown.

Templates

process, pnpm, command-snapshot (a daemon-owned database whose
checkpoint deposits into a tracker), and external (a resource newgit holds
only a handle to). Templates bring the companion definitions and tracker
lanes they depend on.

Known limits

Deliberately out of scope for v1, and not bugs: no FUSE projection
(workspaces are full clones), no hermetic builds, no hunk-level privacy, no
native remote, no command shims, and storage = "remote" parses but only
local is implemented. v1 does not claim security properties — it keeps
non-public tracker content out of Git by construction, not against a hostile
agent.

An instance whose workspace is deleted cannot be re-spawned under the same
name until newgit cleanup finalizes it.