The most-installed git skill for Claude Code is git-guardrails-claude-code, Matt Pocock's git safety skill, with 523,036 all-time installs on the skills.sh registry as of November 7, 2026. It lives in mattpocock/skills on GitHub (317,373 stars the same day).
It does one job. In the words of its SKILL.md, it "Sets up a PreToolUse hook that intercepts and blocks dangerous git commands before Claude executes them."
Source: mattpocock/skills, skills/misc/git-guardrails-claude-code/SKILL.md
A hook is a better bet than a line in CLAUDE.md, because a hook is code that runs on every tool call and a prompt rule can fall out of a long context. But a hook is only as good as its patterns. So we read the bundled script and tested it the way Claude Code calls it. Short version: it catches chained and wrapped pushes like ls && git push, but git -C . push, a double space, git clean -xfd, any git alias, and every command on a machine without jq get through.
Disclosure: we run Skillselion. Install counts come from our listing pages (live catalog, refreshed daily from skills.sh, GitHub and MCP registries, ranked by real installs). This post is a technical cut of our git skills for Claude Code guide.
How does git-guardrails-claude-code work?
The skill copies block-dangerous-git.sh into .claude/hooks/ (one project) or ~/.claude/hooks/ (all projects), then registers it under hooks.PreToolUse with a Bash matcher. Every time Claude wants to run a shell command, Claude Code sends the hook a JSON payload on stdin. The command string sits at .tool_input.command.
Per the Claude Code hooks reference, exit code 2 from a PreToolUse hook blocks the tool call, and the hook's stderr is shown to Claude.
The current block-dangerous-git.sh is 25 lines. It reads the command with jq, then loops over this list and runs grep -qE against each entry:
DANGEROUS_PATTERNS=(
"git push"
"git reset --hard"
"git clean -fd"
"git clean -f"
"git branch -D"
"git checkout \."
"git restore \."
"push --force"
"reset --hard"
)
On a match it prints to stderr and exits 2:
BLOCKED: 'git push origin main' matches dangerous pattern 'git push'. The user has prevented you from doing this.
So this is substring matching on the raw command string. That design choice explains every row in the table below.
The test harness
We fed each command to the script exactly as a PreToolUse hook receives it. Copy this if you want to run your own list:
#!/bin/bash
# usage: ./test-hook.sh path/to/block-dangerous-git.sh < commands.txt
HOOK="$1"
while IFS= read -r cmd; do
[ -z "$cmd" ] && continue
jq -nc --arg c "$cmd" '{tool_input:{command:$c}}' | bash "$HOOK" >/dev/null 2>&1
code=$?
[ $code -eq 2 ] && v=BLOCKED || v=passes
printf '%s\t%s\t%s\n' "$code" "$v" "$cmd"
done
We ran it on macOS against the upstream script as of November 7, 2026 (last commit to that skill folder: August 19, 2026). The SKILL.md's own self-test, piping git push origin main and expecting exit 2, passes.
Which git commands does the hook block?
| Command | Exit | Result |
|---|---|---|
git push origin main |
2 | blocked |
git push --force-with-lease |
2 | blocked |
ls && git push |
2 | blocked |
command git push |
2 | blocked |
bash -c "git push" |
2 | blocked |
git -C . push |
0 | passes |
git push origin main (two spaces) |
0 | passes |
git reset --hard HEAD~1 |
2 | blocked |
git clean -fd / git clean -fdx
|
2 | blocked |
git clean -xfd |
0 | passes |
git branch -D x |
2 | blocked |
git branch --delete --force x |
0 | passes |
git checkout . / git restore .
|
2 | blocked |
git checkout -- . |
0 | passes |
git restore src/ |
0 | passes |
git checkout -f main |
0 | passes |
git stash drop / git stash clear
|
0 | passes |
git rebase -i HEAD~3 |
0 | passes |
git commit --amend --no-edit |
0 | passes |
git reflog expire --expire=now --all |
0 | passes |
git config alias.p push, then git p
|
0 / 0 | passes |
git log --grep="reset --hard" |
2 | blocked |
git commit -m "docs: never git push from CI" |
2 | blocked |
git status |
0 | passes |
What the numbers say:
-
Chaining does not help Claude. Because the match is a substring,
ls && git push,bash -c "git push"andcommand git pushare all caught. That is the strong side of the design. -
Anything that splits the literal string gets through, although the SKILL.md lists
git pushas blocked in "all variants including--force". A global option betweengitand the subcommand (-C,-c), a second space, a reordered flag cluster (-xfdinstead of-fd...), or the long form of a flag (--delete --forcefor-D). -
Some history-losing commands are not on the list.
git stash drop,git stash clear,git checkout -- .andgit reflog expireall exit 0. The SKILL.md never claims to cover them, so treat this as scope, not a bug. -
Aliases are invisible. A string matcher cannot know that
git pmeanspush. Any alias already in your~/.gitconfigpasses. -
It errs toward blocking. A commit message or a
--grepthat contains a pattern gets blocked. Annoying, but the safe direction. -
It fails open without jq. With
jqremoved fromPATH, the script printsjq: command not foundand exits 0, sogit push origin mainpasses. Our test Mac has/usr/bin/jqbuilt in; check that your containers and CI images do too.
Add these patterns if your workflow needs them
The skill's step 4 tells Claude to ask whether you want to add or remove patterns, so extending it is the intended path. This is the variant we tested. It closes every gap in the table except --amend, which we left open on purpose, and aliases that already exist:
#!/bin/bash
command -v jq >/dev/null || { echo "BLOCKED: jq not installed, git guard cannot read the command." >&2; exit 2; }
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command' | tr -s '[:space:]' ' ')
DANGEROUS_PATTERNS=(
# ...the nine upstream patterns, unchanged...
"git (-[cC] [^ ]+ )+push"
"git clean -[a-zA-Z]*f"
"git branch .*--delete --force"
"git checkout (-- )?\.( |$)"
"git checkout -f"
"git stash (drop|clear)"
"git rebase -i"
"git reflog expire"
"git config .*alias\."
)
# ...same loop as upstream...
With that version, 24 of our 28 commands exit 2. The four that pass are git restore src/, git commit --amend --no-edit, git status, and git p from an alias that already exists. Blocking amend is a judgment call. If Claude amends a commit you already pushed, the next push needs force, and the guard stops that push anyway.
For the alias gap, the real backstop sits on the server: a branch protection rule or ruleset on main that rejects force pushes. A client-side hook decides what Claude may try. The remote decides what can land.
The rest of a git stack for Claude Code
A few other skills shape how Claude commits, isolates work and opens PRs. We checked each current SKILL.md on GitHub before describing it.
Commits. caveman-commit, the terse Conventional Commits skill (422,617 installs; juliusbrussee/caveman on GitHub) aims for subjects of 50 characters or fewer with a hard cap of 72, and leaves out AI attribution lines unless your own rules require one. It never touches the repo: "Does not run git commit, does not stage files, does not amend." Our caveman skill guide covers the rest of that pack. If you want staging too, the git-commit skill from awesome-copilot (47,830 installs; github/awesome-copilot) does both.
Source: juliusbrussee/caveman, skills/caveman-commit/SKILL.md
Worktrees. using-git-worktrees, obra's workspace isolation skill (223,088 installs; obra/superpowers) first checks whether the session already runs in a linked worktree, prefers a native worktree tool, and only then falls back to git worktree add. Its core principle ends with "Never fight the harness." Two agents in one checkout share one index, so this is the skill that keeps their git add calls apart.
Source: obra/superpowers, skills/using-git-worktrees/SKILL.md
Pull requests. create-pull-request, Cline's gh PR skill (810 installs; cline/cline) checks gh --version, pushes with git push origin HEAD, and passes the body to gh pr create --body-file from a temp file. Note the interaction: with the guardrail installed, that push step exits 2, so you push and Claude opens the PR.
Stacked PRs. graphite, Graphite's stacked-PR skill (9,977 installs; withgraphite/agent-skills) is a quick reference for gt create, gt restack and gt submit. We ran gt submit --no-interactive through the stock hook: exit 0. It contains no git push string, so if your rule is "Claude never pushes", add gt submit to the list. gh pr create --fill and glab mr create --fill also exit 0. If a PR CLI in your setup can push a branch for you, the hook will not see that push, so read its flags and add it to the list if needed.
For habits rather than rules, git-workflow-and-versioning, Addy Osmani's git practice skill (63,600 installs; addyosmani/agent-skills) treats commits as save points.
The wider set is ranked on our best dev tools skills page and in the dev tools category. If Claude talks to GitHub through an API instead of gh, see the best GitHub MCP servers ranking; a Bash-matcher hook never sees those calls.
Install the guardrail, run the harness against the commands your team actually types, and add what is missing.
The full list with install counts is in our Claude Code git skills guide.
Top comments (0)