Give bare checkout, push, and pull git-like defaults¶
The intended onboarding flow is init → checkout <name> → remote add → bind → pull, but v1 required the explicit forms (checkout create <name>, push --all, pull --all) and made the bare invocations errors. Bare forest checkout <name> now creates, registers, and activates the checkout when the name is not registered (and still just switches when it is). Bare forest push / forest pull now target every bound stage, printing a per-stage warning (Warning: stage 'x' is not bound; skipping. Run: forest bind x <PATH>) for unbound stages instead of aborting — a fresh clone with one bound stage can pull immediately. --all keeps its strict semantics: any unbound stage aborts the whole transfer, so scripts that must move everything still fail loudly.
When no active remote is set and exactly one remote is configured, remote
resolution falls back to that remote instead of erroring — remote add origin
followed by bare push/pull just works, and forest remote use is only
required once a second remote exists. The fallback never writes local.yaml;
it is inferred per invocation, so adding a second remote restores the explicit
remote use requirement.
Read commands and follow-ups (2026-07-01)¶
Live verification of the fresh-clone flow (bind one stage of several, start working) surfaced three gaps; the same contract now extends to them:
- Bare
forest statusandforest diffcover bound stages with the same per-stage warning, exiting 1 only when no stage is bound (or none is configured). A skipped stage contributes no rows at all — its sync-state entries do not resurface asremote-only. Explicit--stage xon an unbound stage keeps the hard error.forest lsis remote-driven and never needed a binding, so it is unchanged. forest checkout remove --yesskips the confirmation prompt, giving the auto-create trade-off a scriptable undo (removal stays metadata-only, ADR 0001). Without--yes, the non-interactive-terminal guard is unchanged.forest add STAGE PATH --sync-by [subdirectory|directory|file]sets the unit-discovery mode at creation instead of requiring a hand-edit offorest.yaml; the default (subdirectory) is not serialized. When a bare push finds no units but a bound stage directory is non-empty, it prints a one-line hint naming the stage'ssync_bymode.
Consequences¶
forest checkout <name>on an unregistered name runs the create flow, including the legacy-root (forest checkout adopt) guard and checkout-name validation; typo'd names create a checkout, whichforest checkout remove(orremove --yesin scripts) undoes.- Bare
push/pullwith zero configured stages keep the existing "no stages configured" error; with stages but zero bound they exit 1 after the warnings. - Bare
pulldiscovers units from the remote (likepull --all); barepushdiscovers them locally (likepush --all). checkout create,--all,--stage,--id, and explicit unit ids behave exactly as before.- All remote-using commands (
push/pull/status/diff/ls) inherit the single-remote fallback via_resolve_remote; with two or more remotes and no active one they error as before. - Contract locked in
tests/test_bare_command_defaults.py; supersedes VAL-PULL-028 / VAL-PUSH-035 usage-error expectations.