git-guard: catch destructive-local ops (reset --hard, clean -f, checkout ., branch -D) #25

Open
opened 2026-07-19 00:25:18 +00:00 by crenshawdev · 0 comments
crenshawdev commented 2026-07-19 00:25:18 +00:00 (Migrated from github.com)

Source: skills-analysis session, 2026-07-18 (comparison against Matt Pocock's git-guardrails-claude-code).

Cadence's git-guard.mjs PreToolUse hook guards push (always ask) and commit on a protected branch (git.on_protected). It does not guard destructive-local commands that can irreversibly wipe uncommitted work: git reset --hard, git clean -f/-fd, git checkout . / git restore ., git branch -D.

This is the one class of git command that destroys work with no recovery, and it's currently unguarded.

Do NOT adopt Matt's skill — his is a bash+jq substring-grep blocklist that false-triggers on echo "git push" and can't tell a dangerous flag combo from a safe one. Cadence's parser is strictly better. This is an extension of the existing git-guard.mjs, not a replacement.

Approach:

  • Extend gitSubcommands() (or add a sibling check) to recognize the destructive set, flag-aware:
    • reset only when --hard is present (soft/mixed reset is fine)
    • clean only with -f/-fd
    • checkout / restore only when the pathspec is . or --
    • branch -D
  • New config key git.on_destructive: ask | deny | allow (default ask), mirroring on_protected.
  • Same philosophy as the rest of the rails: ask, don't hard-block; the harness decides.
  • Stays scoped to Cadence projects (existing planningRoot walk-up); silent elsewhere.

Benefit: the "oh no" git commands stop and ask before running, so a stray reset --hard can't silently vaporize uncommitted work.

Scoped for v1.2.0.

**Source:** skills-analysis session, 2026-07-18 (comparison against Matt Pocock's `git-guardrails-claude-code`). Cadence's `git-guard.mjs` PreToolUse hook guards **push** (always ask) and **commit on a protected branch** (`git.on_protected`). It does **not** guard destructive-local commands that can irreversibly wipe uncommitted work: `git reset --hard`, `git clean -f`/`-fd`, `git checkout .` / `git restore .`, `git branch -D`. This is the one class of git command that destroys work with no recovery, and it's currently unguarded. **Do NOT adopt Matt's skill** — his is a bash+jq substring-grep blocklist that false-triggers on `echo "git push"` and can't tell a dangerous flag combo from a safe one. Cadence's parser is strictly better. This is an **extension of the existing `git-guard.mjs`**, not a replacement. **Approach:** - Extend `gitSubcommands()` (or add a sibling check) to recognize the destructive set, **flag-aware**: - `reset` only when `--hard` is present (soft/mixed reset is fine) - `clean` only with `-f`/`-fd` - `checkout` / `restore` only when the pathspec is `.` or `--` - `branch -D` - New config key `git.on_destructive: ask | deny | allow` (default `ask`), mirroring `on_protected`. - Same philosophy as the rest of the rails: **ask, don't hard-block**; the harness decides. - Stays scoped to Cadence projects (existing `planningRoot` walk-up); silent elsewhere. **Benefit:** the "oh no" git commands stop and ask before running, so a stray `reset --hard` can't silently vaporize uncommitted work. _Scoped for v1.2.0._
Sign in to join this conversation.
No description provided.