在本地Git安装中,我可以使用"git show"以查找特定的提交,给定SHA1哈希前缀、分支名称或标记名称。
如何使用TFS/Azure Devops API实现相同的功能?
我尝试过Microsoft.TeamFoundation.SourceControl.WebApi.GitHttpClientBase.[GetCommitsAsync][1]()
,但对于SearchCriteria.ItemVersion
和CompareVersion
,我需要提供一个VersionType
(Branch、Tag或Commit(,所以与git show不同,我必须知道我有什么类型的标识符。此外,在";提交";,它必须是一个完整的SHA1散列;前缀不行。此外,我想只找到一个提交,而不是整个列表。
并且Microsoft.TeamFoundation.SourceControl.WebApi.GitHttpClientBase.GetCommitAsync()
只适用于完整的SHA1散列,而不适用于前缀、分支或标记。
是否有任何API调用等价于;git show"?
如果版本很重要,它是TFS服务器2019(Dev17.M153.5(。
Azure DevOps在UI的提交页面上有一个搜索框。将其与部分哈希一起使用,可以得到以下查询条件。它使用GET Commit REST方法:
{
"fromCommitId": "b86c400000000000000000000000000000000000",
"toCommitId": "b86c4fffffffffffffffffffffffffffffffffff",
"skip": 0,
"maxResultCount": 25
}
或者将searchCriteria.itemVersion.version
设置为确切名称,将searchCriteria.itemVersion.versionType
设置为branch
或tag
或commit
,以搜索特定提交,以防您知道全名(分支、标记或完整提交id(。
我使用Chrome开发工具来捕获请求。最坏的情况是,短散列不是唯一的,它将返回多个选项。
对于分支和标记,您还可以使用refs
API,它有一个start-with和一个contains选项来查找要查找的ref。
示例:
GET https://dev.azure.com/fabrikam/_apis/git/repositories/{repositoryId}/refs?filter=heads/&filterContains=replacer&api-version=6.0
为分支搜索filter=heads/
,为标记搜索filter=tags/
,或者将主过滤器留空以同时搜索两者。
理论上,这个API可以返回多个对象,因为它对filter
使用startsWith
,对filterContains
使用contains
。
使用Jesse的提示,我提出了这个实现:
public async Task<GitCommit> GetCommitClever(string id)
{
return await GetCommitFromTag(id)
?? await GetCommitFromBranch(id)
?? await GetCommitFromHashPrefix(id);
}
private async Task<GitCommit> GetCommit(string commitId)
{
return await m_gitClient.GetCommitAsync(commitId, m_repo.Id).ConfigureAwait(false);
}
private async Task<GitCommit> GetCommitFromTag(string id)
{
var refs = await m_gitClient.GetRefsAsync(m_repo.Id, filter: "tags/" + id).ConfigureAwait(false);
if (refs == null || refs.Count != 1)
{
return null;
}
var tag = await m_gitClient.GetAnnotatedTagAsync(m_repo.ProjectReference.Id, m_repo.Id, refs[0].ObjectId).ConfigureAwait(false);
return await GetCommit(tag.TaggedObject.ObjectId);
}
private async Task<GitCommit> GetCommitFromBranch(string id)
{
var refs = await m_gitClient.GetRefsAsync(m_repo.Id, filter: "heads/" + id).ConfigureAwait(false);
if (refs == null || refs.Count != 1)
{
return null;
}
return await GetCommit(refs.Single().ObjectId).ConfigureAwait(false);
}
private async Task<GitCommit> GetCommitFromHashPrefix(string id)
{
if (!System.Text.RegularExpressions.Regex.IsMatch(id, @"Ab[0-9a-fA-F]+bZ"))
{
throw new ArgumentException($"Branch or tag '{id}' not found.");
}
GitQueryCommitsCriteria crit = new GitQueryCommitsCriteria()
{
FromCommitId = id.PadRight(40, '0'),
ToCommitId = id.PadRight(40, 'f')
};
var refs = await m_gitClient.GetCommitsAsync(m_repo.Id, crit, top: 2).ConfigureAwait(false);
if (refs == null || refs.Count == 0)
{
throw new ArgumentException($"Commit '{id}' not found.");
}
if (refs.Count > 1)
{
throw new ArgumentException($"Commit id '{id}' not unique.");
}
return await GetCommit(refs.Single().CommitId).ConfigureAwait(false);
}
// Using these private members:
private GitHttpClient m_gitClient;
private GitRepository m_repo;
还有改进的空间;例如,如果你有一个标签";foobar";以及分支";foo";,则通过id获得提交";foo";将返回标记,而不是更好匹配的分支。但我只需要有限的聪明,所以这就行了