블로그로 돌아가기
GitHubAPI개발 도구오픈소스

GitHub은 이제 스타 히스토리를 알려주지 않습니다 — 그래서 직접 쌓기로 했습니다

Touchizen·

간단해 보였던 질문

"최근 3개월 동안 스타 1만 개 이상 받은 GitHub 저장소가 있을까?"

한 문장짜리 질문입니다. 그런데 답을 구하려고 보니, 이 질문은 성격이 전혀 다른 두 개의 질문이 겹쳐 있었습니다. 하나는 30초 만에 풀렸고, 다른 하나는 답할 방법이 아예 없었습니다.

GitHub 스타 트래커 — 최근 3개월 내 생성된 저장소 중 스타 1만 개 이상

쉬운 절반: 새로 만들어진 저장소

"최근 3개월 안에 생성된 저장소 중 스타 1만 개 이상"은 GitHub 검색 API 한 줄이면 됩니다.

created:>2026-06-09 stars:>=10000

이 질문의 답은 오늘 기준 24개입니다. 1위는 8월 13일에 만들어져 21만 스타를 넘긴 deepseek-ai/deepseek-harness 고요. 목록은 압도적으로 AI 에이전트·하네스 계열입니다.

여기서 눈여겨볼 만한 사실이 하나 있습니다. 이 검색 API는 인증 없이도 브라우저에서 직접 호출됩니다.

HTTP/2 200
access-control-allow-origin: *
x-ratelimit-limit: 10
x-ratelimit-resource: search

CORS가 열려 있고, 분당 10회 제한은 방문자 IP 기준입니다. 서버를 하나 두고 프록시하면 사이트 전체가 분당 10회를 나눠 쓰지만, 브라우저에서 직접 부르면 방문자마다 각자 10회를 갖습니다. 이 경우엔 백엔드를 두지 않는 쪽이 편법이 아니라 더 나은 설계입니다.

어려운 절반: 이미 있던 저장소가 얼마나 컸는가

문제는 두 번째 해석입니다. "생성 시점과 무관하게, 최근 3개월 동안 스타가 1만 개 늘어난 저장소"—이건 검색 API로 안 나옵니다. GitHub 검색은 현재 스타 수만 알고, 3개월 전 스타 수는 모릅니다.

예전에는 우회로가 있었습니다. stargazers 엔드포인트에 특별한 Accept 헤더를 붙이면 누가 언제 스타를 눌렀는지 타임스탬프가 나왔고, 마지막 페이지부터 이진 탐색으로 경계를 찾으면 기간별 증가량을 계산할 수 있었습니다.

지금은 이렇습니다.

GET /repos/facebook/react/stargazers
Accept: application/vnd.github.star+json

HTTP/2 404

facebook/react 입니다. 오타도, 권한 문제도 아닙니다. 몇 가지를 더 찔러보면 패턴이 보입니다.

엔드포인트 응답
/repos/{o}/{r}/stargazers 404
/repos/{o}/{r}/subscribers 404
/repos/{o}/{r}/forks 200
/repos/{o}/{r}/contributors 200
/user/starred (본인) 200 (starred_at 포함)

포크와 컨트리뷰터는 멀쩡하고, 내가 누른 스타도 볼 수 있습니다. "남의 저장소를 누가 스타·워치했는지" 계열만 내려갔습니다. 프라이버시 관점에서는 납득이 가는 변경이지만, 스타 히스토리를 계산하던 모든 도구의 토대가 함께 사라졌습니다.

두 번째 우회로도 말랐습니다

그다음 후보는 공개 이벤트 피드입니다. GitHub의 퍼블릭 이벤트 스트림에서 WatchEvent 하나가 스타 하나이고, GH Archive는 이걸 시간 단위로 아카이빙합니다. 기간별 증가량 랭킹을 만들던 서비스들은 대부분 여기에 기대고 있었습니다.

같은 시각(0시) 한 시간치 파일을 직접 받아서 세어 봤습니다.

날짜 전체 이벤트 WatchEvent (스타)
2025-06-09 137,566 4,394
2026-06-09 156,305 730
2026-09-08 83,301 213

1년 만에 5% 수준으로, 지금은 1% 아래로 떨어졌습니다. 전체 이벤트 수는 크게 줄지 않았는데 스타 이벤트만 사라졌다는 점이 핵심입니다.

이 데이터로 랭킹을 만들던 OSSInsight의 API는 아예 이렇게 답합니다.

{
  "status": "unavailable",
  "unavailable_since": "2026-03-01",
  "reason": "our capture of those events fell to roughly 0.3% of baseline,
             so the ordering would be noise"
}

결론: 과거는 아무도 돌려주지 않습니다

정리하면 이렇습니다. 지나간 기간의 스타 증가량은 지금 어떤 방법으로도 소급해서 구할 수 없습니다. 남은 방법은 하나뿐입니다 — 오늘부터 직접 기록하는 것.

그리고 이 사실에는 미루면 손해라는 성질이 있습니다. 하루 미루면 히스토리가 하루 늦어지고, 지나간 날은 영원히 채울 수 없습니다.

그래서 만들었습니다.

GitHub 스타 트래커

무료이고, 로그인이 없고, 계정도 토큰도 필요 없습니다.

신규 저장소 탭은 실시간입니다. 기간(1·3·6·12개월)과 최소 스타 수를 고르고 버튼을 누르면 브라우저가 GitHub 검색 API를 직접 호출합니다. 같은 조건을 다시 물으면 10분간 캐시에서 답하므로, 버튼을 연타해도 분당 10회 제한에 걸리지 않습니다.

급상승 탭은 매일 한 번 수집하는 스냅샷으로 계산합니다. 신생 저장소(1년 내 생성, 스타 1,000 이상)와 기존 대형 저장소(스타 2만 이상) 약 1,900개의 스타 수를 매일 기록하고, 7·30·90일 증가량을 순위로 보여줍니다.

설계에서 두 가지

정직한 구간. 수집을 오늘 시작했으니 내일은 하루치, 다음 주에는 일주일치밖에 없습니다. 이때 "최근 90일" 탭이 9일치 데이터로 계산한 순위를 90일 결과인 척 보여주면 그건 거짓말입니다. 그래서 각 구간은 자기가 실제로 몇 일치에 기반하는지를 함께 들고 다니고, 부족하면 화면에 그렇게 씁니다. 수집 중에 새로 들어온 저장소도 "이 구간 도중 편입되어 증가량은 최대값 기준"이라고 표시합니다.

배포와 데이터의 분리. 수집기는 GitHub Actions에서 매일 돌고 결과를 저장소에 커밋합니다. 그런데 Actions의 기본 토큰으로 만든 커밋은 다른 워크플로를 깨우지 않습니다. 즉 데이터가 커밋돼도 사이트가 다시 빌드되지 않습니다.

이 제약은 우회하는 대신 이용했습니다. 페이지가 배포된 사이트 대신 raw.githubusercontent.com에서 데이터를 직접 읽습니다. CORS가 열려 있고 5분 캐시가 걸려 있어서, 수집 커밋이 재배포 없이 5분 안에 반영됩니다. 데이터 파이프라인과 사이트 배포가 완전히 분리되고, 사이트를 매일 다시 빌드할 이유도 사라집니다.

지금 상태

첫 스냅샷은 저장소 1,913개, 60KB로 오늘 들어갔습니다. 그래서 오늘 급상승 탭은 비어 있습니다 — 비교 대상이 없으니까요. 내일 두 번째 스냅샷이 들어오면 7일 구간부터 값이 나오고, 90일 구간은 12월에 채워집니다.

지금 사용해 보기 →