
本文详解如何使用 github rest api 和 go-github 客户端在 go 服务中完整获取用户的全部仓库(含私有库),重点解决因分页限制导致部分仓库遗漏的问题,并提供可直接复用的分页遍历实现。
本文详解如何使用 github rest api 和 go-github 客户端在 go 服务中完整获取用户的全部仓库(含私有库),重点解决因分页限制导致部分仓库遗漏的问题,并提供可直接复用的分页遍历实现。
GitHub API 默认对列表接口(如 /user/repos)启用分页机制,每次请求最多返回 30 或 100 条记录(取决于 PerPage 参数设置),不会自动返回全部仓库——这是导致“部分仓库未被获取”的根本原因。即使已正确配置 OAuth token 并拥有 repo 权限(可读私有库),若未手动处理分页,仅调用一次 RepositoriesService.List() 将仅返回第一页结果。
正确做法:循环分页获取全部仓库
go-github 库中,所有列表方法(如 client.Repositories.List(ctx, "", opts))均接受 github.ListOptions 类型参数,其包含两个关键字段:
- PerPage:单页最大条数(推荐设为 100,上限值);
- Page:当前页码(从 1 开始)。
需持续递增 Page,直到某次响应结果长度小于 PerPage,即表示已到达末页。
以下是生产可用的 Go 实现示例:
import (
"context"
"log"
"github.com/google/go-github/v62/github"
"golang.org/x/oauth2"
)
func getAllUserRepos(ctx context.Context, client *github.Client, token string) ([]*github.Repository, error) {
// 使用 token 创建授权上下文
ts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: token})
oauthClient := oauth2.NewClient(ctx, ts)
client = github.NewClient(oauthClient)
var allRepos []*github.Repository
opt := &github.RepositoryListOptions{
Type: "all", // 确保包含 public + private
PerPage: 100, // 最大每页数量
Page: 1,
}
for {
repos, resp, err := client.Repositories.List(ctx, "", opt)
if err != nil {
return nil, err
}
allRepos = append(allRepos, repos...)
// 检查是否还有下一页
if resp.NextPage == 0 {
break
}
opt.Page = resp.NextPage
}
return allRepos, nil
}✅ 关键要点说明:
- 必须传入空字符串 "" 作为 owner 参数(或使用 client.Repositories.List(ctx, "username", opt) 指定用户名),才能获取当前认证用户的全部仓库;
- Type: "all" 显式声明,确保私有仓库也被包含(默认值为 "owner",但为防兼容性建议显式设置);
- 优先使用 resp.NextPage 判断分页终止条件,比手动计数更健壮(API 可能因权限或过滤返回少于 PerPage 的结果,但仍有后续页);
- 记得在 HTTP 客户端中设置合理超时(如 ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)),避免因大量仓库导致请求挂起。
⚠️ 注意事项:
- 用户 Token 必须具备 repo scope(而非仅 public_repo),否则私有仓库将被静默过滤;
- GitHub 对未认证请求限速为 60 次/小时,OAuth Token 提升至 5000 次/小时,但仍建议添加错误重试与限流保护;
- 若用户仓库数量极多(>1000),注意内存占用,可考虑流式处理或分批入库。
通过上述分页逻辑,即可稳定、完整地拉取用户全部可见仓库,彻底解决“部分仓库缺失”问题。


















