Skip to content

Instantly share code, notes, and snippets.

@JustSuperHuman
Created April 8, 2026 18:38
Show Gist options
  • Select an option

  • Save JustSuperHuman/ac71e551688655bfe8dd6f73c8d3ea30 to your computer and use it in GitHub Desktop.

Select an option

Save JustSuperHuman/ac71e551688655bfe8dd6f73c8d3ea30 to your computer and use it in GitHub Desktop.
# Auto-Generate Custom AI Git Commit Messages with Cursor
When you commit without a message, a git hook calls an AI CLI tool to read your changes and write the message for you.
## How It Works
1. You run `git commit` with no `-m` message
2. Git runs the `prepare-commit-msg` hook
3. The hook sees the message is empty, grabs your staged diff, and pipes it to an AI CLI
4. The AI reads your diff + your commit style rules and writes the message
5. Git uses that generated message for the commit
## Setup (3 files)
### 1. The Hook — `scripts/hooks/prepare-commit-msg`
This is a bash script that git runs before every commit. It checks if the message is empty, and if so, asks the AI to write one.
```bash
#!/usr/bin/env bash
COMMIT_MSG_FILE="$1"
COMMIT_SOURCE="$2"
# Skip merges, squashes, amends
if [ "$COMMIT_SOURCE" = "merge" ] || [ "$COMMIT_SOURCE" = "squash" ] || [ "$COMMIT_SOURCE" = "commit" ]; then
exit 0
fi
# If there's already a message, leave it alone
MSG=$(sed '/^#/d;/^$/d' "$COMMIT_MSG_FILE")
if [ -n "$MSG" ]; then
exit 0
fi
# Find your rules file
REPO_ROOT="$(git rev-parse --show-toplevel)"
RULES_FILE="$REPO_ROOT/path/to/your-commit-rules.md" # <-- change this
if [ ! -f "$RULES_FILE" ]; then
exit 0
fi
# Check the AI tool exists
#
# Swap "claude" for whatever CLI you use:
# - claude -p (Claude Code)
# - gh copilot (GitHub Copilot CLI)
# - aichat (aichat)
# - llm (simon willison's llm)
# - Any CLI that reads stdin and writes to stdout
#
AI_CMD="claude"
if ! command -v "$AI_CMD" >/dev/null 2>&1; then
echo "Warning: '$AI_CMD' not found, skipping." >&2
exit 0
fi
DIFF=$(git diff --cached --stat)
DIFF_DETAIL=$(git diff --cached)
# Truncate huge diffs so you don't blow up the prompt
DIFF_LEN=${#DIFF_DETAIL}
if [ "$DIFF_LEN" -gt 12000 ]; then
DIFF_DETAIL="$(printf '%s' "$DIFF_DETAIL" | head -c 12000)
... (truncated)"
fi
RULES=$(cat "$RULES_FILE")
PROMPT=$(cat <<ENDPROMPT
Generate a git commit message for these changes. Follow these rules:
$RULES
Diff summary:
$DIFF
Detailed diff:
$DIFF_DETAIL
Reply with ONLY the commit message. Nothing else.
ENDPROMPT
)
echo "Generating commit message..." >&2
# Swap this line for your AI tool:
GENERATED_MSG=$(printf '%s' "$PROMPT" | claude -p 2>/dev/null)
# Examples for other tools:
# GENERATED_MSG=$(printf '%s' "$PROMPT" | gh copilot suggest 2>/dev/null)
# GENERATED_MSG=$(printf '%s' "$PROMPT" | llm 2>/dev/null)
# GENERATED_MSG=$(printf '%s' "$PROMPT" | aichat 2>/dev/null)
if [ $? -ne 0 ] || [ -z "$GENERATED_MSG" ]; then
echo "Warning: AI failed, proceeding with empty message." >&2
exit 0
fi
TMPFILE="$COMMIT_MSG_FILE.tmp"
printf '%s\n' "$GENERATED_MSG" > "$TMPFILE"
grep '^#' "$COMMIT_MSG_FILE" >> "$TMPFILE" 2>/dev/null || true
mv "$TMPFILE" "$COMMIT_MSG_FILE"
echo "Commit message generated." >&2
```
### 2. The Setup Script — `scripts/git-config.js`
Tells git to use your tracked hooks folder instead of `.git/hooks/` (which isn't tracked).
```js
const { execSync } = require("child_process");
const { chmodSync, readdirSync } = require("fs");
const path = require("path");
const hooksDir = path.join(__dirname, "hooks");
// Make hooks executable (needed on macOS/Linux)
for (const file of readdirSync(hooksDir)) {
try { chmodSync(path.join(hooksDir, file), 0o755); } catch {}
}
// Point git at our hooks folder
execSync("git config core.hooksPath scripts/hooks", {
cwd: path.resolve(__dirname, ".."),
stdio: "inherit",
});
console.log("Git hooks configured.");
```
### 3. Wire It Up — `package.json`
```json
{
"scripts": {
"git-config": "node scripts/git-config.js",
"postinstall": "node scripts/git-config.js"
}
}
```
`postinstall` means anyone who runs `npm install` / `bun install` / `yarn` gets the hooks set up automatically.
## That's It
- `git commit` with no message → AI writes it
- `git commit -m "my message"` → your message is used as-is
- No AI tool installed? → hook silently skips, normal git behavior
- Works on Windows (Git Bash), macOS, and Linux
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment