【问题标题】:Finding the oldest commit in a GitHub repository via the API通过 API 在 GitHub 存储库中查找最旧的提交
【发布时间】:2014-09-26 12:58:47
【问题描述】:

确定何时在 GitHub 存储库中进行初始提交的最有效方法是什么?存储库具有 created_at 属性,但对于包含导入历史记录的存储库,最旧的提交可能要旧得多。

当使用命令行时,这样的事情会起作用:

git rev-list --max-parents=0 HEAD

但是我在 GitHub API 中看不到等效项。

【问题讨论】:

  • 我认为没有办法在恒定数量的 API 请求中实现这一点——目前,没有与您列出的 Git 命令等效的方法。因此,您需要通过提交列表找到最后一页(例如使用二进制搜索),然后获取该页面上的最后一次提交。另外(我很确定你知道这一点),请注意最旧的提交(按时间戳)不需要是最后一个(没有父母)——重写历史记录和手动设置时间戳将允许最旧的提交提交到提交树中的其他位置。

标签: github github-api


【解决方案1】:

使用GraphQL API,有一种解决方法可以在特定分支中获取最旧的提交(初始提交)。

首先获取last commit并返回totalCountendCursor

{
  repository(name: "linux", owner: "torvalds") {
    ref(qualifiedName: "master") {
      target {
        ... on Commit {
          history(first: 1) {
            nodes {
              message
              committedDate
              authoredDate
              oid
              author {
                email
                name
              }
            }
            totalCount
            pageInfo {
              endCursor
            }
          }
        }
      }
    }
  }
}

它为光标和pageInfo 对象返回类似的内容:

"totalCount": 931886,
"pageInfo": {
  "endCursor": "b961f8dc8976c091180839f4483d67b7c2ca2578 0"
}

我没有关于光标字符串格式 b961f8dc8976c091180839f4483d67b7c2ca2578 0 的任何来源,但我已经使用其他一些提交超过 1000 次的存储库进行了测试,它似乎总是格式化为:

<static hash> <incremented_number>

因此,您只需从 totalCount 中减去 2(如果 totalCount 大于 1)并获得最旧的提交(如果您愿意,也可以是初始提交):

{
  repository(name: "linux", owner: "torvalds") {
    ref(qualifiedName: "master") {
      target {
        ... on Commit {
          history(first: 1, after: "b961f8dc8976c091180839f4483d67b7c2ca2578 931884") {
            nodes {
              message
              committedDate
              authoredDate
              oid
              author {
                email
                name
              }
            }
            totalCount
            pageInfo {
              endCursor
            }
          }
        }
      }
    }
  }
}

给出以下输出(Linus Torvalds 的初始提交):

{
  "data": {
    "repository": {
      "ref": {
        "target": {
          "history": {
            "nodes": [
              {
                "message": "Linux-2.6.12-rc2\n\nInitial git repository build. I'm not bothering with the full history,\neven though we have it. We can create a separate \"historical\" git\narchive of that later if we want to, and in the meantime it's about\n3.2GB when imported into git - space that would just make the early\ngit days unnecessarily complicated, when we don't have a lot of good\ninfrastructure for it.\n\nLet it rip!",
                "committedDate": "2005-04-16T22:20:36Z",
                "authoredDate": "2005-04-16T22:20:36Z",
                "oid": "1da177e4c3f41524e886b7f1b8a0c1fc7321cac2",
                "author": {
                  "email": "torvalds@ppc970.osdl.org",
                  "name": "Linus Torvalds"
                }
              }
            ],
            "totalCount": 931886,
            "pageInfo": {
              "endCursor": "b961f8dc8976c091180839f4483d67b7c2ca2578 931885"
            }
          }
        }
      }
    }
  }
}

中的一个简单实现,使用此方法获得第一次提交:

import requests

token = "YOUR_TOKEN"

name = "linux"
owner = "torvalds"
branch = "master"

query = """
query ($name: String!, $owner: String!, $branch: String!){
  repository(name: $name, owner: $owner) {
    ref(qualifiedName: $branch) {
      target {
        ... on Commit {
          history(first: 1, after: %s) {
            nodes {
              message
              committedDate
              authoredDate
              oid
              author {
                email
                name
              }
            }
            totalCount
            pageInfo {
              endCursor
            }
          }
        }
      }
    }
  }
}
"""

def getHistory(cursor):
    r = requests.post("https://api.github.com/graphql",
        headers = {
            "Authorization": f"Bearer {token}"
        },
        json = {
            "query": query % cursor,
            "variables": {
                "name": name,
                "owner": owner,
                "branch": branch
            }
        })
    return r.json()["data"]["repository"]["ref"]["target"]["history"]

#in the first request, cursor is null
history = getHistory("null")
totalCount = history["totalCount"]
if (totalCount > 1):
    cursor = history["pageInfo"]["endCursor"].split(" ")
    cursor[1] = str(totalCount - 2)
    history = getHistory(f"\"{' '.join(cursor)}\"")
    print(history["nodes"][0])
else:
    print("got oldest commit (initial commit)")
    print(history["nodes"][0])

您可以在this post 中找到示例

【讨论】:

    【解决方案2】:

    如果数据已经缓存(在 GitHub 端)并且取决于您的精度要求,这可以在最少两个请求中完成。

    首先检查在创建时间之前是否确实存在提交,方法是对/repos/:owner/:repo/commits 执行GET 并将until 参数设置为创建时间(如VonC 的回答所建议的那样)并限制返回的数量1 次提交(通过 per_page 参数)。

    如果在创建时间之前有提交,则可以调用contributors statistics endpoint (/repos/:owner/:repo/stats/contributors)。每个贡献者的响应都有一个weeks 列表,其中最旧的w 值与最旧的提交在同一周。

    如果您需要精确的时间戳,您可以再次使用提交列表端点,并将 untilsince 设置为最早一周后 7 天的值。

    请注意,统计端点可能会返回一个202,表示统计信息不可用,在这种情况下需要在几秒钟后重试。

    【讨论】:

      【解决方案3】:

      一个建议是使用until 参数列出回购中的提交(参见GitHub api V3 section),设置为回购的创建(例如,加上一天)。

      GET /repos/:owner/:repo/commits
      

      这样,您将列出在创建 repo 时或之前创建的所有提交:这将限制列表,不包括 所有在 repo 创建后创建的提交。

      【讨论】:

      • 我认为这个想法是他们不一定知道哪个提交可能是最旧的,正如 Ivan 指出的那样,最旧的提交可能确实有父母。
      • 感谢您建议首先使用创建日期作为上限做一个提交列表。我最终使用它作为初始过滤器,然后使用统计 API 不必对所有提交进行分页(请参阅我的答案,它在 github.com/mihaip/githop/commit/… 实现)。
      • @MihaiParparita 很好的实现,比我的回答更完整。 +1
      • @MihaiParparita 我假设你将你的 repo 从githop 重命名为retrogitgithub.com/mihaip/retrogit/commit/…
      • @testworks:正确,后来有重命名。
      【解决方案4】:

      页码上的试错,

      https://github.com/fatfreecrm/fat_free_crm/commits/master?page=126

      git 历史记录,例如可能使用 gitk,可以帮助您提高试错效率。

      【讨论】:

      • 问题是关于 GitHub API,您提供的示例 URL 是针对 GitHub 网站的。
      【解决方案5】:

      这不是通过 API,而是在 GitHub.com 上:如果你有最新的提交 SHA 和提交计数,你可以构建 URL 来找到它:

      https://github.com/USER/REPO/commits?after=LAST_COMMIT_SHA+COMMIT_COUNT_MINUS_2
      
      # Example. Commit count in this case was 1573
      https://github.com/sindresorhus/refined-github/commits/master
        ?after=a76ed868a84cd0078d8423999faaba7380b0df1b+1571
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-04-01
        • 2020-11-20
        • 2013-05-13
        • 2018-09-01
        • 1970-01-01
        • 2015-04-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多