15

我正在尝试使用 GitHub v3 API 来获取两个 SHA 之间的完整提交列表,使用比较 API ( /repos/:owner/:repo/compare/:base...:head),但它只返回前 250 个提交,我需要获取所有提交。

我找到了 API 分页文档,但比较 API 似乎不支持pageorper_page参数,无论是计数还是 SHA(编辑last_sha参数也不起作用)。与提交 API 不同,比较 API 似乎不返回LinkHTTP 标头。

有什么方法可以增加比较 API 的提交计数限制或获取第二页提交?

4

10 回答 10

2

尝试使用参数sha,例如:

https://api.github.com/repos/junit-team/junit/commits?sha=XXX,其中 XXX 是当前轮次查询中最后返回的提交的 SHA。然后重复这个过程,直到你到达结束的 SHA。

示例python代码:

startSHA = ''
endSHA = ''
while True:
    url = 'https://api.github.com/repos/junit-team/junit/commits?sha=' + startSHA
    r = requests.get(url)
    data = json.loads(r.text)
    for i in range(len(data)):
        commit = data[i]['sha']
        if commit == endSHA:
            #reach the ending SHA, stop here
        startSHA = commit
于 2014-10-09T07:34:28.890 回答
1

我再次尝试解决这个问题。我的笔记:

  • 比较(或拉取请求提交)列表仅显示 250 个条目。对于拉取请求,您可以分页,但无论您做什么,最多只能获得 250 次提交。

  • 提交列表 API 可以遍历整个提交链,分页一直到存储库的开头。

  • 对于拉取请求,“基本”提交不一定在拉取请求“头”提交可访问的历史记录中。这是相同的比较,“base_commit”不一定是当前头部历史的一部分。

  • 然而,“merge_base_commit”是历史的一部分,因此正确的方法是从“head”提交开始,并迭代提交列表查询,直到到达“merge_base_commit”。对于拉取请求,这意味着必须分别对拉取的“头”和“基”进行比较。

  • 另一种方法是使用比较返回的“total_commits”,然后向后迭代直到达到所需的提交次数。这似乎可行,但是我不能 100% 确定这在所有带有合并等的极端情况下都是正确的。

因此,提交列表 API、分页和“merge_base_commit”解决了这个难题。

于 2014-12-18T09:22:09.833 回答
1

这相对容易。这是一个例子:

import requests
next_url = 'https://api.github.com/repos/pydanny/django-admin2/commits'
while next_url:
    response = requests.get(next_url)
    # DO something with response
    # ...
    # ...
    if 'next' in response.links:
        next_url = response.links['next']['url']
    else:
        next_url = ''

更新:

takie 请记住,下一个 url 与初始 ex 不同:初始 url:

https://api.github.com/repos/pydanny/django-admin2/commits

下一个网址:

https://api.github.com/repositories/10054295/commits?top=develop&last_sha=eb204104bd40d2eaaf983a5a556e38dc9134f74e

所以这是全新的 url 结构。

于 2013-09-07T10:20:13.807 回答
0

尝试使用last_sha参数。提交 API 似乎将其用于分页而不是page

于 2013-01-24T11:02:02.073 回答
0

我对此有一个解决方案,但它并不美味。这相当于自己构建图表。一般的策略是递归地在 BASE 和 BRANCH 之间请求更多的比较对象,直到找到正确的提交数量。如果没有优化,这对于大型比较来说是非常站不住脚的。通过优化,我发现在比较中每 50 个唯一提交需要大约 1 个比较调用。

import Github
repo = Github(MY_PAT).get_repo(MY_REPO)

def compare(base_commit, branch_commit):
  comparison = repo.compare(base_commit, branch_commit)
  result = set()
  unexplored_commits = set()
  for commit in comparison.commits:
    result.add(commit.sha)
    unexplored_commits.add(commit.sha)
    for parent in commit.parents:
      # It's possible that we'll need to explore a commit's parents directly. E.g., if it's
      # a merge of a large (> 250 commits) recent branch with an older branch.
      unexplored_commits.add(parent.sha)
  while len(commits) < comparison.total_commits:
    commit_to_explore = unexplored_commits.pop()
    commits.update(compare(base_commit, commit_to_explore))
  return commits

如果你真的想实现这个,我发现有用的优化都是围绕选择要探索的提交。例如:

  • 选择提交以随机探索,而不是使用.pop(). 这避免了一类更坏的情况。我把它放在第一位主要是因为它很简单。
  • 跟踪您已经拥有其完整祖先列表的提交,因此您知道不要不必要地探索这些提交。这是“自己构建图表”部分。
  • 如果您base_commit在该范围内找到 的祖先,请将它们用作二等分点。
于 2018-10-18T07:01:30.793 回答
0

/commits?per_page=* 会给你所有的提交

于 2017-06-15T09:26:14.503 回答
0

这是使用 Octokit.NET ( https://github.com/octokit/octokit.net )编写的获取拉取请求的所有提交的示例

       var owner = "...";
       var repository = "...";
       var gitHubClient = new GitHubClient(
               new ProductHeaderValue("MyApp"),
               new InMemoryCredentialStore(new Credentials("GitHubToken")));
        var pullRequest = await gitHubClient.PullRequest.Get(owner, repository, pullRequestNumber);
        Console.WriteLine("Summarising Pull Request #{0} - {1}", pullRequest.Number, pullRequest.Title);
        var commits = new List<GitHubCommit>();
        var moreToGet = true;
        var headSha = pullRequest.Head.Sha;
        while (moreToGet)
        {
            var comparison =
                await
                gitHubClient.Repository.Commits.Compare(
                    owner,
                    repository,
                    pullRequest.Base.Sha,
                    headSha);

            // Because we're working backwards from the head towards the base, but the oldest commits are at the start of the list
            commits.InsertRange(0, comparison.Commits);
            moreToGet = comparison.Commits.Count == 250;
            if (moreToGet)
            {
                headSha = commits.First().Sha;
            }
        }

如果找到具有基本 sha 的提交,我最初尝试将 moreToGet 设置为 true,但从未包含在提交列表中(不知道为什么)所以我只是假设如果比较命中是 250 的限制,可以获得更多。

于 2015-09-09T08:02:27.433 回答
0

截至 2021 年 3 月 22 日,GitHub 的 v3 REST API 支持分页 – https://github.blog/changelog/2021-03-22-compare-rest-api-now-supports-pagination/

您只需附加?per_page=100&page=1到您的/compare/URL。

例如:

于 2021-12-28T16:19:59.160 回答
0

这是我使用 Octokit.Net 的解决方案

private async Task<IReadOnlyList<GitHubCommit>> GetCommits(string branch, string baseBranch)
{
    // compare branches and get all commits returned
    var result = await this.gitHub.Repository.Commit.Compare(this.repoSettings.Owner, this.repoSettings.Name, baseBranch, branch);
    var commits = result.Commits.ToList();

    // the commits property on the result only has the first 250 commits
    if (result.TotalCommits > 250)
    {
        var baseCommitId = result.MergeBaseCommit.Sha;
        var lastCommitLoadedId = commits.First().Sha;
        var allCommitsLoaded = false;
        var page = 1;

        while (!allCommitsLoaded)
        {
            var missingCommits = await this.gitHub.Repository.Commit.GetAll(this.repoSettings.Owner, this.repoSettings.Name, new CommitRequest
            {
                Sha = lastCommitLoadedId // start from the oldest commit returned by compare
            },
            new ApiOptions
            {
                PageCount = 1,
                PageSize = 100, // arbitrary page size - not sure what the limit is here so set it to a reasonably large number
                StartPage = page
            });

            foreach (var missingCommit in missingCommits)
            {
                if (missingCommit.Sha == lastCommitLoadedId)
                {
                    // this is the oldest commit in the compare result so we already have it
                    continue; 
                }

                if (missingCommit.Sha == baseCommitId)
                {
                    // we don't want to include this commit - its the most recent one on the base branch
                    // we've found all the commits now we can break out of both loops
                    allCommitsLoaded = true;
                    break;
                }

                commits.Add(missingCommit);
            }

            page++;
        }
    }

    return commits;
}
于 2017-12-14T16:03:04.530 回答
-1

来自:https ://developer.github.com/v3/repos/commits/#working-with-large-comparisons

处理大型比较

响应将包括最多 250 个提交的比较。如果您正在处理更大的提交范围,则可以使用提交列表 API 枚举该范围内的所有提交。

对于与非常大的差异进行比较,您可能会收到错误响应,表明差异生成时间过长。您通常可以通过使用较小的提交范围来解决此错误

于 2014-08-15T22:02:31.920 回答