newgit Docs GitHub
Contents

Behavior worth knowing

export fails closed. Source ships (its audience is everyone) and so do trackers whose audience is public. Anything narrower is withheld and reported; --include <path> overrides. It writes one commit, not history, because exporting the branch's commits would carry any file they contain — including withheld ones. This is a path-level filter, not concealment.

GitHub stays where it is. newgit export --remote widget pushes a composed history to an ordinary repository that a tracker's own definition declares: export = "github.com/acme/widget" in .newgit/trackers/root.toml. A tracker with export = "inherit" ships wherever its parent ships, and one with no export never ships, so what leaves fails closed. newgit tracker create --git --path <dir> writes "inherit" for you, so carving a directory out never drops it from a mirror. A target declared by a tracker other than root is rooted at it (its files at the top), so a library can ship inside the project's mirror and on its own (export = ["inherit", "github.com/acme/lib"]). Definitions live in access, so widening where anything ships takes an owner's merge. A history that ever committed the file of a tracker outside Git is refused. Exporting again fast-forwards, after bringing in whatever was merged on the target since, and the push uses your own Git credentials, so gh, GitHub Actions, and anyone cloning from GitHub keep working. With branches = true, every push from a workspace exports its branch there too, and on a newgit remote the workspace gets the target as the remote gh resolves, so an agent's git push then gh pr create opens a real pull request.

Tags are the project's. On a newgit remote, git tag v1.0 && git push origin main v1.0 (or git push --follow-tags) in the project root names that point of main on the remote, then on each export target carrying root's history (the one root declares), at its view of the commit; a GitHub release made on a mirror comes back as the same tag. A target declared by a child tracker (t3code's fork) gets none: it has versions of its own, and a tag never moves, so the project's v0.9.0 there would take that name from it for good. Tags coming in from such a target are refused for the same reason. git fetch brings tags from the remote like any other. A tag never moves, and names only what main has: tag from the project root once the work is merged, not from a workspace.

[[render]] puts this instance's ports in the config file your tool actually reads. Most tools take a port from a committed config file rather than argv, so a resource declares literal substitutions into one:

[[render]]
path = "supabase/config.toml"
replace = [
  { find = "port = 54321", with = "port = {{ports.api}}" },
]

There is no template file — port = 54321 is your working default, so a clone without newgit still starts on it. find is literal, never a regex, and must match exactly once; that check is also the drift detector, failing the bind by name when the default changes upstream rather than quietly doing nothing. Rendered source files are marked --skip-worktree, so they never show in git status and git add -A cannot commit them — which also means real edits to a rendered file do not survive the workspace. newgit says so at bind. For a tracker-owned file, tracker capture reverses the substitution, so edits you make beside the rendered value reach the lane and your port does not. A render writes only a regular file of its own: a rendered path that is a symlink, or lies under a symlinked directory, is refused by name rather than written through to wherever the link leads, and a hard link there is replaced by a new file, so its other names keep what they held (spec).

Several resources may render one file — db its URL and web its port into the app's .env.local — each declaring only the values it owns. They apply as one batch, so the order they bind in does not matter; two resources claiming the same text are refused, naming both.

A file rendered once is not read again by a process already running on it. When tracker use or drop changes a rendered file's bytes (binding a per-branch database writes its port into apps/admin/.env.local, say), each process that was running before restarts if its resource declares reads covering the file, and is named with the command that restarts it if it declares nothing:

reads = ["apps/admin"]   # a dev server run from apps/admin reads its .env.local

A render can also target a file inside a resource's own [identity] produces, a built tree rather than source. That is how an install whose tree records its workspace path can still be shared through the install store (newgit reference render).

A workspace's origin is the real remote. git pull and gh see the project's repository, and git push checkpoints the instance before forwarding the push there — succeeding only if that remote accepted it. gh pr create works from the workspace with no flags.

Branching inside a workspace is fine. git checkout -b try-x in an instance's workspace works the way Git does. A checkpoint captures try-x as it stands, and undo returns to it, but the instance's own branch stays where it was until you switch back and commit there. status shows feature-a@1a2b3c4d (workspace on `try-x`) while that is the case.

cleanup never breaks an undo. It finalizes instances whose workspace is gone, deletes unclaimed workspaces and dead process state, and prunes tracker snapshot revs nothing references — but never a rev a checkpoint still points at, and never a checkpoint record. project- and user-owned resources are never torn down by per-branch cleanup.

The one exception is one you ask for. An archived instance's checkpoints are unreachable — undo needs a binding record — yet they go on pinning revs, so newgit remove <name> --purge and newgit cleanup --purge-archived discard that history and release what it held. Live instances are never affected, and ordinary cleanup says how many of its retained revs the flag would free.