Поиск самого старого коммита в репозитории GitHub через API
Каков наиболее эффективный способ определить, когда была сделана первоначальная фиксация в репозитории GitHub? Репозитории имеют created_at
свойство, но для репозиториев, которые содержат импортированную историю, самый старый коммит может быть значительно старше.
При использовании командной строки что-то вроде этого будет работать:
git rev-list --max-parents=0 HEAD
Однако я не вижу эквивалента в GitHub API.
6 ответов
Это можно сделать всего за два запроса, если данные уже кэшированы (на стороне GitHub) и в зависимости от ваших требований к точности.
Сначала проверьте, есть ли на самом деле коммиты до времени создания, выполнив GET
за /repos/:owner/:repo/commits
с until
параметр, установленный на время создания (как предложено в ответе VonC) и ограничивающий число, возвращаемое до 1 коммита (через per_page
параметр).
Если есть коммиты до времени создания, то конечная точка статистики участников (/repos/:owner/:repo/stats/contributors
) может быть вызван. Ответ имеет weeks
список на каждого участника и самый старый w
значение там совпадает с самой старой фиксацией.
Если вам нужна точная временная метка, вы можете снова использовать конечную точку списка коммитов с помощью until
а также since
установите значение 7 дней после самой старой недели.
Обратите внимание, что конечная точка статистики может возвращать 202
указывает на то, что статистика недоступна, и в этом случае требуется повторная попытка через несколько секунд.
Используя GraphQL API, существует обходной путь для получения самой старой фиксации (начальной фиксации) в определенной ветке.
Сначала получите последнюю фиксацию и вернитеtotalCount
и endCursor
:
{
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>
Итак, вы должны просто вычесть 2 из totalCount
(если 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
}
}
}
}
}
}
}
что дает следующий результат (начальная фиксация Линуса Торвальдса):
{
"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"
}
}
}
}
}
}
}
Простая реализация на python для получения первой фиксации с помощью этого метода:
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])
Вы можете найти пример в javascript в этом посте
Одним из предложений будет перечисление коммитов на репо (см. Раздел GitHub api V3), используя until
параметр, задающий создание репо (плюс один день, например).
GET /repos/:owner/:repo/commits
Таким образом, вы бы перечислили все коммиты, созданные во время создания репо или раньше: это ограничит список, исключая все коммиты, созданные после создания репо.
Публикую свое решение, так как все остальные мне не помогли.
Следующий скрипт извлекает список коммитов для данного REPO («владелец/репо»), при необходимости переходит к последней странице и выводит объект JSON последнего (самого старого) коммита.
REPO="owner/repo"
URL="https://api.github.com/repos/$REPO/commits"
H=" -H \"Accept: application/vnd.github+json\" \
-H \"X-GitHub-Api-Version: 2022-11-28\""
response=$(curl -s -L --include $H $URL | awk 'NR > 1')
# Split the output into header and json
header=$(echo "$response" | awk 'BEGIN{RS="\r\n";ORS="\r\n"} /^[a-zA-Z0-9-]+:/')
commits=$(echo "$response" | awk '!/^[a-zA-Z0-9-]+:/')
# If paginated, get last page
if [[ $header == *"link"* ]]; then
# Extract the last page value
link_line=$(echo "$header" | grep -i "^link:")
last_page=$(echo "$link_line" | sed -n 's/.*page=\([0-9]\+\)[^0-9].*rel="last".*/\1/p')
# Get last-page commits
commits=$(curl -s -L $H $URL?page=$last_page)
fi
# Print first commit
echo $commits | jq '.[-1].commit'
Метод проб и ошибок на странице номер,
https://github.com/fatfreecrm/fat_free_crm/commits/master?page=126
История git, возможно, с использованием, например, gitk, поможет повысить эффективность проб и ошибок.
Это происходит не через 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