【问题标题】:GitHub v3 API: Get full commit list for large comparisonGitHub v3 API:获取完整的提交列表以进行大型比较
【发布时间】:2013-01-03 09:53:15
【问题描述】:

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

我找到了the API pagination docs,但比较 API 似乎不支持 pageper_page 参数,无论是计数还是 SHA(编辑last_sha 参数也不起作用)。与提交 API 不同的是,比较 API 似乎没有返回 Link HTTP 标头。

有没有办法增加比较 API 的提交计数限制或获取第二页提交?

【问题讨论】:

  • 我已经为您联系了 GitHub 支持。作为 API 包装器的作者,我自己对此很好奇。如果他们自己不回答,我会回复他们回答的内容。
  • 是的,他们从来没有回复我...对不起
  • @sigmavirus24 阅读我的回答,我认为这会有所帮助。

标签: git github github-api


【解决方案1】:

尝试使用参数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

【讨论】:

  • 使用分页更好。 Git 历史可能包含合并,其中仅采用最后一个 sha 只会跟随合并的一个父级。使用分页,这不会发生,因为所有父级的提交都会返回。
  • 这不会返回 OP 要求的答案。举个简单的例子,endSHA 可能不是 startSHA 的祖先。您可以通过在 startSHA 和 endSHA 的共同祖先处停止来解决这个问题,但我认为您无法解决结果按日期顺序返回的更大问题,并且 endSHA..startSHA 中的一些提交可能有比 endSHA 更早的日期。
【解决方案2】:

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

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 不同: 初始网址:

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

下一个网址:

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

所以这是全新的 url 结构。

【讨论】:

  • 感谢这个答案,Django Packages 现在能够恢复在上次 GitHub API 更改后丢失的一堆提交。谢谢@galuszkak!
  • 我会注意到这不是“相对容易”。文档不清楚这是如何工作的。虽然实现很“容易”,但与编程中的许多挑战一样,确定实现很困难。
  • @pydanny 哪些文档不清楚? GitHub 的 API 文档、请求文档,两者都有?
  • 另外,您并没有真正回答这个问题。他们正在尝试进行比较,您只是在迭代所有提交。我确实相信有区别。
  • 不幸的是,正如@sigmavirus24 所指出的那样,该方法不适用于比较 API。不过谢谢!
【解决方案3】:

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

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

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

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

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

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

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

【讨论】:

    【解决方案4】:

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

    【讨论】:

    • 不幸的是,提交比较 API 似乎只是忽略了 last_sha 参数;有和没有它的输出是相同的。
    • 不起作用,而且last_sha 这些天无论如何都被弃用了。
    【解决方案5】:

    这是一个示例,用于获取使用 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 的限制,可以获得更多.

    【讨论】:

      【解决方案6】:

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

      【讨论】:

        【解决方案7】:

        这是我使用 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;
        }
        

        【讨论】:

          【解决方案8】:

          我对此有一个解决方案,但它不好吃。这相当于自己构建图表。一般的策略是递归地在 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 的祖先,请将其用作二等分点。

          【讨论】:

            【解决方案9】:
            【解决方案10】:

            发件人:https://developer.github.com/v3/repos/commits/#working-with-large-comparisons

            处理大量比较

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

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

            【讨论】:

            • 实际上并没有告诉你怎么做,因为提交列表API的用法肯定不清楚!
            猜你喜欢
            • 1970-01-01
            • 2013-08-10
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-10-26
            • 2022-11-25
            • 1970-01-01
            相关资源
            最近更新 更多