如何从*github.Repository获取文件总数与代码总行数?
解决方案:从go-github的Repository获取文件总数与代码总行数
你说得没错,*github.Repository结构体确实没有直接提供文件总数或代码总行数的字段/方法,下面是几种无需引入额外复杂依赖的替代方案:
方案1:通过GitHub REST API递归遍历仓库内容
使用go-github客户端调用Repositories.GetContents方法,递归遍历仓库的目录树,同时完成文件计数与代码行数统计:
package main import ( "context" "fmt" "strings" "github.com/google/go-github/v40/github" "golang.org/x/oauth2" ) func countFilesAndLines(ctx context.Context, client *github.Client, owner, repo, path string) (int, int, error) { fileCount := 0 lineCount := 0 contents, _, _, err := client.Repositories.GetContents(ctx, owner, repo, path, nil) if err != nil { return 0, 0, err } for _, content := range contents { if content.GetType() == "dir" { // 递归处理子目录 subFiles, subLines, err := countFilesAndLines(ctx, client, owner, repo, content.GetPath()) if err != nil { return 0, 0, err } fileCount += subFiles lineCount += subLines } else if content.GetType() == "file" { fileCount++ // 过滤非代码文件(可根据需求调整后缀) ext := strings.ToLower(strings.TrimPrefix(filepath.Ext(content.GetName()), ".")) if !strings.Contains(".md,.txt,.yml,.yaml,.json,.gitignore", ext) { // 获取文件内容并统计行数 decodedContent, err := content.GetContent() if err != nil { continue // 跳过无法读取的文件 } lineCount += strings.Count(decodedContent, "\n") + 1 // 最后一行可能无换行 } } } return fileCount, lineCount, nil } func main() { ctx := context.Background() ts := oauth2.StaticTokenSource( &oauth2.Token{AccessToken: "YOUR_GITHUB_TOKEN"}, ) tc := oauth2.NewClient(ctx, ts) client := github.NewClient(tc) owner := "your-owner" repo := "your-repo" fileCount, lineCount, err := countFilesAndLines(ctx, client, owner, repo, "") if err != nil { fmt.Printf("Error: %v\n", err) return } fmt.Printf("Total files: %d\nTotal lines: %d\n", fileCount, lineCount) }
注意事项:
- GitHub REST API有速率限制(未认证请求每小时60次,认证后每小时5000次),大仓库需要考虑分页和速率控制
- 可以自定义文件过滤规则,只统计你关心的代码文件类型
- 二进制文件会被自动跳过(
GetContent会返回错误)
方案2:本地克隆仓库后统计(使用go-git)
如果不想受API速率限制,可以用go-git库克隆仓库到本地临时目录,直接遍历文件系统统计:
package main import ( "fmt" "os" "path/filepath" "strings" "github.com/go-git/go-git/v5" ) func countLocalRepoFilesAndLines(repoPath string) (int, int, error) { fileCount := 0 lineCount := 0 err := filepath.Walk(repoPath, func(path string, info os.FileInfo, err error) error { if err != nil { return err } if info.IsDir() { // 跳过.git目录 if info.Name() == ".git" { return filepath.SkipDir } return nil } fileCount++ // 过滤非代码文件 ext := strings.ToLower(filepath.Ext(path)) if strings.Contains(".md,.txt,.yml,.yaml,.json,.gitignore", ext) { return nil } // 读取文件内容统计行数 content, err := os.ReadFile(path) if err != nil { return nil // 跳过无法读取的文件 } lineCount += strings.Count(string(content), "\n") + 1 return nil }) return fileCount, lineCount, err } func main() { repoURL := "https://github.com/your-owner/your-repo.git" tempDir := "./temp-repo" // 克隆仓库 _, err := git.PlainClone(tempDir, false, &git.CloneOptions{ URL: repoURL, }) if err != nil { fmt.Printf("Clone error: %v\n", err) return } defer os.RemoveAll(tempDir) // 清理临时目录 fileCount, lineCount, err := countLocalRepoFilesAndLines(tempDir) if err != nil { fmt.Printf("Count error: %v\n", err) return } fmt.Printf("Total files: %d\nTotal lines: %d\n", fileCount, lineCount) }
优点:
- 不受GitHub API速率限制,统计更准确
- 可以处理超大仓库
缺点:
- 需要磁盘空间存储临时仓库,克隆大仓库耗时较长
可选方案:调用cloc命令(若可接受依赖)
如果不想自己实现统计逻辑,可以用Go的os/exec包直接调用cloc命令:
package main import ( "fmt" "os/exec" ) func main() { cmd := exec.Command("cloc", "./your-repo-path") output, err := cmd.CombinedOutput() if err != nil { fmt.Printf("Error running cloc: %v\n", err) return } fmt.Println(string(output)) }
但正如你所说,这需要在环境中安装cloc,引入了外部依赖,需要额外维护。
内容的提问来源于stack exchange,提问作者Hemant Bhargava
相关产品推荐
相关产品推荐

