Repository navigation
v0.28.0
Migrate onto go-strictcli v0.33.0: presence declared on every flag and argument, push and doctor take a required choice, scrub match and scrub run take member-spelled selectors, and author rewrite declares its constraints.
Context
The declaration-regime campaign's Phase F for safegit. strictcli v0.33.0 refuses a
declaration whose presence is unstated, and refuses a value default on any flag or
positional arg of a mutating command -- on a mutating command a value the framework
picked is a value the framework writes. Together with the deletion of MutexGroup and
CoRequired, that turns four hand-rolled selections and one hand-written guard into
declarations the parser enforces and --help renders.
Two CLI spellings change and one does not, and the split is deliberate. push's four
mode bools and doctor's three collapse into one required choices flag each, because a
bool member could be negated into a state that elected nothing -- which is exactly how
--no-only-tags used to push HEAD. scrub match's --replace/--mangle and scrub
match/run's --from/--entire-history become member-spelled selectors, which keeps every
flag an operator types unchanged and reproduces the old refusal sentences byte for
byte; the tools that drive those commands need no change.
Exit codes move at every converted site: a hand guard returned safegit's own usage
code (2, or 70 for the unreachable-state refusals) and a framework parse error exits 1.
Breaking
- The CLI declares what it accepts; three hand-written guards are gone, and two spellings changed.
safegit push --only-head|--only-branches|--only-tags|--both-branches-and-tagsbecomessafegit push --refs head|branches|tags|both, andsafegit doctor --diagnose|--fix|--uninstallbecomessafegit doctor --action diagnose|fix|uninstall— neither has a default, and the negation that made--no-only-tagspush HEAD and--no-fixrun the diagnose path no longer exists at all.scrub match's--replace/--mangleandscrub match/scrub run's--from/--entire-historykeep their exact spellings and their exact refusal messages, now as declared selections rather than mutex groups.author rewritedeclares its two pairs and its at-least-one rule as constraints, rendered in--help; a missing or half-typed pair is refused by the parser and exits 1 instead of 2, and the two statespushandscrub matchused to refuse with exit 70 are unrepresentable. Every flag and positional argument now declares its presence, so--helpmarks each one[required],[optional]or[default: v];--amend,--allow-empty,--pre-push-hook,--force-with-lease,--bypass-session,--count,--diff,--limit,--overwrite-remote-backupand--allow-public-remotecarry no default value any more and name their fallback in their own help text, behaving exactly as before when omitted. - The machine envelope declares
interface_version: 2. Machine mode (--json) is the CLI framework's, and the framework's envelope contract advanced with the release safegit now builds against: the document gains awritesmember (alwaysnullhere — safegit declares no update command) and the version it reports is 2. A consumer that pinsinterface_version == 1must be updated before it can read safegit's output.
Fixes
- Released binaries report their real version again. The goreleaser build stamped
main.Version, a variable that does not exist; every published binary fell back to the module pseudo-version, sosafegit versionandsafegit --versionreported something like0.27.1-0.20260814034848-8737c897423ainstead of the release tag.