是否有等效于 'git log --follow -- <File name>' 的 Azure DevOps Git REST API 操作?

Is there an equivalent Azure DevOps Git REST API operation to 'git log --follow -- <File name>'?

我正在尝试使用 get-commits API 端点获取给定 git 项目的第一次提交:https://docs.microsoft.com/en-us/rest/api/azure/devops/git/commits/get-commits?view=azure-devops-rest-6.0.

我的问题是,如果文件已重命名,则重命名之前文件的提交历史将丢失。从命令行使用 git 我可以将 --follow 标志添加到 return 重命名之前文件的历史记录。

我找不到使用 Azure DevOps Git REST API 的等效操作。有吗?

一些附加信息: 我正在尝试获取给定项目的第一次提交,以便获得该项目的第一作者。似乎没有直接的方法可以在不先查询提交的情况下获取作者,这就是为什么我要尝试获取第一个提交。

编辑:鉴于 TTT 的回答,我添加了输出以显示完整历史+简化合并标志和以下标志之间的区别:

--完整历史--简化合并

$ git log --full-history --simplify-merges -- Custom/Scripts/js_file_renamed.js
commit xxx
Author: xxx xxx <xxx.com>
Date:   Mon Feb 14 12:25:49 2022 +0100

    Rename commit

--关注

$ git log --follow -- Custom/Scripts/js_file_renamed.js
commit xxx
Author: xxx xxx <xxx@yyy.com>
Date:   Mon Feb 14 12:25:49 2022 +0100

    Rename commit

commit xxx
Author: xxx xxx <xxx@yyy.com>
Date:   Mon Feb 14 11:22:29 2022 +0000

    Revert "Content migrated."

commit xxx
Author: xxx xxx <xxx@yyy.com>
Date:   Mon Feb 14 11:20:14 2022 +0000

    Content migrated.

commit xxx
Author: xxx xxx <xxx@yyy.com>
Date:   Mon Feb 14 12:14:08 2022 +0100

    Add folders

编辑 2:

鉴于我还没有找到直接等同于 'git log --follow' 的方法,我做了以下解决方法:

  1. 使用文件路径和包含该文件所在分支的项目描述符执行 GET 提交。
  2. 如果最早获得的文件提交更改是添加,则 return 该提交。如果是重命名,则使用使用提交 ID 的 GET 提交来获取包含父提交的更详细模型。
  3. 获取第一个父提交并将差异与重命名提交进行比较以获得文件的先前名称。
  4. 递归,传入文件的先前名称,以及父提交 ID 作为项目描述符。

在伪代码中它看起来像这样:

private GitCommit GetFirstCommit(GitVersionDescriptor itemVersion, string path)
{
    commitQuery = new GitQueryCommitsCriteria
    {
        ItemVersion = itemVersion,
        ItemPath = path
    }

    commits = GET commits(commitQuery)
    firstCommit = commits.Last()
    if (!firstCommit) {
        return null;
    }

    isAdd = firstCommit.Changes.Any(y => y.ChangeType.HasFlag(VersionControlChangeType.Add));
    isRename = firstCommit.Changes.Any(y => y.ChangeType.HasFlag(VersionControlChangeType.Rename));

    fullCommitDetails = GET commit(firstCommit.CommitId);

    if (isAdd)
    {
        return fullCommitDetails
    }

    if (isRename)
    {
        parentId = fullCommitDetails.Parents.First();
        if (!parentId)
        {
            return null;
        }

        baseVersionDescriptor = new GitBaseVersionDescriptor() { VersionType = GitVersionType.Commit, Version = parentId };
        targetVersionDescriptor = new GitTargetVersionDescriptor() { VersionType = GitVersionType.Commit, Version = firstCommit.CommitId };
        diffs = GET diffs(baseVersionDescriptor, targetVersionDescriptor)

        previousPath = diffs.Changes
            .Where(x =>
                x.ChangeType.HasFlag(VersionControlChangeType.Rename) &&
                x.Item.Path == path)
            .Select(x => x.SourceServerItem)
            .SingleOrDefault()

        if (!previousPath)
        {
            return null;
        }

        return GetFirstCommit(baseVersionDescriptor, previousPath);
    }

    return null;
}

添加我自己的问题的答案,因为我还没有找到直接等同于 'git log --follow' 的答案。作为解决方法,我执行了以下操作:

  1. 使用文件路径和包含该文件所在分支的项目描述符执行 GET 提交。
  2. 如果最早获得的文件提交更改是添加,则 return 该提交。如果是重命名,则使用使用提交 ID 的 GET 提交来获取包含父提交的更详细模型。
  3. 获取第一个父提交并将差异与重命名提交进行比较以获得文件的先前名称。
  4. 递归,传入文件的先前名称,以及父提交 ID 作为项目描述符。

在伪代码中它看起来像这样:

private GitCommit GetFirstCommit(GitVersionDescriptor itemVersion, string path)
{
    commitQuery = new GitQueryCommitsCriteria
    {
        ItemVersion = itemVersion,
        ItemPath = path
    }

    commits = GET commits(commitQuery)
    firstCommit = commits.Last()
    if (!firstCommit) {
        return null;
    }

    isAdd = firstCommit.Changes.Any(y => y.ChangeType.HasFlag(VersionControlChangeType.Add));
    isRename = firstCommit.Changes.Any(y => y.ChangeType.HasFlag(VersionControlChangeType.Rename));

    fullCommitDetails = GET commit(firstCommit.CommitId);

    if (isAdd)
    {
        return fullCommitDetails
    }

    if (isRename)
    {
        parentId = fullCommitDetails.Parents.First();
        if (!parentId)
        {
            return null;
        }

        baseVersionDescriptor = new GitBaseVersionDescriptor() { VersionType = GitVersionType.Commit, Version = parentId };
        targetVersionDescriptor = new GitTargetVersionDescriptor() { VersionType = GitVersionType.Commit, Version = firstCommit.CommitId };
        diffs = GET diffs(baseVersionDescriptor, targetVersionDescriptor)

        previousPath = diffs.Changes
            .Where(x =>
                x.ChangeType.HasFlag(VersionControlChangeType.Rename) &&
                x.Item.Path == path)
            .Select(x => x.SourceServerItem)
            .SingleOrDefault()

        if (!previousPath)
        {
            return null;
        }

        return GetFirstCommit(baseVersionDescriptor, previousPath);
    }

    return null;
}