You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从*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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 10:22:38