How I use Claude to write better commit messages (with a git hook)
Every developer knows the pain: you've just fixed a gnarly bug at 11pm, and git is waiting for a commit message. You type fix stuff and move on.
I fixed this with a git hook that calls the Claude API to generate a meaningful commit message from my diff — automatically.
The problem with manual commit messages
Bad commit messages are a tax you pay in the future:
-
fix bug— which bug? Fixed how? -
WIP— why is this in main? -
asdfasdf— we've all been there
Good commit messages are like documentation that writes itself — if you have the discipline to write them at 11pm. Most of us don't.
The solution: a prepare-commit-msg git hook
Git has a hook called prepare-commit-msg that runs before your editor opens. It can pre-populate the commit message. This is perfect for AI generation.
Here's the hook I use:
#!/bin/bash
# .git/hooks/prepare-commit-msg
COMMIT_MSG_FILE=$1
COMMIT_SOURCE=$2
# Only auto-generate for normal commits (not merges, amends, etc)
if [ -n "$COMMIT_SOURCE" ]; then
exit 0
fi
# Get the diff of staged changes
DIFF=$(git diff --cached --stat | head -20)
DIFF_CONTENT=$(git diff --cached | head -100)
if [ -z "$DIFF" ]; then
exit 0
fi
# Call the API
RESPONSE=$(curl -s -X POST https://simplylouie.com/api/chat \
-H "Content-Type: application/json" \
-H "X-API-Key: $LOUIE_API_KEY" \
-d "$(jq -n \
--arg diff "$DIFF" \
--arg content "$DIFF_CONTENT" \
'{message: ("Write a concise git commit message (under 72 chars) for these changes. Use conventional commits format (feat/fix/refactor/docs/chore). Just the message, no explanation.\n\nStat:\n" + $diff + "\n\nDiff (first 100 lines):\n" + $content)}')")
MESSAGE=$(echo $RESPONSE | jq -r '.response // empty')
if [ -n "$MESSAGE" ]; then
echo "$MESSAGE" > "$COMMIT_MSG_FILE"
echo "# AI-generated. Edit if needed." >> "$COMMIT_MSG_FILE"
fi
Make it executable:
chmod +x .git/hooks/prepare-commit-msg
Set your API key:
export LOUIE_API_KEY=your_key_here
# Add to ~/.bashrc or ~/.zshrc to make permanent
Real examples from my workflow
Before (what I'd have typed at 11pm):
fix auth thing
After (AI-generated from the same diff):
fix: resolve JWT expiry race condition in token refresh
Another one:
before: update stuff
after: refactor: extract UserRepository from UserService, add unit tests
The hook sees exactly what changed. It generates messages that are actually useful 6 months later.
Making it a global git hook
If you want this in every repo, not just one:
mkdir -p ~/.git-hooks
cp .git/hooks/prepare-commit-msg ~/.git-hooks/
git config --global core.hooksPath ~/.git-hooks
Now every repo on your machine gets AI commit messages automatically.
The cost
I use SimplyLouie's API — it's $2/month for unlimited access, which means this hook costs effectively $0 per commit. I run it probably 20-30 times a day.
If you're calling Anthropic directly, each commit message is maybe 500 input tokens + 50 output tokens. At $3/million input tokens, that's $0.0015 per commit. Still cheap, but it adds up if you're committing constantly.
Extending it
This same pattern works for:
PR descriptions — run the diff through the same API when you open a PR:
gh pr create --body "$(git diff main...HEAD | head -200 | curl -s -X POST https://simplylouie.com/api/chat -H 'Content-Type: application/json' -H "X-API-Key: $LOUIE_API_KEY" -d '{"message": "Write a PR description for this diff"}' | jq -r '.response')"
Changelog generation — at release time:
git log v1.0..HEAD --oneline | curl -s -X POST https://simplylouie.com/api/chat \
-H "Content-Type: application/json" \
-H "X-API-Key: $LOUIE_API_KEY" \
-d "{\"message\": \"Convert these commits to a user-friendly changelog:\\n$(git log v1.0..HEAD --oneline)\"}"
Get the API key
You need a SimplyLouie API key to run this. Sign up at simplylouie.com — it's $2/month, the API is included.
Or adapt the hook to use any OpenAI-compatible API endpoint — the JSON format is standard.
What's your current commit message workflow? Drop it in the comments — I'm curious how many people are still typing fix stuff at 11pm.
Top comments (0)