能否用LibGit2Sharp复现指定git log命令并获取文件统计?
用LibGit2Sharp复现目标Git命令并实现需求
完全可以用LibGit2Sharp复现你指定的git命令,同时满足获取提交哈希、作者日期、文件增删行数,以及处理路径变更/重命名的需求。以下是具体实现思路和代码示例:
1. 核心配置与提交遍历
首先初始化仓库,设置和原命令匹配的提交遍历规则:
- 只走当前分支的第一父提交(对应
--first-parent) - 过滤出过去61个月内的提交(对应
--since-as-filter=61.months.ago) - 仅加载必要字段,跳过提交消息以节省资源
using LibGit2Sharp; using System; using System.Collections.Generic; using System.Linq; var repoPath = "你的仓库路径"; var cutoffDate = DateTime.Now.AddMonths(-61); using var repo = new Repository(repoPath); var currentBranch = repo.Head; // 构建提交过滤规则 var commitFilter = new CommitFilter { IncludeReachableFrom = currentBranch, FirstParentOnly = true, Since = cutoffDate, SortBy = CommitSortStrategies.Time // 按提交时间排序 };
2. 获取提交的文件统计与变更信息
LibGit2Sharp的Commit对象通过Stats属性提供文件增删行数,同时利用TreeChanges可以识别文件重命名、路径变更等操作:
foreach (var commit in repo.Commits.QueryBy(commitFilter)) { // 获取提交完整哈希和本地时区的作者日期 var commitHash = commit.Sha; var localAuthorDate = commit.Author.When.ToLocalTime(); // 跳过初始提交(无父提交)的特殊处理 var parentCommit = commit.Parents.FirstOrDefault(); if (parentCommit == null) continue; // 对比当前提交与父提交的树变更,识别重命名/路径修改 var treeChanges = repo.Diff.Compare<TreeChanges>(parentCommit.Tree, commit.Tree); foreach (var change in treeChanges) { string targetFilePath = change.Path; // 处理重命名:保留原路径或新路径可按需调整 if (change.Status == ChangeKind.Renamed) { targetFilePath = change.OldPath; } // 获取当前文件的增删行数 if (commit.Stats.TryGetEntry(targetFilePath, out var fileStat)) { int additions = fileStat.Additions; int deletions = fileStat.Deletions; // 此处可将数据存入自定义对象或字典,用于后续任务处理 } } }
3. 实现你的两个核心任务
任务1:找出每个文件最后被修改的时间
用字典记录每个文件的最新修改时间,遍历提交时更新:
var fileLastModified = new Dictionary<string, DateTime>(); foreach (var commit in repo.Commits.QueryBy(commitFilter)) { var localDate = commit.Author.When.ToLocalTime(); var parentCommit = commit.Parents.FirstOrDefault(); if (parentCommit == null) continue; var treeChanges = repo.Diff.Compare<TreeChanges>(parentCommit.Tree, commit.Tree); foreach (var change in treeChanges) { // 处理重命名场景,同时更新原路径和新路径的记录 if (change.Status == ChangeKind.Renamed) { UpdateFileLastModified(change.OldPath, localDate); UpdateFileLastModified(change.Path, localDate); } else { UpdateFileLastModified(change.Path, localDate); } } } // 辅助方法:更新文件最后修改时间 void UpdateFileLastModified(string filePath, DateTime newDate) { if (!fileLastModified.ContainsKey(filePath) || newDate > fileLastModified[filePath]) { fileLastModified[filePath] = newDate; } }
任务2:统计过去30天内的代码增删行数
添加时间过滤,仅统计近30天的提交数据:
var thirtyDaysAgo = DateTime.Now.AddDays(-30); int totalAdditions = 0; int totalDeletions = 0; foreach (var commit in repo.Commits.QueryBy(commitFilter)) { var localDate = commit.Author.When.ToLocalTime(); // 跳过30天前的提交 if (localDate < thirtyDaysAgo) continue; var parentCommit = commit.Parents.FirstOrDefault(); if (parentCommit == null) continue; var treeChanges = repo.Diff.Compare<TreeChanges>(parentCommit.Tree, commit.Tree); foreach (var change in treeChanges) { string filePath = change.Status == ChangeKind.Renamed ? change.OldPath : change.Path; if (commit.Stats.TryGetEntry(filePath, out var fileStat)) { totalAdditions += fileStat.Additions; totalDeletions += fileStat.Deletions; } } } // 输出统计结果 Console.WriteLine($"近30天新增行数:{totalAdditions}"); Console.WriteLine($"近30天删除行数:{totalDeletions}");
关键注意事项
- 重命名处理:通过
TreeChanges的ChangeKind.Renamed标记,可以避免将同一文件的不同路径视为独立文件,保证统计准确性。 - 性能优化:全程仅加载必要的提交属性,跳过提交消息等无关数据,适配无服务器环境的资源限制。
- 时区转换:LibGit2Sharp默认使用UTC时间,通过
ToLocalTime()转换为本地时间,和原命令的--date=local行为一致。
内容的提问来源于stack exchange,提问作者scottctr
相关产品推荐
相关产品推荐

