Git hooks
Block bad commits at pre-commit, commit-msg, or pre-push with a one-command CommitBrief hook scaffolder.
commitbrief install-hook drops a small shell script at
.git/hooks/<name> that runs CommitBrief against the relevant
change set, blocking the git operation on a critical-severity
finding.
Quick install
commitbrief install-hook # default: pre-commit
commitbrief install-hook --hook=pre-push
commitbrief install-hook --uninstall # remove (only if we wrote it)
Supported hooks
| Hook | Default? | What the body does |
|---|---|---|
pre-commit | ✓ | Runs commitbrief --staged --fail-on=critical --quiet --no-cost-check. Blocks the commit on any critical-severity finding. |
commit-msg | — | Same body as pre-commit. Useful when you want the review to happen after the commit message is composed. |
pre-push | — | Reads git’s per-ref stdin protocol and runs commitbrief diff <remote>..<local> --fail-on=critical --quiet --no-cost-check for each ref being pushed. Skips branch deletions; for new branches reviews the tip commit. The push is blocked on the first critical finding. |
post-commit, post-receive, and other hooks are intentionally
not supported.
Flags
| Flag | Notes |
|---|---|
--hook=<name> | Which hook to install. One of pre-commit, commit-msg, pre-push. Default pre-commit. |
--uninstall | Remove a hook previously written by install-hook. Refuses to touch a hook that does not carry our generated-marker comment. |
--yes (global) | Overwrite an existing hook file. The previous content is backed up to <name>.bak.<timestamp>. |
Conflict handling
| Situation | Behavior |
|---|---|
| Target hook does not exist | Write it. Print Installed <path>. |
Hook exists, our marker, no --yes | Refuse with install-hook: <path> already exists; re-run with --yes to back it up and overwrite. |
Hook exists, our marker, with --yes | Rename existing to <path>.bak.<UTC-ISO-timestamp>. Write fresh. |
Hook exists, NO marker, with --yes | Same backup + overwrite — explicit opt-in. |
--uninstall, file missing | No-op success. |
--uninstall, marker present | Remove. Print Removed <path>. |
--uninstall, marker missing | Refuse — was not written by commitbrief; refusing to remove. |
The generated marker
Every hook this command writes contains the verbatim comment:
Generated by `commitbrief install-hook`
--uninstall greps for it before removing. A hand-written hook
of the same name is never silently clobbered.
Embedded absolute path
The generated hook embeds the absolute path of the running
commitbrief binary as a single-quoted shell token instead of
relying on $PATH lookup. Resolved via os.Executable() plus
filepath.EvalSymlinks so the path survives brew upgrade (which
swaps the keg symlink target).
This makes the hook work under GUI git clients (Tower, GitHub
Desktop, Fork, JetBrains IDEs) that strip the user’s shell
$PATH and would otherwise fail to find commitbrief if it sits
under /opt/homebrew/bin/.
Pre-push specifics
The pre-push body parses git’s per-ref stdin protocol:
<local-ref> <local-sha> <remote-ref> <remote-sha>
per line. For each ref:
- Branch deletion (
<local-sha>is0000…) → skip. - New branch (
<remote-sha>is0000…) → review the tip commit. - Normal push → review
<remote-sha>..<local-sha>.
--fail-on=critical exits 1 on the first critical finding,
which blocks the push.
Examples
# Default: install pre-commit hook.
commitbrief install-hook
# Pre-push hook for catch-on-push semantics.
commitbrief install-hook --hook=pre-push
# Overwrite an existing hook (backup auto-created).
commitbrief install-hook --yes
# Remove the hook we installed earlier.
commitbrief install-hook --uninstall
# Pre-push variant.
commitbrief install-hook --hook=pre-push --uninstall
See also
- Severity and CI gating — what
--fail-on=criticalactually means. - Review scopes —
the
diffsubcommand used by the pre-push body. - Safety and cost — why the hook
body uses
--no-cost-checkand--quiet.