GitHttpClient.GetCommitDiffsAsync获取指定Commit文件内容异常求助
问题:Azure DevOps API 获取指定提交的文件内容时始终返回最新版本
背景代码
已连接Azure DevOps API并创建Git客户端:
var conn = new VssConnection(new Uri(uri), new VssBasicCredential("", pat)); var gitClient = conn.GetClient<GitHttpClient>();
获取提交列表:
var commits = gitClient.GetCommitsAsync(project, repo.Id.ToString(), searchCriteria).WaitForResult();
使用的WaitForResult扩展方法:
public static class TaskExtension { public static T WaitForResult<T>(this Task<T> task) where T : class { task.Wait(); return task.Result; } }
获取提交修改文件内容的代码
尝试获取每个提交中修改的VB文件内容,但始终返回最新版本:
var c2 = gitClient.GetCommitAsync(project: project, commitId: commit.CommitId, repositoryId: repositoryId) .WaitForResult(); if (c2.Parents?.Any() ?? false) { var parentCommitId = c2.Parents.First(); var desc = new GitTargetVersionDescriptor { Version = commit.CommitId, VersionType = GitVersionType.Commit, VersionOptions = GitVersionOptions.None }; var pdesc = new GitBaseVersionDescriptor { Version = parentCommitId, VersionType = GitVersionType.Commit, VersionOptions = GitVersionOptions.None }; var diff = gitClient.GetCommitDiffsAsync(repositoryId: repositoryId, project: project, diffCommonCommit: false, targetVersionDescriptor: desc, baseVersionDescriptor: pdesc ).WaitForResult(); foreach(var change in diff.Changes) { if (!change.Item.IsFolder && change.ChangeType == Microsoft.TeamFoundation.SourceControl.WebApi.VersionControlChangeType.Edit && change.Item.Path.EndsWith(".vb")) { var item = gitClient.GetItemAsync(project: project, repositoryId, path: change.Item.Path, versionDescriptor: desc, includeContent: true).WaitForResult(); /* 此处获取的item.Content始终为文件最新版本,即使使用pdesc结果也相同 */ } } }
核心问题
- 调用
GetItemAsync时,无论使用当前提交的版本描述符还是父提交的版本描述符,均返回文件的最新版本内容,而非对应提交版本的内容 - 即使在
Version中填入非SHA1格式的无效哈希值,API不报错,仍返回文件最新版本
原因与解决方案
核心原因
你错误地使用了GitTargetVersionDescriptor和GitBaseVersionDescriptor来指定单个版本的文件。这两个类型是专门用于差异比较场景(如GetCommitDiffsAsync)的参数,并不适用于单独获取某一提交版本的文件内容。当API无法识别这类不匹配的版本描述符时,会默认返回文件的最新版本。
解决方案
将获取文件内容时使用的版本描述符替换为通用的GitVersionDescriptor,该类型才是用于指定单个Git版本(提交、分支、标签等)的正确类型:
修改代码中的版本描述符创建逻辑:
// 替换原有的GitTargetVersionDescriptor var targetVersion = new GitVersionDescriptor { Version = commit.CommitId, VersionType = GitVersionType.Commit, VersionOptions = GitVersionOptions.None }; // 替换原有的GitBaseVersionDescriptor var parentVersion = new GitVersionDescriptor { Version = parentCommitId, VersionType = GitVersionType.Commit, VersionOptions = GitVersionOptions.None };
然后在GetItemAsync中使用修改后的版本描述符:
// 获取当前提交版本的文件内容 var item = gitClient.GetItemAsync(project: project, repositoryId, path: change.Item.Path, versionDescriptor: targetVersion, includeContent: true).WaitForResult(); // 若需要父提交版本的文件内容,使用parentVersion即可 // var parentItem = gitClient.GetItemAsync(project: project, repositoryId, // path: change.Item.Path, versionDescriptor: parentVersion, includeContent: true).WaitForResult();
额外验证
确保传入的commit.CommitId和parentCommitId是完整的SHA1哈希值(如示例中的e71789c1424ba1ea5c6a9edb5bca4fff1b647185),短哈希可能导致API无法准确定位到目标提交,同样会 fallback 到最新版本。
内容的提问来源于stack exchange,提问作者Anders Lindén
相关产品推荐
相关产品推荐

