-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathprepare-commit-msg
More file actions
executable file
·110 lines (87 loc) · 3.04 KB
/
Copy pathprepare-commit-msg
File metadata and controls
executable file
·110 lines (87 loc) · 3.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#!/usr/bin/env bash
# .git/hooks/prepare-commit-msg
# Pre-fills the commit message with a Claude-generated conventional commit.
set -euo pipefail
COMMIT_MSG_FILE="$1"
COMMIT_SOURCE="${2:-}"
case "$COMMIT_SOURCE" in
message|template|merge|squash|commit)
exit 0
;;
esac
if [[ "${SKIP_CLAUDE:-0}" == "1" ]]; then
exit 0
fi
# Skip silently if claude isn't installed on this machine.
if ! command -v claude >/dev/null 2>&1; then
exit 0
fi
if git diff --cached --quiet; then
exit 0
fi
LINES=$(git diff --cached --numstat | awk '{s+=$1+$2} END {print s+0}')
MAX_LINES=${CLAUDE_MSG_MAX_LINES:-2000}
if (( LINES > MAX_LINES )); then
exit 0
fi
DIFF=$(git diff --cached)
FILES=$(git diff --cached --name-only)
RECENT=$(git log -n 10 --pretty=format:'%s' 2>/dev/null || true)
# Same reproducibility flags as the pre-commit hook.
SETTINGS_JSON='{"disableAllHooks": true}'
read -r -d '' PROMPT <<'EOF' || true
Write a Conventional Commits message for the staged diff below.
Format:
<type>(<optional scope>)<!>: <subject>
<optional body explaining WHY, wrapped at 72 chars>
<optional "BREAKING CHANGE: <description>" footer>
Rules:
- type is one of: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert, clean
- subject is imperative mood, lowercase, no trailing period, <= 72 chars
- Use a scope only if there's an obvious one from the changed paths
- Add a body ONLY if the "why" isn't obvious from the subject; otherwise omit
- If the diff is purely mechanical (formatting, renames, version bumps), keep it to one line
- Match the style of the recent commits shown below where reasonable
- Mark a breaking change by appending `!` after the type/scope AND adding
a `BREAKING CHANGE: <description>` footer (both are required together).
Flag a breaking change when the diff:
* alters or removes inputs accepted from parameter files (e.g. renames,
removes, or changes the type/meaning of a parameter; changes default
values in a non-backward-compatible way)
* alters or removes command-line options/arguments
* changes the structure, schema, or format of output files in a way
that existing consumers would need to be updated for
Additive, backward-compatible changes (new optional parameters, new
optional output fields) are NOT breaking.
Output ONLY the commit message. No code fences, no preamble, no explanation.
EOF
INPUT=$(cat <<EOF
$PROMPT
---RECENT COMMITS---
$RECENT
---FILES CHANGED---
$FILES
---DIFF---
$DIFF
EOF
)
MSG=$(printf '%s' "$INPUT" \
| claude -p \
--settings "$SETTINGS_JSON" \
--strict-mcp-config \
--mcp-config '{"mcpServers": {}}' \
--allowedTools "" \
--max-turns 2 \
--output-format json 2>/tmp/claude-msg.err) || {
exit 0
}
GENERATED=$(echo "$MSG" | jq -r '.result // empty')
if [[ -z "$GENERATED" ]]; then
exit 0
fi
EXISTING=$(cat "$COMMIT_MSG_FILE")
{
printf '%s\n\n' "$GENERATED"
printf '# --- claude suggested above; edit freely or delete to write your own ---\n'
printf '%s' "$EXISTING"
} > "$COMMIT_MSG_FILE"