get_merge_recommendations
Analyze git branches to generate merge strategy recommendations for resolving conflicts and integrating code changes.
Instructions
Get detailed merge strategy recommendations
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| repoPath | Yes | Path to git repository | |
| branches | Yes | Branches to analyze | |
| outputPath | Yes | Path to write analysis output |
Implementation Reference
- src/index.ts:325-341 (handler)The main handler function that executes the get_merge_recommendations tool logic. It computes merge strategy, conflict risks, and steps using helper methods, writes JSON output to the specified path, and returns a success message.private async handleMergeRecommendations(args: MergeRecommendationsArgs) { const recommendations = { strategy: this.determineMergeStrategy(args.repoPath, args.branches), conflictRisks: this.assessConflictRisks(args.repoPath, args.branches), steps: this.generateMergeSteps(args.repoPath, args.branches), }; writeFileSync(args.outputPath, JSON.stringify(recommendations, null, 2)); return { content: [ { type: 'text', text: `Merge recommendations written to ${args.outputPath}`, }, ], };
- src/index.ts:203-209 (registration)The switch case in the CallToolRequestSchema handler that routes calls to 'get_merge_recommendations' to the handleMergeRecommendations method after parameter validation.case 'get_merge_recommendations': { const args = request.params.arguments as MergeRecommendationsArgs; if (!args?.repoPath || !args?.branches || !args?.outputPath) { throw new McpError(ErrorCode.InvalidParams, 'Missing required parameters'); } return await this.handleMergeRecommendations(args); }
- src/index.ts:153-175 (registration)The tool registration in the ListToolsRequestSchema response, including name, description, and input schema.{ name: 'get_merge_recommendations', description: 'Get detailed merge strategy recommendations', inputSchema: { type: 'object', properties: { repoPath: { type: 'string', description: 'Path to git repository', }, branches: { type: 'array', items: { type: 'string' }, description: 'Branches to analyze', }, outputPath: { type: 'string', description: 'Path to write analysis output', }, }, required: ['repoPath', 'branches', 'outputPath'], }, },
- src/index.ts:37-41 (schema)TypeScript interface defining the input arguments for the get_merge_recommendations tool.interface MergeRecommendationsArgs { repoPath: string; branches: string[]; outputPath: string; }
- src/index.ts:341-472 (helper)Helper method called by the handler to determine the recommended merge strategy based on commit counts.}; } private getLastCommit(repoPath: string, branch: string) { const output = execSync( `cd "${repoPath}" && git log -1 --format="%H|%aI|%s" ${branch}`, { encoding: 'utf8' } ).trim(); const [hash, date, message] = output.split('|'); return { hash, date, message, branch }; } private getCommitCount(repoPath: string, branch: string): number { return parseInt( execSync( `cd "${repoPath}" && git rev-list --count ${branch}`, { encoding: 'utf8' } ).trim(), 10 ); } private getMergeBase(repoPath: string, branch1: string, branch2: string): string { return execSync( `cd "${repoPath}" && git merge-base ${branch1} ${branch2}`, { encoding: 'utf8' } ).trim(); } private getCommitsInRange( repoPath: string, branch: string, timeRange: { start: string; end: string } ) { const output = execSync( `cd "${repoPath}" && git log --format="%H|%aI|%s" ` + `--after="${timeRange.start}" --before="${timeRange.end}" ${branch}`, { encoding: 'utf8' } ); return output.trim().split('\n').filter(Boolean).map(line => { const [hash, date, message] = line.split('|'); return { hash, date, message, branch }; }); } private getFileHistory(repoPath: string, branch: string, file: string) { const output = execSync( `cd "${repoPath}" && git log --format="%H|%aI|%s" ${branch} -- ${file}`, { encoding: 'utf8' } ); return output.trim().split('\n').filter(Boolean).map(line => { const [hash, date, message] = line.split('|'); return { hash, date, message, branch }; }); } private summarizeActivity(commits: Array<{ hash: string; date: string; message: string; branch: string }>) { return { totalCommits: commits.length, firstCommit: commits[commits.length - 1], lastCommit: commits[0], commitTypes: this.categorizeCommits(commits), }; } private categorizeCommits(commits: Array<{ message: string }>) { const categories = { feature: 0, fix: 0, refactor: 0, docs: 0, other: 0, }; commits.forEach(({ message }) => { if (message.match(/^feat|^add/i)) categories.feature++; else if (message.match(/^fix|^bug/i)) categories.fix++; else if (message.match(/^refactor|^style|^chore/i)) categories.refactor++; else if (message.match(/^docs/i)) categories.docs++; else categories.other++; }); return categories; } private analyzeConflicts(branchChanges: Array<{ branch: string; history: Array<{ hash: string; date: string; message: string }> }>) { const overlaps = this.findOverlappingChanges(branchChanges); return { riskLevel: this.assessRiskLevel(overlaps), reasons: this.generateConflictReasons(overlaps), }; } private findOverlappingChanges(branchChanges: Array<{ branch: string; history: Array<{ date: string }> }>) { const timeRanges = branchChanges.map(({ branch, history }) => ({ branch, start: history[history.length - 1]?.date, end: history[0]?.date, })); return timeRanges.flatMap((range1, i) => timeRanges.slice(i + 1).map(range2 => ({ branches: [range1.branch, range2.branch], overlaps: this.datesOverlap( new Date(range1.start), new Date(range1.end), new Date(range2.start), new Date(range2.end) ), })) ).filter(({ overlaps }) => overlaps); } private datesOverlap(start1: Date, end1: Date, start2: Date, end2: Date): boolean { return start1 <= end2 && start2 <= end1; } private assessRiskLevel(overlaps: Array<{ branches: string[] }>) { if (overlaps.length === 0) return 'low'; if (overlaps.length <= 2) return 'medium'; return 'high'; } private generateConflictReasons(overlaps: Array<{ branches: string[] }>) { return overlaps.map(({ branches }) => `Parallel development detected between ${branches.join(' and ')}` ); } private determineMergeStrategy(repoPath: string, branches: string[]) {