使用Azure DevOps API获取Git提交的实际变更内容(Diff)
Azure DevOps Git API 获取提交变更内容及代码优化
一、解决变更内容为null的问题
你当前使用GetCommitDiffsAsync获取的差异结果中,GitItem.Content和GitChange.NewContent默认不会返回实际文件内容,需要针对每个变更的文件单独调用API获取内容:
- 对于每个变更项,通过
GitChange.Item.Path获取文件路径 - 调用
GitHttpClient.GetItemContentAsync方法,传入仓库ID、项目名、文件路径,以及目标版本(当前提交ID)来获取文件内容
示例修改后的代码片段:
foreach(var change in diff.Changes) { // 获取变更文件的内容 var contentStream = gitClient.GetItemContentAsync( repositoryId: repositoryId, project: project, path: change.Item.Path, versionDescriptor: new GitVersionDescriptor { VersionType = GitVersionType.Commit, Version = commit.CommitId }).WaitForResult(); // 将Stream转换为字符串输出 using (var reader = new StreamReader(contentStream)) { Debug.WriteLine(reader.ReadToEnd()); } }
该方式能覆盖修改、新增等各类文件变更场景,无需依赖NewContent.Uri这类特定字段。
二、简化代码减少API调用
你的代码存在冗余API调用,可从以下两点优化:
移除多余的
GetCommitAsync调用GetCommitsAsync返回的GitCommitRef对象已包含Parents属性,无需再次调用GetCommitAsync获取完整提交信息,直接使用commit.Parents即可,减少一次API请求。过滤不必要的文件减少请求
循环内的文件内容请求是主要的API消耗点,可优先过滤需要检查的文件类型(如仅检查.cs、.json等),避免获取无关文件的内容。
优化后的完整代码:
private void GetGitChanges() { var organization = "org"; var project = "proj"; var repositoryId = "repo"; var uri = $"https://tfs.foobar.se/tfs/{organization}/"; var pat = ConfigurationManager.AppSettings["PAT"]; using (var conn = new VssConnection(new Uri(uri), new VssBasicCredential("", pat))) { var gitClient = conn.GetClient<GitHttpClient>(); var searchCriteria = new GitQueryCommitsCriteria { IncludeWorkItems = true, ItemVersion = new GitVersionDescriptor { VersionType = GitVersionType.Branch, VersionOptions = GitVersionOptions.FirstParent, Version = "master" } }; var commits = gitClient.GetCommitsAsync(project, repositoryId, searchCriteria).WaitForResult(); foreach(var commit in commits) { if (commit.Parents?.Any() ?? false) { var parentCommitId = commit.Parents.First(); var diff = gitClient.GetCommitDiffsAsync( repositoryId: repositoryId, project: project, diffCommonCommit: false, targetVersionDescriptor: new GitTargetVersionDescriptor { Version = commit.CommitId, VersionType = GitVersionType.Commit, VersionOptions = GitVersionOptions.None }, baseVersionDescriptor: new GitBaseVersionDescriptor { Version = parentCommitId, VersionType = GitVersionType.Commit, VersionOptions = GitVersionOptions.None }).WaitForResult(); foreach(var change in diff.Changes) { // 过滤仅检查.cs文件,可根据需求调整 if (!change.Item.Path.EndsWith(".cs", StringComparison.OrdinalIgnoreCase)) { continue; } var contentStream = gitClient.GetItemContentAsync( repositoryId: repositoryId, project: project, path: change.Item.Path, versionDescriptor: new GitVersionDescriptor { VersionType = GitVersionType.Commit, Version = commit.CommitId }).WaitForResult(); using (var reader = new StreamReader(contentStream)) { Debug.WriteLine($"文件路径:{change.Item.Path}"); Debug.WriteLine($"内容:{reader.ReadToEnd()}"); } } } } } }
额外提示
- 确保你的PAT拥有Code Read权限,否则无法获取文件内容
- 若遇到API限流问题,可添加重试逻辑或降低并发请求数
内容的提问来源于stack exchange,提问作者Anders Lindén
相关产品推荐
相关产品推荐

