Skip to main content
Glama

CodeGraph CLI MCP Server

by Jakedismo
history.rs4.59 kB
use crate::{errors::*, types::*}; use git2::{DiffOptions, Sort}; use std::collections::{BTreeMap, HashMap}; impl super::GitRepository { pub fn analyze_history(&self, opts: HistoryOptions) -> Result<HistoryInsights> { let repo = self.repository(); let mut revwalk = repo.revwalk()?; revwalk.set_sorting(Sort::TIME | Sort::REVERSE)?; // Determine start point if let Some(branch) = &opts.branch { let reference = repo.resolve_reference_from_short_name(branch)?; revwalk.push( reference .target() .ok_or_else(|| git2::Error::from_str("Invalid reference target"))?, )?; } else { revwalk.push_head()?; } let mut total_commits = 0usize; let mut authors: HashMap<(String, String), usize> = HashMap::new(); let mut file_churn: BTreeMap<String, FileChurn> = BTreeMap::new(); for (i, oid_res) in revwalk.enumerate() { if let Some(max) = opts.max_commits { if i >= max { break; } } let oid = match oid_res { Ok(oid) => oid, Err(_) => continue, }; let commit = match repo.find_commit(oid) { Ok(c) => c, Err(_) => continue, }; if let Some(since) = opts.since_timestamp { if commit.time().seconds() < since { continue; } } total_commits += 1; let sig = commit.author(); let name = sig.name().unwrap_or("unknown").to_string(); let email = sig.email().unwrap_or("").to_string(); *authors.entry((name, email)).or_insert(0) += 1; if commit.parent_count() == 0 { continue; } let _parent = match commit.parent(0) { Ok(p) => p, Err(_) => continue, }; let mut diffopts = DiffOptions::new(); let diff = repo.diff_tree_to_tree( commit .parent(0) .ok() .as_ref() .map(|p| p.tree().ok()) .flatten() .as_ref(), Some(&commit.tree().ok().unwrap()), Some(&mut diffopts), )?; let stats = diff.stats()?; // Iterate deltas for per-file churn diff.foreach( &mut |delta, _| { if let Some(path) = delta.new_file().path().or_else(|| delta.old_file().path()) { if let Some(path_str) = path.to_str() { let entry = file_churn.entry(path_str.to_string()).or_insert(FileChurn { additions: 0, deletions: 0, }); // Approximate by distributing stats evenly is too naive; do per-patch below if available let _ = entry; // fallthrough } } true }, None, None, None, )?; // If patch stats per file are needed, we can compute patches and sum hunk changes; keep it lightweight for large repos. let insertions = stats.insertions(); let deletions = stats.deletions(); // Assign to a synthetic "_aggregate" for repo-wide churn let agg = file_churn.entry("_aggregate".into()).or_insert(FileChurn { additions: 0, deletions: 0, }); agg.additions += insertions as usize; agg.deletions += deletions as usize; } let mut authors_vec: Vec<AuthorStat> = authors .into_iter() .map(|((name, email), commits)| AuthorStat { name, email, commits, }) .collect(); authors_vec.sort_by(|a, b| b.commits.cmp(&a.commits)); // Count branches analyzed let branches_analyzed = repo.branches(Some(git2::BranchType::Local))?.count(); Ok(HistoryInsights { total_commits, authors: authors_vec, file_churn, branches_analyzed, }) } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Jakedismo/codegraph-rust'

If you have feedback or need assistance with the MCP directory API, please join our Discord server