guard-primary-checkout¶
Block commits made directly in the primary checkout while it sits on a feature branch. Feature work belongs in a dedicated git worktree that branches off the integration branch.
See References → Common contract for the pinning, fail-open, and primary-checkout-versus-worktree conventions that apply across every hook.
Prerequisites¶
- pre-commit on the
PATH. - A
gitrepository. The hook shells out togitonly; it has no other runtime dependency.
Arguments¶
| Argument | Default | Purpose |
|---|---|---|
--branch <name> |
develop |
The integration branch the primary checkout must stay on. Pass --branch=main for repositories that integrate on main. |
Arguments are supplied through pre-commit's args: list:
hooks:
- id: guard-primary-checkout
args: [--branch=main]
Behaviour¶
- Enforces only in the primary checkout. The hook compares the per-worktree git-dir with the shared git-common-dir; they're equal only in the primary checkout. In a linked worktree they differ, so the hook exits 0 — feature-branch commits belong there.
- Allows the integration branch. When the primary checkout is on the
configured branch (default
develop), the commit proceeds. - Blocks anything else. On any other branch — or a detached HEAD — in the primary checkout, the commit is refused with exit 1 and a message that shows how to move the work into a worktree.
- Fails open in CI. When
CIis set, the hook exits 0 immediately. - Never mutates state. It only refuses the commit; the branch, index, and working tree are left untouched.
It's registered with always_run: true and pass_filenames: false, so it
fires on every commit regardless of which files are staged.
Example¶
# .pre-commit-config.yaml in the consumer repository
repos:
- repo: https://github.com/nolte/pre-commit-hooks
rev: v1.0.0
hooks:
- id: guard-primary-checkout
A commit attempted on a feature branch in the primary checkout:
✖ Primary checkout is on branch 'feat/x', not 'develop' — commit blocked.
The primary checkout (…) is for integration only and MUST stay
on 'develop' at all times. Feature work happens on a feature
branch in a dedicated worktree that branches off 'develop'.
Troubleshooting¶
- The hook blocks a legitimate commit on
main. The repository integrates onmain, notdevelop. Configure it withargs: [--branch=main]. - The hook doesn't fire at all. Confirm
pre-commit installran in the clone and that the commit happens in the primary checkout. In a linked worktree the hook is silent by design. - CI commits are unexpectedly blocked. They aren't: the hook exits 0
whenever
CIis set. If a local automation context needs the same bypass, setCI=1for that invocation. - A commit must land in the primary checkout to repair drift. Run the git command from a worktree, or temporarily move the hook aside; the hook prints the worktree-based repair steps when it blocks.
Related¶
nolte/taskfilesworktreemodule (task worktree:add) creates the dedicated worktrees this hook steers you toward.