@@ -4,7 +4,7 @@ COMMIT_MSG_FILE="$1"
44
55# If the commit message file already contains non-comment lines, do nothing.
66if grep -qE ' ^[^[:space:]#]' " $COMMIT_MSG_FILE " ; then
7- exit 0
7+ exit 0
88fi
99
1010# Gather a list of staged (changed) files.
@@ -34,6 +34,119 @@ INLINE_MSG=$(cat <<'EOF'
3434EOF
3535)
3636
37+ # AICommit uses an LLM (via ollama) to generate commit messages that match git
38+ # commit style by learning from previous commits.
39+ # Inspired by https://github.com/acrosa/aicommits.
40+ MODEL=" qwen2.5-coder"
41+ SUGGESTED_COMMITMSG=
42+ AICOMMIT=$( git config --get core.aicommit || echo ' auto' )
43+ if [[ " $AICOMMIT " == " always" ]] || [[ " $AICOMMIT " == " auto" && -t 1 ]] && \
44+ git diff --cached --name-only | grep -qiE " \.(c|h|cpp|hpp)$" ; then
45+ # Build commit history list from the last non-merge commit messages.
46+ commit_history=$( git log -n 70 --no-merges --pretty=format:' "%s",' | \
47+ sed -E ' s/ \(\#[0-9]+\)//; $ s/,$//' )
48+ commit_history=" [$commit_history ]"
49+
50+ # Capture the staged diff.
51+ staged_diff=$( git diff --cached)
52+
53+ # Create a style prompt from commit history.
54+ style_prompt="
55+ You are a specialized system for generating high-quality Git commit messages based on 'git diff --cached' output and optional developer descriptions.
56+ # Task:
57+ Analyze the following commit messages and produce **accurate, concise, and meaningful commit messages** that clearly describe the changes:
58+ - $commit_history
59+
60+ # Output:
61+ Provide a concise description of the style without quoting commit content.
62+ "
63+ echo " Running ollama... "
64+ style_description=$( echo " $style_prompt " | ollama run " $MODEL " )
65+
66+ # Build the commit message prompt.
67+ prompt="
68+ # Context:
69+ Style: $style_description
70+
71+ # Instructions:
72+ - Analyze the diff below and generate a commit message based solely on its content.
73+ - Mimic the style described above (tone, length, structure) without copying previous messages.
74+ - Use clear action verbs and be concise.
75+ - Output ONLY the commit message (subject, a blank line, then body).
76+ - Separate the subject from the body with a blank line.
77+ - Remove triple backticks; replace backticks with single quotes.
78+ - Keep the first line (subject) under 50 characters
79+ - Ensure no line exceeds 72 characters.
80+ - Avoid vague messages like 'Updates' or 'Fixed bug'
81+ - Always write in **plain text** without markdown or HTML.
82+ - No concluding remarks.
83+ - Do NOT use conventional commit prefixes (like 'feat:', 'fix:', 'docs:')
84+ - Avoid the redundant message like 'Updated commit messages'
85+
86+ # Diff:
87+ <diff>$staged_diff </diff>
88+
89+ Commit message:"
90+ if [ " $2 " = " --show-prompt" ]; then
91+ echo " Full style prompt:"
92+ echo " $style_prompt "
93+ echo " Extracted style:"
94+ echo " $style_description "
95+ echo " Full commit prompt:"
96+ echo " $prompt "
97+ fi
98+
99+ # Generate commit message using ollama.
100+ SUGGESTED_COMMITMSG=$( echo " $prompt " | ollama run " $MODEL " )
101+
102+ # Post-process the commit message.
103+ # - Trim whitespace.
104+ # - Remove triple backticks.
105+ # - Replace backticks with single quotes.
106+ # - Wrap lines at 72 characters.
107+ SUGGESTED_COMMITMSG=$( echo " $SUGGESTED_COMMITMSG " | sed ' s/^[[:space:]]*//; s/[[:space:]]*$//' )
108+ SUGGESTED_COMMITMSG=$( echo " $SUGGESTED_COMMITMSG " | sed -E ' /^(Author:|Date:|Commit message:)/d' )
109+ SUGGESTED_COMMITMSG=" $(
110+ echo " $SUGGESTED_COMMITMSG " \
111+ | sed -E ' /^```(markdown|diff|text|plaintext)?$/d; s/\*\*([^*]+)\*\*/\1/g; s/`([^`]+)`/' \' ' \1' \' ' /g' \
112+ | awk -v w=72 '
113+ function sp(n){ return sprintf("%" n "s", "") }
114+ function wrap(bp, txt){
115+ gsub(/^ +| +$/,"",txt)
116+ if(!length(txt)){ print bp; return }
117+ n = split(txt, a, /[ \t]+/)
118+ l = bp; len = length(bp)
119+ for(i = 1; i <= n; i++){
120+ wl = length(a[i])
121+ if((len > length(bp) ? len + 1 : len) + wl > w){
122+ print l; l = sp(length(bp)) a[i]; len = length(bp) + wl
123+ } else if(len == length(bp)){
124+ l = bp a[i]; len = length(bp) + wl
125+ } else {
126+ l = l " " a[i]; len++; len += wl
127+ }
128+ }
129+ if(len > length(bp)) print l
130+ }
131+ BEGIN { paragraph = ""; bullet = "" }
132+ {
133+ line = $0; gsub(/^ +| +$/, "", line)
134+ if(!length(line)){
135+ if(length(paragraph)){ wrap(bullet, paragraph); paragraph = ""; bullet = "" }
136+ print ""; next
137+ }
138+ if(match(line, /^( *[0-9]+\.[ \t]+| *-[ \t]+| *\*[ \t]+)/)){
139+ if(length(paragraph)){ wrap(bullet, paragraph); paragraph = ""; bullet = "" }
140+ bp = substr(line, RSTART, RLENGTH); rest = substr(line, RSTART + RLENGTH)
141+ gsub(/^[ \t]+/, "", rest); wrap(bp, rest)
142+ } else {
143+ if(!length(paragraph)) paragraph = line; else paragraph = paragraph " " line
144+ }
145+ }
146+ END { if(length(paragraph)) wrap(bullet, paragraph) }
147+ ' ) "
148+ fi
149+
37150# Write an empty line, the guidelines, and the changed files into the commit message.
38151{
39152 echo
44157 else
45158 echo " # (No staged files detected.)"
46159 fi
160+ if [ -n " $SUGGESTED_COMMITMSG " ]; then
161+ echo " #"
162+ echo " # ✅Suggested commit messages:"
163+ echo " $SUGGESTED_COMMITMSG " | sed ' s/^/# /'
164+ fi
47165} > " $COMMIT_MSG_FILE "
48166
49167# Prompt the user about aborting the commit.
0 commit comments