You just finished a feature branch with 47 changed files. Your team lead asks for a summary of what changed. You could spend 20 minutes writing it up β or you could run one command and let AI do it.
In this tutorial, weβll build git-summary, a CLI tool that reads your git diff and generates a clean, human-readable changelog. It takes about 15 minutes to build and youβll actually use it daily.
What weβre building
$ git-summary
## Changes Summary
### New Features
- Added user authentication with JWT tokens
- Created /api/users endpoint with CRUD operations
### Bug Fixes
- Fixed race condition in WebSocket connection handler
- Resolved null pointer when user profile is incomplete
### Refactoring
- Extracted database queries into repository pattern
- Moved validation logic to middleware
**Files changed:** 12 | **Insertions:** 847 | **Deletions:** 234
Prerequisites
- Node.js 20+
- An Anthropic API key (get one at console.anthropic.com)
- A git repository to test with
Step 1: Set up the project
mkdir git-summary && cd git-summary
npm init -y
npm install @anthropic-ai/sdk
Add to package.json:
{
"type": "module",
"bin": { "git-summary": "./index.js" }
}
Step 2: Build the CLI
Create index.js:
#!/usr/bin/env node
import Anthropic from '@anthropic-ai/sdk';
import { execSync } from 'child_process';
// Get the git diff
function getGitDiff() {
try {
// Try staged changes first, then unstaged, then last commit
let diff = execSync('git diff --cached --stat -p', { encoding: 'utf-8' });
if (!diff.trim()) {
diff = execSync('git diff --stat -p', { encoding: 'utf-8' });
}
if (!diff.trim()) {
diff = execSync('git diff HEAD~1 --stat -p', { encoding: 'utf-8' });
}
return diff;
} catch {
console.error('Not a git repository or no changes found.');
process.exit(1);
}
}
// Truncate diff if too long (API has token limits)
function truncateDiff(diff, maxChars = 80000) {
if (diff.length <= maxChars) return diff;
return diff.slice(0, maxChars) + '\n\n... (diff truncated for length)';
}
async function summarize() {
const diff = getGitDiff();
if (!diff.trim()) {
console.log('No changes to summarize.');
return;
}
const client = new Anthropic();
const message = await client.messages.create({
model: 'claude-sonnet-4-20250514',
max_tokens: 1024,
messages: [{
role: 'user',
content: `Summarize this git diff into a clean changelog. Group changes into categories like "New Features", "Bug Fixes", "Refactoring", "Configuration", etc. Only include categories that have changes. Use bullet points. Be concise but specific. At the end, include a stats line with files changed, insertions, and deletions.
\`\`\`diff
${truncateDiff(diff)}
\`\`\``
}],
});
console.log(message.content[0].text);
}
summarize();
Step 3: Set your API key
export ANTHROPIC_API_KEY=your-key-here
# Add to your shell profile for persistence
echo 'export ANTHROPIC_API_KEY=your-key-here' >> ~/.zshrc
Step 4: Test it
# Make some changes in a git repo, then:
node index.js
# Or link it globally:
npm link
git-summary
Making it smarter
Compare specific branches
Add branch comparison support by accepting arguments:
const args = process.argv.slice(2);
const target = args[0] || 'HEAD~1';
const diff = execSync(`git diff ${target} --stat -p`, { encoding: 'utf-8' });
Now you can run:
git-summary main # compare current branch to main
git-summary HEAD~5 # last 5 commits
git-summary v1.2.0 # since a tag
Add a commit message generator
Extend the tool to also suggest a commit message:
async function generateCommitMessage() {
const diff = execSync('git diff --cached --stat -p', { encoding: 'utf-8' });
if (!diff.trim()) {
console.log('No staged changes. Run `git add` first.');
return;
}
const client = new Anthropic();
const message = await client.messages.create({
model: 'claude-sonnet-4-20250514',
max_tokens: 256,
messages: [{
role: 'user',
content: `Write a concise conventional commit message for this diff. Format: type(scope): description. Keep it under 72 characters. Only output the commit message, nothing else.
\`\`\`diff
${truncateDiff(diff)}
\`\`\``
}],
});
console.log(message.content[0].text);
}
// Route based on flag
if (process.argv.includes('--commit')) {
generateCommitMessage();
} else {
summarize();
}
git-summary --commit
# Output: feat(auth): add JWT authentication with refresh token rotation
Save summaries to a file
import { writeFileSync } from 'fs';
if (process.argv.includes('--save')) {
const date = new Date().toISOString().split('T')[0];
writeFileSync(`changelog-${date}.md`, summary);
console.log(`Saved to changelog-${date}.md`);
}
Cost
Each summary costs roughly $0.003-0.01 depending on diff size. You could run this 1,000 times for under $10. For most developers, the monthly cost is negligible.
What you learned
- How to build a CLI tool with Node.js and the
binfield in package.json - How to use the Anthropic SDK to call Claudeβs API
- How to pipe git output into an AI prompt
- How to structure prompts for consistent, formatted output
The full code is about 60 lines. You can extend it with PR description generation, release notes, or even automatic CHANGELOG.md updates. The pattern is always the same: get the diff, send it to the API with a clear prompt, format the output.
FAQ
Which LLM works best for summarizing diffs?
For short diffs (<500 lines): GPT-4o-mini or DeepSeek Chat work great and are cheap. For large diffs or when you need high-quality PR descriptions: Claude Sonnet or GPT-4o. The key is the prompt β tell the model to focus on what changed functionally, not line-by-line.
How do I handle large diffs that exceed the context window?
Split the diff by file and summarize each file separately, then create an overall summary. Or filter out noise: exclude lock files, generated code, and test snapshots from the diff before sending to the LLM.
Can I use this in a GitHub Action for automatic PR descriptions?
Yes. Run the summarizer in a GitHub Action triggered on pull_request events, then use the GitHub API to update the PR body with the generated summary. This gives every PR an automatic description without developer effort.
How much does this cost per commit?
A typical commit diff is 200-500 tokens input. At GPT-4o-mini rates ($0.15/1M input): about $0.0001 per commit. Even summarizing 100 commits/day costs less than $0.01/day. With DeepSeek, itβs 10x cheaper.
Related resources
- Git Cheat Sheet
- Git Complete Guide
- npm Complete Guide
- Build Changelog Generator
- Build Discord Code Roast Bot
- How to Reduce LLM API Costs