Git Commit Hygiene
Install a commit-msg hook that auto-strips AI tool attribution from git commits.
$skillfish add ~skills/git-commit-hygiene Real Conversations
See how the Git Commit Hygiene skill responds to actual requests. These are representative examples of what your AI agent will produce.
Claude Code keeps adding "Co-Authored-By: Claude Sonnet" to my commits. I've told it not to but it still happens sometimes. How do I enforce this at the git level so it can never slip through?
Install a commit-msg hook — it runs before every commit is recorded and strips attribution lines automatically, regardless of what the agent wrote.
Create the hook:
cat > .git/hooks/commit-msg << 'EOF'
#!/bin/sh
sed -i '' '/^[[:space:]]*[Cc]o-[Aa]uthored-[Bb]y:/d' "$1"
sed -i '' '/^[[:space:]]*[Gg]enerated by.*AI/d' "$1"
sed -i '' '/^[[:space:]]*[Cc]reated with.*AI/d' "$1"
sed -i '' -e :a -e '/^\n*$/{$d;N;ba' -e '}' "$1"
EOF
chmod +x .git/hooks/commit-msg
On Linux replace
sed -i ''withsed -i(no empty string arg).
Verify it works:
git commit --allow-empty -m "test
Co-Authored-By: Claude Sonnet <noreply@anthropic.com>"
git log -1 --format="%B"
# → only "test" — attribution gone
Also add to CLAUDE.md so the agent knows the rule at the prompt level too:
## Git Commit Rules
- NEVER add `Co-Authored-By` lines to git commits
- Commit messages should be concise and human-style
The hook is the backstop. CLAUDE.md is the first line of defence. Both together means attribution never reaches your git history.
Get Started
How to install and use this skill in your preferred environment.
Skills are designed for AI coding agents (Claude Code, Cursor, Windsurf) and IDE-based workflows where the agent can read files, run scripts, and act on your codebase. Web-based AI can use the knowledge and frameworks, but won't have tool access.
Models & Context
Which AI models and context windows work best with this skill.
Recommended Models
Larger models produce more detailed, production-ready outputs.
Context Window
This skill's SKILL.md is typically 3–10 KB — fits in any modern context window.
All current frontier models (Claude, GPT, Gemini) support 100K+ context. Use the full window for complex multi-service work.
Pro tips for best results
Be specific
Include numbers — users, budget, RPS — so the skill can size the architecture.
Share constraints
Compliance needs, team size, and existing stack all improve the output.
Iterate
Start with a high-level design, then ask follow-ups for IaC, cost analysis, or security review.
Combine skills
Pair with companion skills below for end-to-end coverage.
Good to Know
Advanced guide and reference material for Git Commit Hygiene. Background, edge cases, and patterns worth understanding.
Contents
Two-Layer Defence
The hook is a backstop, not the only control. Both layers together are more robust:
Layer 1 — CLAUDE.md instructs the agent at the prompt level. Claude Code reads CLAUDE.md at startup and follows its rules. With the rule present, the agent will usually not add attribution lines in the first place.
Layer 2 — commit-msg hook enforces at the git level regardless of what the agent wrote. Even if the agent ignores CLAUDE.md or is replaced by a different tool, the hook silently strips attribution before the commit is recorded.
The combination: the agent tries not to add attribution (Layer 1), and even if it does, the hook removes it before it reaches history (Layer 2).
Disabling Attribution in Your Editor
Editor settings let you turn off attribution at the source — before it ever reaches the commit message. They don't replace the hook; they reduce the noise so the hook rarely needs to fire.
Claude Code
Claude Code writes attribution to commits via the attribution.commit setting in .claude/settings.json. Set it to an empty string to suppress the Co-Authored-By: Claude Sonnet… line.
Commit-only disable (most common):
{
"attribution": {
"commit": ""
}
}
Full disable (commits and pull requests):
{
"attribution": {
"commit": "",
"pr": ""
}
}
Scope options:
- User-level:
~/.claude/settings.json— applies to all projects - Project-level:
.claude/settings.json— applies to one repo only (check this in if your team wants a shared default)
Caveat: This is a soft control. When Claude Code uses the Bash tool to run git commit directly, it may inject attribution via the shell environment rather than through the settings file. The commit-msg hook catches those cases.
Cursor
Cursor adds attribution as a Made with Cursor commit trailer (and in older versions, a Co-Authored-By: Cursor line).
To disable: open Settings (Cmd+, / Ctrl+,) → Agent → Attribution → toggle off "Add Cursor as co-author in Git commits".
Critical caveat: Cursor silently re-enables this toggle after IDE updates. Check the setting after every Cursor update — it is the most common reason attribution reappears in teams that thought they had it disabled.
Enterprise teams: Administrators can disable the setting globally from the Cursor Admin Dashboard, which prevents individual users from re-enabling it.
Why the hook still matters
Editor settings are soft controls: opt-in, easy to forget, and reset by updates. A new team member, a Cursor update, or a different AI tool entirely can reintroduce attribution without anyone noticing.
The commit-msg hook enforces the rule at the git level — it runs regardless of which editor or agent is in use, regardless of whether a setting got reset, and regardless of whether the developer knows attribution is being added. The hook is the guarantee; the editor settings reduce the day-to-day noise.
Team Distribution Options
.git/hooks/ is not tracked by git — each developer must install the hook themselves. Three practical approaches:
Option A — core.hooksPath (recommended)
Commit the hook to .githooks/ and point git at it:
mkdir -p .githooks
cp .git/hooks/commit-msg .githooks/commit-msg
git config core.hooksPath .githooks
All developers who run this command (or have it in a setup script or onboarding docs) get the hook automatically.
Option B — package.json postinstall
Runs automatically on npm install:
{
"scripts": {
"postinstall": "git config core.hooksPath .githooks"
}
}
Option C — Husky
For teams already using Husky for other hooks:
npx husky add .husky/commit-msg 'sh .githooks/commit-msg $1'
Auditing Existing History
The hook prevents future attribution but does not rewrite past commits. To check whether attribution already exists in your history:
git log --all --grep="Co-Authored-By" --oneline
git log --all --grep="Co-Authored-By" --oneline | wc -l
Removing attribution from existing history requires rewriting with git filter-repo — a significant operation only appropriate when all collaborators are informed.
How the commit-msg Hook Works
Git runs hooks at specific points in the commit lifecycle. The commit-msg hook fires after you run git commit and write the message, but before git finalises the commit object. It receives one argument: the path to a temporary file containing the raw commit message.
The hook can read and modify that file, exit non-zero to abort the commit entirely, or run any shell command.
Hook execution order:
pre-commit— runs first; can abort if lint/tests failprepare-commit-msg— can pre-populate the messagecommit-msg— this hook fires here — validate or rewrite the message filepost-commit— runs after; cannot abort; used for notifications
Pattern Reference
Every sed line in the hook targets a distinct attribution pattern:
| Pattern | Purpose |
|---|---|
/[Cc]o-[Aa]uthored-[Bb]y:/ |
Claude Code, GitHub Copilot, Codex — case-insensitive |
/[Mm]ade-with:.*[Cc]ursor/ |
Cursor-specific Made-with: Cursor line |
/[Gg]enerated by [Cc]ursor/ |
Cursor alternate phrasing |
/[Cc]reated with [Cc]ursor/ |
Cursor alternate phrasing |
/[Cc]ursor AI/ |
Generic Cursor AI mention anywhere in line |
/[Gg]enerated by.*AI/ |
Generic catch-all for any AI tool |
/[Cc]reated with.*AI/ |
Generic catch-all for any AI tool |
| Trailing blank line loop | Removes blank lines left behind after stripping |
macOS vs Linux sed
The hook uses sed -i to edit the commit message file in place. The syntax differs between BSD sed (macOS) and GNU sed (Linux):
| Platform | Correct syntax | Notes |
|---|---|---|
| macOS / BSD | sed -i '' |
Empty string = no backup file created |
| Linux / GNU | sed -i |
No argument after -i |
The hook ships with sed -i '' for macOS. For cross-platform repos, use the OS-detection variant in the SKILL.md or switch to perl -i -pe which works identically on both.
Ready to try Git Commit Hygiene?
Install the skill and start getting expert-level guidance in your workflow — any agent, any IDE.
$skillfish add ~skills/git-commit-hygiene