get_git_diff
Retrieve the full unified diff between two git refs, returning diff text, file list, and addition/deletion counts. Use to review changes before logging them to the ledger.
Instructions
Get the full unified diff between two refs (default: HEAD~1..HEAD). Returns diff text, file list, and addition/deletion counts. Use to review changes before logging them to the ledger.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| base | No | Base git ref to diff against. Defaults to HEAD~1 (last commit). Use "HEAD" for uncommitted changes. | |
| file | No | Optional file path to scope the diff to a single file. |
Implementation Reference
- src/access/GitAccess.ts:137-179 (handler)Core implementation of getDiff that executes `git diff --stat` and `git diff` commands, parses additions/deletions, file list, and truncates output at 80,000 chars.
async function getDiff( repoDir: string, base?: string, filePath?: string, ): Promise<DiffResult> { const MAX_DIFF = 80_000; const ref = base ?? 'HEAD~1'; // Stat summary: additions/deletions + file list const statArgs = ['-C', repoDir, 'diff', '--stat', ref, 'HEAD']; if (filePath) statArgs.push('--', filePath); // Full diff const diffArgs = ['-C', repoDir, 'diff', ref, 'HEAD']; if (filePath) diffArgs.push('--', filePath); const [statResult, diffResult] = await Promise.all([ execFileAsync('git', statArgs), execFileAsync('git', diffArgs), ]); const raw = diffResult.stdout; const truncated = raw.length > MAX_DIFF; const diff = truncated ? raw.slice(0, MAX_DIFF) + '\n\n[...truncated]' : raw; // Parse additions/deletions from stat const addMatch = statResult.stdout.match(/(\d+) insertion/); const delMatch = statResult.stdout.match(/(\d+) deletion/); // File list from stat lines const files = statResult.stdout .split('\n') .filter((l) => l.includes('|')) .map((l) => (l.split('|')[0] ?? '').trim()); return { diff, files, additions: addMatch?.[1] != null ? parseInt(addMatch[1], 10) : 0, deletions: delMatch?.[1] != null ? parseInt(delMatch[1], 10) : 0, truncated, }; } - Zod schema for get_git_diff: optional 'base' (default HEAD~1) and 'file' (single file scope) params.
export const GetGitDiffSchema = z.object({ base: z .string() .optional() .describe( 'Base git ref to diff against. Defaults to HEAD~1 (last commit). Use "HEAD" for uncommitted changes.', ), file: z .string() .optional() .describe('Optional file path to scope the diff to a single file.'), }); - src/tools/dev-lifecycle.tool.ts:66-77 (registration)MCP tool registration of 'get_git_diff' with schema and handler that delegates to manager.getDiff.
server.tool( 'get_git_diff', 'Get the full unified diff between two refs (default: HEAD~1..HEAD). Returns diff text, file list, and addition/deletion counts. Use to review changes before logging them to the ledger.', GetGitDiffSchema.shape, async (args) => { const result = await manager.getDiff(args.base, args.file); return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }], }; }, ); } - DevLifecycleManager interface declaring getDiff method.
export interface DevLifecycleManager { runTypecheck(servicePath: string): Promise<TypecheckResult>; runTests(servicePath: string, pattern?: string): Promise<TestResult>; getDiff(base?: string, filePath?: string): Promise<DiffResult>; - Manager getDiff method that delegates to GitAccess.getDiff with the repo directory.
async function getDiff(base?: string, filePath?: string): Promise<DiffResult> { return git.getDiff(repoDir, base, filePath); }