Skip to content

Commit 88417b5

Browse files
committed
chore: update version to 0.1.7 in Cargo files
- use format string syntax for error messages - introduce prompt_chunked.txt for chunk summarization - implement diff summarization for large contexts
1 parent 5d95fae commit 88417b5

5 files changed

Lines changed: 96 additions & 13 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "git-commit-helper"
3-
version = "0.1.6"
3+
version = "0.1.7"
44
authors = ["coding@dfine.tech"]
55
edition = "2024"
66
repository = "https://github.com/newdee/git-commit-helper.git"

src/git.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ pub fn get_staged_diff(repo: &Repository) -> Option<String> {
5151
buf.extend_from_slice(_l.content());
5252
true
5353
}) {
54-
eprintln!("failed to print diff: {}", e);
54+
eprintln!("failed to print diff: {e}");
5555
return None;
5656
}
5757
let result = String::from_utf8_lossy(&buf).to_string();
@@ -144,7 +144,7 @@ pub fn gpg_sign(data: &[u8], key: Option<&str>) -> Result<String, Box<dyn std::e
144144
/// let repo = Repository::discover(".").expect("Not a git repository");
145145
/// let message = "Add README and initial setup";
146146
/// if let Err(err) = commit_with_git(&repo, message) {
147-
/// eprintln!("Commit failed: {}", err);
147+
/// eprintln!("Commit failed: {err}");
148148
/// }
149149
/// ```
150150
pub fn commit_with_git(
@@ -173,7 +173,7 @@ pub fn commit_with_git(
173173

174174
if !gpgsign {
175175
let commit_oid = repo.commit(Some("HEAD"), &sig, &sig, message, &tree, &parents)?;
176-
println!("✅ Commit created: {}", commit_oid);
176+
println!("✅ Commit created: {commit_oid}");
177177
return Ok(());
178178
}
179179
let signature = gpg_sign(&buf, signkey);
@@ -192,6 +192,6 @@ pub fn commit_with_git(
192192
"update ref",
193193
)?;
194194

195-
println!("✅ Commit created: {}", commit_oid);
195+
println!("✅ Commit created: {commit_oid}");
196196
Ok(())
197197
}

src/main.rs

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use std::error::Error;
1919
use clap::{Parser, arg};
2020

2121
static PROMPT_TEMPLATE: &str = include_str!("prompt.txt");
22+
static CHUNK_PROMPT_TEMPLATE: &str = include_str!("prompt_chunked.txt");
2223

2324
enum UserChoice {
2425
Commit,
@@ -66,17 +67,50 @@ struct Args {
6667
//count: u8,
6768
#[arg(long, default_value_t = 2048_u32)]
6869
max_token: u32,
70+
71+
#[arg(long, default_value_t = 200000_usize)]
72+
chunk_size: usize,
6973
}
7074

7175
fn print_commit_msg(commit_msg: &str) {
7276
// blue
7377
println!("\x1b[34m================ COMMIT MESSAGE ================\x1b[0m");
7478
// green
75-
println!("\x1b[32m{}\x1b[0m", commit_msg);
79+
println!("\x1b[32m{commit_msg}\x1b[0m");
7680
// blue
7781
println!("\x1b[34m================================================\x1b[0m");
7882
}
7983

84+
async fn summarize_diff_in_chunks(diff: &str, args: &Args) -> Result<String, Box<dyn Error>> {
85+
let mut chunks = Vec::new();
86+
let mut start = 0;
87+
while start < diff.len() {
88+
let end = (start + args.chunk_size).min(diff.len());
89+
chunks.push(&diff[start..end]);
90+
start = end;
91+
}
92+
93+
let mut part_summaries = Vec::new();
94+
for (i, chunk) in chunks.iter().enumerate() {
95+
let prompt = format!(
96+
"You are a code change summarization assistant. Summarize the main goal and impact of the following code changes in a concise sentence:\n\nPart {} of the diff:\n{}\n\nSummary:",
97+
i + 1,
98+
chunk
99+
);
100+
101+
match call_llm(&args.provider, &prompt, &args.model, args.max_token).await {
102+
Ok(summary) => {
103+
// println!("summary {i}: {summary}");
104+
part_summaries.push(summary.trim().to_string())
105+
}
106+
Err(e) => eprintln!("⚠️ summarizing chunk {} failed: {}", i + 1, e),
107+
}
108+
}
109+
let combined_summary = part_summaries.join("\n");
110+
// println!("{combined_summary}");
111+
Ok(combined_summary)
112+
}
113+
80114
#[tokio::main]
81115
async fn main() {
82116
let args = Args::parse();
@@ -87,9 +121,26 @@ async fn main() {
87121
});
88122
let signkey = (!args.gpgsignkey.is_empty()).then_some(args.gpgsignkey.as_str());
89123
let commits = get_recent_commit_message(&repo).unwrap_or("None".to_string());
90-
let prompt = PROMPT_TEMPLATE
91-
.replace("{recent_commits}", &commits)
92-
.replace("{diff_context}", &diff);
124+
let prompt = if diff.len() > args.chunk_size {
125+
println!(
126+
"Diff context is too large: {}, need to summarize",
127+
diff.len()
128+
);
129+
let summary = match summarize_diff_in_chunks(&diff, &args).await {
130+
Ok(s) => s,
131+
Err(e) => {
132+
eprintln!("Error summarizing diff: {e}");
133+
std::process::exit(0);
134+
}
135+
};
136+
CHUNK_PROMPT_TEMPLATE
137+
.replace("{recent_commits}", &commits)
138+
.replace("{diff_context}", &summary)
139+
} else {
140+
PROMPT_TEMPLATE
141+
.replace("{recent_commits}", &commits)
142+
.replace("{diff_context}", &diff)
143+
};
93144
loop {
94145
match call_llm(&args.provider, &prompt, &args.model, args.max_token).await {
95146
Ok(commit_msg) => {
@@ -101,7 +152,7 @@ async fn main() {
101152
}
102153
Ok(UserChoice::Commit) => {
103154
if let Err(e) = commit_with_git(&repo, &commit_msg, args.gpgsign, signkey) {
104-
eprintln!("❌ Commit failed: {}", e);
155+
eprintln!("❌ Commit failed: {e}");
105156
}
106157
break;
107158
}
@@ -110,12 +161,12 @@ async fn main() {
110161
continue;
111162
}
112163
Err(e) => {
113-
eprintln!("❌ Input error: {}", e);
164+
eprintln!("❌ Input error: {e}");
114165
break;
115166
}
116167
}
117168
}
118-
Err(e) => eprintln!("generate failed: {}", e),
169+
Err(e) => eprintln!("generate failed: {e}"),
119170
}
120171
}
121172
}

src/prompt_chunked.txt

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
You are a Git commit assistant. Based on the provided `diff_context` (summary of diff context) and style reference `recent_commits`, generate a commit message with the following rules:
2+
3+
1. First line: Conventional Commit format — `type: concise description`
4+
- Valid types: feat, fix, docs, style, refactor, perf, test, chore, etc.
5+
- Description should be short, specific, and lowercase (except proper nouns).
6+
7+
2. Optional bullet points (only if they add useful context):
8+
- Second line must be blank if bullet points are used
9+
- Bullet points should start with a dash (`-`)
10+
- Be short and focused — what changed, not why
11+
- No fluff, no unnecessary explanation
12+
13+
**Strict Output Rules:**
14+
- DO NOT include any explanation, commentary, or reasoning
15+
- DO NOT output anything like `<think>`, `<plan>`, or markdown formatting
16+
- DO NOT wrap the result in quotes or code blocks
17+
- Output ONLY the commit message
18+
19+
**Examples (do NOT reuse or repeat):**
20+
feat: add user auth system
21+
fix: resolve memory leak in worker pool
22+
fix: typo in README.md
23+
24+
---
25+
26+
Recent commits for style guidance:
27+
{recent_commits}
28+
29+
---
30+
31+
Diff context to base your message on (summary of diff context):
32+
{diff_context}

0 commit comments

Comments
 (0)