Updated Edit
On this page
Complete CLI reference for safegit — all available commands, subcommands, flags, arguments, and usage examples with detailed descriptions.
#safegit CLI Reference
concurrency-safe git wrapper for multi-agent use with atomic commits, oplog-based undo, and history rewriting
Version: 0.29.2
#Commands
- commit -- stage and commit specified files in a single atomic operation
- mv -- move tracked paths and commit the moves with their records in one operation
- merge-continue -- conclude a merge git stopped before committing. Every conflicted path is named with --resolve (or in a --resolve-file), and safegit writes the merge commit itself: HEAD plus the MERGE_HEAD line as parents; the merge's whole staged result as its tree, so a path the merge staged cleanly is never dropped; git's own message draft with its comment block stripped, or -m; the repository's commit-msg hook run and safegit's trailers injected; and the merge's whole state-file set removed afterwards, so a later commit is not refused. An empty merge needs no flag -- a merge commit records its parents whether or not the tree changed. Two merge shapes only raw git can start are REFUSED, each naming git's own 'merge --continue' and '--abort': an OCTOPUS, because every check safegit makes over a merge is written against two sides, and a content conflict git recorded with no AUTO_MERGE, which is a non-default strategy's signature and leaves the marker verification nothing to read
- cherry-pick-continue -- conclude a cherry-pick git stopped before committing. Every conflicted path is named with --resolve (or in a --resolve-file), and safegit writes the commit itself: one parent, the AUTHOR preserved from the commit being applied while the committer is you, git's own message draft with its comment block stripped or -m, the repository's commit-msg hook run, and the cherry-pick's state files removed afterwards. A QUEUED sequence --
git cherry-pick <a> <b>, which only raw git can start, since safegit's cherry-pick applies one commit -- is REFUSED, naming git's own 'cherry-pick --continue' and '--abort': the queue is part of the state a conclusion removes, so finishing one step of it would throw the rest away - revert-continue -- conclude a revert git stopped before committing. Every conflicted path is named with --resolve (or in a --resolve-file). For a SINGLE revert safegit writes the commit itself: one parent, YOU as both author and committer -- a revert is your own new change, not the reverted commit author's, which is git's own division and the opposite of what a cherry-pick does -- git's own message draft with its comment block stripped or -m, the repository's commit-msg hook run, and the revert's state files removed afterwards. Note the stage keywords: a revert applies an INVERSE patch, so theirs is what the reverted commit's parent held -- resolving to theirs keeps the revert, resolving to ours keeps the commit being reverted. A QUEUED sequence --
git revert <a> <b>, which only raw git can start, since safegit's revert undoes one commit -- is REFUSED, naming git's own 'revert --continue' and '--abort': the queue is part of the state a conclusion removes, so finishing one step of it would throw the rest away - switch -- switch to another BRANCH, guarded twice before git runs: the worktree operation lock, held for the whole command, and then a check for uncommitted work. The command line is a deliberate subset of git's: an existing branch name, or -c to create one, and nothing else. A tag, an object name or any other commit-ish is refused, because switching onto one detaches HEAD -- the state safegit's commit, conclusion and undo paths all refuse -- and the refusal names the raw-git command for the rare deliberate case. --detach, -C, --force/--discard-changes, --orphan and --merge are refused, each naming why. There is NO file mode and no 'safegit checkout': git's checkout of files over the working tree destroys uncommitted work with no record anywhere, so safegit does not implement it at all
- merge -- merge one branch into the current one, and author the result: safegit decides the fast-forward itself and moves the ref under compare-and-swap, or runs git's merge machinery with --no-ff --no-commit and commits the staged result through its own pipeline -- so a merge safegit performed carries safegit's trailers, ran the repository's commit-msg hook and is reversible with 'safegit undo'. A merge git stops on a conflict parks, and 'safegit merge-continue' concludes it; 'safegit merge --continue' is refused and names that command. The command line is a deliberate subset of git's: exactly one branch (no octopus), no strategy selection, no --squash, no --edit and no --autostash. --no-commit computes the merge and leaves it parked even when it is clean. On an UNBORN branch -- one with no commits yet -- a merge can only be a fast-forward, so --no-ff and --no-commit are both refused there before git runs, with the reason
- rebase -- rebase the current branch onto upstream, guarded before git runs: the worktree operation lock -- held for the whole rebase, an interactive one's editor session included, so a second safegit process in this worktree waits that long -- then a check for uncommitted work, and then a refusal to rebase over ANOTHER operation git already has in flight (a rebase over a parked revert exits 0 and strands that revert's state files behind it, blocking every later commit). That last check is kind-scoped: it refuses an in-flight state that is not a REBASE, so a rebase's own --continue, --abort and --skip pass by construction. Those three stay git's either way: safegit has no verb that finishes a rebase. A rebase on an UNBORN branch -- one with no commits yet, so with nothing to replay -- is refused before git runs too, by a separate check beside that one. The command line is a deliberate subset of git's: exactly one upstream, --onto, -i, --autostash and --rebase-merges (whose optional value is attached only). The apply backend and its patch options, --exec and --root are refused, each naming why
- reset -- reset HEAD with guards that prevent accidental data loss. The worktree operation lock is taken for EVERY reset, because every reset moves HEAD; the uncommitted-work check applies to the modes that WRITE working-tree files -- --hard, --merge and --keep -- while --soft and --mixed move only the ref and the index. Which is which is derived from safegit's git classification table, never re-read from the argument list here. The command line is a deliberate subset of git's: one of the five modes with a commit. The PATHSPEC form is refused -- it writes the shared index entry by entry, which is the one file safegit's design keeps out of -- and so is --patch
- bisect -- binary search through commits to find a bug. The worktree operation lock is taken for EVERY invocation; the uncommitted-work check applies to the STEPPING subcommands (start, good, bad, old, new, skip, run, replay, reset), each of which checks another commit out, and not to the reporting ones (terms, log, view). Which is which is derived from safegit's git classification table, never kept as a list here -- and so is which subcommands may be typed at all: a word outside that vocabulary is refused before git runs, as is every option. 'bisect start' on an UNBORN branch is refused before git runs as well: there is no range of commits to search there
- push -- push refs to remote with pre-pre-push hooks and automatic retry
- pull -- fetch from a remote and merge what was fetched, with the merge strategy stated explicitly: --merge-strategy is required and has no default, so a pull never depends on git's own configuration to decide whether it may create a merge commit. The merge step is safegit's own -- the same one 'safegit merge' performs -- so a pull that cannot fast-forward produces a commit carrying safegit's trailers, run through the repository's commit-msg hook and reversible with 'safegit undo'; a pull that can fast-forward moves the ref under compare-and-swap and puts the index and the working tree in step with it. A merge git stops on a conflict parks, and 'safegit merge-continue' concludes it. --rebase is refused and names the two commands that do it
- doctor -- run diagnostic health checks on the repository and optionally repair issues
- cherry-pick -- apply ONE commit onto the current branch, and author the result: git computes the pick with --no-commit and safegit commits the staged result through its own pipeline -- so a pick safegit performed carries safegit's trailers, ran the repository's commit-msg hook and is reversible with 'safegit undo'. The AUTHOR is preserved from the commit being applied and the committer is you, which is git's own division. A pick git stops on a conflict parks -- safegit writes CHERRY_PICK_HEAD itself, because 'git cherry-pick --no-commit' does not -- and 'safegit cherry-pick-continue' concludes it; 'safegit cherry-pick --continue' is refused and names that command. The command line is a deliberate subset of git's: exactly one commit named as a commit (a range or any other revision set is refused, because a range hands the operation to git's sequencer even when it holds one commit), no --edit, no --ff, no --commit, no --cleanup, no signing and no empty-commit flags. --abort and --quit stay plain passthroughs, because they author nothing and are the way out of a state safegit must not refuse over; --no-commit is forwarded to git too, but it COMPUTES, so it takes the same refusal the restructured form does over an operation git already has in flight
- revert -- revert ONE commit by applying its inverse patch, and author the result: git computes the inverse with --no-commit and safegit commits the staged result through its own pipeline -- so a revert safegit performed carries safegit's trailers, ran the repository's commit-msg hook, is reversible with 'safegit undo', and declares the INVERSE of every move record the reverted commit declared. YOU are recorded as both author and committer, because a revert is your own new change rather than the reverted author's; that is git's own division and the opposite of what a cherry-pick does. A revert git stops on a conflict parks, and 'safegit revert-continue' concludes it; 'safegit revert --continue' is refused and names that command. The command line is a deliberate subset of git's: exactly one commit named as a commit (a range or any other revision set is refused, because a range hands the operation to git's sequencer even when it holds one commit), no --edit, no --commit, no --cleanup and no signing. --abort and --quit stay plain passthroughs, because they author nothing and are the way out of a state safegit must not refuse over; --no-commit is forwarded to git too, but it COMPUTES, so it takes the same refusal the restructured form does over an operation git already has in flight
- undo -- reverse the last safegit-authored operation using the oplog -- a commit, an mv, an amend, a reword, a merge, pull, cherry-pick or revert safegit's own commit pipeline authored, or a conclusion (merge-continue, cherry-pick-continue, revert-continue). A fast-forward is REFUSED rather than reversed: the tip it moved onto is a commit git created and safegit never rolls a branch back over one. It moves a REF and never the working tree
- unlock -- release one of safegit's OWN lock files -- a per-ref lock, this worktree's operation lock, or the repository-wide rewrite lock -- left behind by a safegit process that was killed while holding it. It has nothing to do with git's .git/index.lock or any other lock git takes for itself. A lock whose holder is still alive is refused; ordinarily nothing needs this command, because a stale lock is reclaimed automatically by the next contender and 'safegit doctor --action fix' sweeps them, so it is the last-resort path for a filesystem where that reclamation cannot work
- scan -- search git history for regex pattern matches across all objects and working tree files, scanning blobs, commit messages, tag annotations, and trailers with optional scope filtering and commit range selection
- version -- print safegit version, Go runtime version, and git version
#Command Groups
- backup -- push, list, and restore per-branch history backups held in the tool-owned refs/backups namespace on a remote, so uncommitted-to-the-world work survives a lost machine without ever touching refs/heads
- config -- show, get, or set safegit configuration key-value pairs
- hook -- manage pre-pre-push hook scripts that run before every push
- author -- audit and rewrite commit author/committer identity — list all identities, check against expected values, and rewrite name or email across history
- scrub -- surgically rewrite git history to remove or replace sensitive content: file and match rewrite the commits, trees and blobs of a range the caller selects (--from or --entire-history), run applies a recipe of such operations in one coordinated pass, and verify only reads -- it confirms that the patterns named on its command line are absent from the whole object store
#Global flags
| Name | Short | Type | Presence | Env | Description |
|---|---|---|---|---|---|
--config-file | str | optional | path to a custom safegit config file instead of the default location; when omitted the default location is used |
#Framework flags
These flags are owned by the strictcli framework, not by the app. No command may declare a flag with one of these names, and each is recognized anywhere on the command line.
| Flag | Effect |
|---|---|
--dry-run | Preview mode: no mutation runs. The framework prints a log of every effect the command would have performed. |
--approve-consequential | Skips the confirmation prompt a consequential command shows before it runs. |
--quiet | Hides informational output. Warnings, errors, structured data and the dry-run log are never suppressed. |
--verbose | Shows debug output. --quiet wins when both are passed. |
#Infrastructure
#Handshake variables
| Env var | Description |
|---|---|
CLAUDE_CODE_SESSION_ID | Claude Code session identifier set by the invoking agent session; scopes 'safegit undo' to operations this session performed and is recorded as a commit trailer |
#Deprecated
rewrite-author-- use 'safegit author rewrite' instead