🌷🍁 博主猫头虎 带您 Go to New World.✨🍁
🦄 博客首页——猫头虎的博客🎐
🐳《面试题大全专栏》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺
🌊 《IDEA开发秘籍专栏》学会IDEA常用操作,工作效率翻倍~💐
🌊 《100天精通Golang(基础入门篇)》学会Golang语言,畅玩云原生,走遍大小厂~💐
🪁🍁 希望本文能够给您带来一定的帮助🌸文章粗浅,敬请批评指正!🍁🐥
使用Git命令统计代码提交情况:全面解析与多语言实现 🚀
🐯 摘要:你好,我是猫头虎博主!最近在搜索引擎上发现,关于"如何使用Git命令统计代码提交情况"的搜索量暴涨。很多小伙伴都希望通过Git深入了解他们的代码统计数据。因此,我决定写一篇文章,不仅使用传统的bash脚本方式,还会用Java、Python、Go三种热门编程语言来实现。让我们开始吧!
🌟 引言
Git是每个开发者的好帮手。但是,除了基本的提交和克隆,你真的了解Git的深层功能吗?本文将带你深入了解如何使用Git命令和多种编程语言统计代码提交情况。
🚀 正文
1. Git命令行工具的深度探索
Git命令行工具不仅可以用于代码的提交、拉取和推送,还提供了许多其他功能,如查看提交历史、比较版本差异等。其中,git log
命令就可以帮助我们统计代码提交情况。
1.2. 使用Git命令统计提交情况
1.2.1 统计提交次数
通过git shortlog
命令,我们可以轻松统计每个人的提交次数:
git shortlog -s -n
1.2.2 统计新增和删除行数
要统计每个人的新增和删除行数,我们可以使用以下命令:
git log --numstat --pretty="%aN" | awk 'NF==3 {plus+=$1; minus+=$2} END {printf("新增行数: %d, 删除行数: %d\n", plus, minus)}'
1.1 基于bash的统计脚本
首先,我们使用bash脚本来实现代码统计功能。
#!/bin/bash echo "统计代码提交情况:" # 获取所有贡献者列表 authors=$(git log --format='%aN' | sort -u) for author in $authors; do echo "----------------------------------------" echo "作者:$author" # 统计提交次数 commit_count=$(git shortlog -s -n --author="$author" | awk '{print $1}') echo "提交次数:$commit_count" # 统计新增和删除行数 line_stat=$(git log --numstat --pretty="%aN" --author="$author" | awk 'NF==3 {plus+=$1; minus+=$2} END {printf("%d %d", plus, minus)}') IFS=' ' read -ra stats <<< "$line_stat" echo "新增行数:${stats[0]}" echo "删除行数:${stats[1]}" done
这个脚本首先获取所有的贡献者列表,然后对每个贡献者分别统计他们的提交次数、新增行数和删除行数。
你可以将这个脚本保存为git_stats.sh,然后在项目目录中运行它来获取统计信息。确保你的脚本有执行权限(你可以使用chmod +x git_stats.sh来给它添加执行权限)。
2. Java实现统计功能
Java提供了ProcessBuilder
来帮助我们执行和控制进程。我们可以利用这个特性来运行Git命令,并解析输出。
以下是一个简单的Java实现思路:
使用ProcessBuilder调用Git命令:Java可以通过ProcessBuilder类来执行外部命令。你可以用它来运行Git命令,获取提交日志。
解析Git日志:git log命令可以输出提交日志,你可以结合–pretty=format:选项来自定义日志格式,便于后续解析。
统计信息:解析Git日志后,你可以统计每个人的提交次数、新增行数、删除行数等信息。
以下是一个简化的示例:
import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.HashMap; import java.util.Map; public class GitStats { public static void main(String[] args) throws Exception { String repoPath = "/path/to/your/repo"; // 项目目录 String since = "2023-01-01"; // 开始时间 String until = "2023-12-31"; // 结束时间 ProcessBuilder processBuilder = new ProcessBuilder( "git", "log", "--since=" + since, "--until=" + until, "--shortstat", "--pretty=format:%aN" ); processBuilder.directory(new java.io.File(repoPath)); Process process = processBuilder.start(); BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); Map<String, Integer> commitsCount = new HashMap<>(); Map<String, Integer> insertionsCount = new HashMap<>(); Map<String, Integer> deletionsCount = new HashMap<>(); String line; String currentAuthor = null; while ((line = reader.readLine()) != null) { if (!line.isEmpty()) { if (!line.startsWith(" ")) { currentAuthor = line; commitsCount.put(currentAuthor, commitsCount.getOrDefault(currentAuthor, 0) + 1); } else { String[] stats = line.trim().split(","); for (String stat : stats) { stat = stat.trim(); if (stat.endsWith("insertions(+)")) { int count = Integer.parseInt(stat.split(" ")[0]); insertionsCount.put(currentAuthor, insertionsCount.getOrDefault(currentAuthor, 0) + count); } else if (stat.endsWith("deletions(-)")) { int count = Integer.parseInt(stat.split(" ")[0]); deletionsCount.put(currentAuthor, deletionsCount.getOrDefault(currentAuthor, 0) + count); } } } } } for (String author : commitsCount.keySet()) { System.out.println("Author: " + author); System.out.println("Commits: " + commitsCount.get(author)); System.out.println("Insertions: " + insertionsCount.getOrDefault(author, 0)); System.out.println("Deletions: " + deletionsCount.getOrDefault(author, 0)); System.out.println("-------------"); } } }
2.1 JGit 代码管理仓库特别案例
JGit 是一个轻量级的、完全用 Java 编写的 Git 库。它是 Eclipse 项目的一部分,用于为 Java 开发者提供一个本地的 Git 实现。JGit 提供了一套 API,允许开发者在 Java 代码中直接与 Git 仓库进行交互,而不需要依赖命令行的 Git。
使用 JGit,你可以轻松地从 Java 程序中访问和操作 Git 仓库。以下是一个简单的示例,该示例展示了如何使用 JGit 统计给定日期范围内的代码提交情况:
import org.eclipse.jgit.api.Git; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.storage.file.FileRepositoryBuilder; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.diff.DiffFormatter; import org.eclipse.jgit.diff.DiffEntry; import org.eclipse.jgit.util.io.DisabledOutputStream; import java.io.File; import java.util.HashMap; import java.util.List; import java.util.Map; public class GitStats { public static void main(String[] args) throws Exception { File repoDir = new File("/path/to/your/git/repo/.git"); // 替换为你的 Git 仓库路径 Repository repo = new FileRepositoryBuilder().setGitDir(repoDir).build(); Map<String, UserStats> statsMap = new HashMap<>(); try (Git git = new Git(repo) ) { Iterable<RevCommit> commits = git.log().call(); for (RevCommit commit : commits) { if (commit.getAuthorIdent().getWhen().after(/* your start date */) && commit.getAuthorIdent().getWhen().before(/* your end date */)) { String author = commit.getAuthorIdent().getName(); UserStats userStats = statsMap.getOrDefault(author, new UserStats()); userStats.commitCount++; try (DiffFormatter diffFormatter = new DiffFormatter(DisabledOutputStream.INSTANCE)) { diffFormatter.setRepository(repo); List<DiffEntry> diffs = diffFormatter.scan(commit.getParent(0), commit); for (DiffEntry diff : diffs) { userStats.addedLines += diff.getInsertions(); userStats.deletedLines += diff.getDeletions(); } } statsMap.put(author, userStats); } } } for (Map.Entry<String, UserStats> entry : statsMap.entrySet()) { System.out.println("Author: " + entry.getKey()); System.out.println("Commits: " + entry.getValue().commitCount); System.out.println("Added lines: " + entry.getValue().addedLines); System.out.println("Deleted lines: " + entry.getValue().deletedLines); } } static class UserStats { int commitCount; int addedLines; int deletedLines; } }
注意:
- 替换
/path/to/your/git/repo/.git
为你的 Git 仓库的路径。 - 设置你的开始和结束日期在
commit.getAuthorIdent().getWhen().after(/* your start date */)
和commit.getAuthorIdent().getWhen().before(/* your end date */)
。
这个脚本统计了在指定日期范围内每个作者的提交次数,新增行数和删除行数。你可以根据需要进行进一步的修改和优化。
2.2 GitLab 仓库
要获取 GitLab 上指定日期范围内每个作者的提交次数、新增行数和删除行数,你需要首先获取每个提交的详细信息,然后解析每个提交的差异以获取新增和删除的行数。
下面是一个示例,使用 Java 和 GitLab API 来获取这些统计信息:
import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; import org.json.JSONArray; import org.json.JSONObject; import java.util.HashMap; import java.util.Map; public class GitLabDetailedStats { private static final String GITLAB_URL = "https://gitlab.example.com"; private static final String PRIVATE_TOKEN = "YOUR_PRIVATE_TOKEN"; public static void main(String[] args) throws Exception { String projectId = "your_project_id"; // 替换为你的项目 ID String sinceDate = "2023-01-01"; // 开始日期 String untilDate = "2023-12-31"; // 结束日期 Map<String, UserStats> statsMap = new HashMap<>(); try (CloseableHttpClient httpClient = HttpClients.createDefault()) { HttpGet commitsRequest = new HttpGet(GITLAB_URL + "/api/v4/projects/" + projectId + "/repository/commits?since=" + sinceDate + "&until=" + untilDate); commitsRequest.setHeader("PRIVATE-TOKEN", PRIVATE_TOKEN); try (CloseableHttpResponse response = httpClient.execute(commitsRequest)) { String responseBody = EntityUtils.toString(response.getEntity()); JSONArray commitsArray = new JSONArray(responseBody); for (int i = 0; i < commitsArray.length(); i++) { JSONObject commit = commitsArray.getJSONObject(i); String commitId = commit.getString("id"); String authorName = commit.getJSONObject("author").getString("name"); UserStats userStats = statsMap.getOrDefault(authorName, new UserStats()); HttpGet diffRequest = new HttpGet(GITLAB_URL + "/api/v4/projects/" + projectId + "/repository/commits/" + commitId + "/diff"); diffRequest.setHeader("PRIVATE-TOKEN", PRIVATE_TOKEN); try (CloseableHttpResponse diffResponse = httpClient.execute(diffRequest)) { String diffResponseString = EntityUtils.toString(diffResponse.getEntity()); JSONArray diffArray = new JSONArray(diffResponseString); for (int j = 0; j < diffArray.length(); j++) { JSONObject diff = diffArray.getJSONObject(j); userStats.addedLines += diff.getInt("additions"); userStats.deletedLines += diff.getInt("deletions"); } } userStats.commitCount++; statsMap.put(authorName, userStats); } } } for (Map.Entry<String, UserStats> entry : statsMap.entrySet()) { System.out.println("Author: " + entry.getKey()); System.out.println("Commits: " + entry.getValue().commitCount); System.out.println("Added lines: " + entry.getValue().addedLines); System.out.println("Deleted lines: " + entry.getValue().deletedLines); } } static class UserStats { int commitCount; int addedLines; int deletedLines; } }
注意:
- 替换
GITLAB_URL
、PRIVATE_TOKEN
和其他相关配置为你的实际值。- 这个脚本可能会发出大量的 HTTP 请求,特别是当你有很多提交时。为了避免 GitLab API 的速率限制,你可能需要在请求之间添加适当的延迟或考虑其他优化策略。
3. Python实现
Python也可以轻松地调用子进程。我们可以使用subprocess
模块来实现。
以下是使用Python实现统计Git代码提交情况的完整代码:
import subprocess def git_stats(repo_path): # 获取所有贡献者 cmd_authors = ["git", "log", "--format='%aN'", "--no-merges"] authors_output = subprocess.Popen(cmd_authors, cwd=repo_path, stdout=subprocess.PIPE).communicate()[0].decode() unique_authors = set(authors_output.splitlines()) stats = {} for author in unique_authors: # 统计每个贡献者的提交次数 cmd_commits = ["git", "shortlog", "-s", "-n", "--author=" + author] commits_output = subprocess.Popen(cmd_commits, cwd=repo_path, stdout=subprocess.PIPE).communicate()[0].decode() commit_count = int(commits_output.strip().split()[0]) # 统计每个贡献者的新增和删除行数 cmd_lines = ["git", "log", "--numstat", "--author=" + author, "--pretty=tformat:", "--no-merges"] lines_output = subprocess.Popen(cmd_lines, cwd=repo_path, stdout=subprocess.PIPE).communicate()[0].decode() added, deleted = 0, 0 for line in lines_output.splitlines(): if '\t' in line: a, d, _ = line.split('\t') added += int(a) deleted += int(d) stats[author] = {"commits": commit_count, "added": added, "deleted": deleted} return stats if __name__ == "__main__": repo = "/path/to/repo" # 修改为你的仓库路径 statistics = git_stats(repo) for author, data in statistics.items(): print(f"Author: {author}") print(f"Commits: {data['commits']}") print(f"Added lines: {data['added']}") print(f"Deleted lines: {data['deleted']}") print("-------------------------")
这段代码首先会获取仓库中所有的贡献者,然后对每个贡献者分别统计他们的提交次数、新增行数和删除行数。
为了运行这段代码,你需要确保你的Python环境已经设置好,并且你的机器上已经安装了Git命令行工具。
4. Go语言实现
Go语言也提供了调用子进程的功能,我们可以使用os/exec
包来实现。
demo:
package main import ( "os/exec" "fmt" ) func GitStats(repoPath string) { cmd := exec.Command("git", "shortlog", "-s", "-n") cmd.Dir = repoPath out, err := cmd.Output() if err != nil { fmt.Println(err) return } fmt.Println(string(out)) } func main() { GitStats("/path/to/repo") }
以下是使用Go语言实现统计Git代码提交情况的完整代码:
package main import ( "os/exec" "fmt" "strings" ) func GitStats(repoPath string) { // 获取所有贡献者 cmdAuthors := exec.Command("git", "log", "--format=%aN", "--no-merges") cmdAuthors.Dir = repoPath authorsOutput, err := cmdAuthors.Output() if err != nil { fmt.Println(err) return } uniqueAuthors := removeDuplicates(strings.Split(string(authorsOutput), "\n")) stats := make(map[string]map[string]int) for _, author := range uniqueAuthors { // 统计每个贡献者的提交次数 cmdCommits := exec.Command("git", "shortlog", "-s", "-n", "--author=" + author) cmdCommits.Dir = repoPath commitsOutput, err := cmdCommits.Output() if err != nil { fmt.Println(err) return } commitCount, _ := strconv.Atoi(strings.TrimSpace(strings.Split(string(commitsOutput), "\t")[0])) // 统计每个贡献者的新增和删除行数 cmdLines := exec.Command("git", "log", "--numstat", "--author=" + author, "--pretty=tformat:", "--no-merges") cmdLines.Dir = repoPath linesOutput, err := cmdLines.Output() if err != nil { fmt.Println(err) return } added, deleted := 0, 0 for _, line := range strings.Split(string(linesOutput), "\n") { if strings.Contains(line, "\t") { parts := strings.Split(line, "\t") add, _ := strconv.Atoi(parts[0]) del, _ := strconv.Atoi(parts[1]) added += add deleted += del } } stats[author] = map[string]int{"commits": commitCount, "added": added, "deleted": deleted} } for author, data := range stats { fmt.Println("Author:", author) fmt.Println("Commits:", data["commits"]) fmt.Println("Added lines:", data["added"]) fmt.Println("Deleted lines:", data["deleted"]) fmt.Println("-------------------------") } } func removeDuplicates(elements []string) []string { encountered := map[string]bool{} result := []string{} for v := range elements { if encountered[elements[v]] == true { } else { encountered[elements[v]] = true result = append(result, elements[v]) } } return result } func main() { GitStats("/path/to/repo") }
这段Go代码首先获取仓库中所有的贡献者,然后对每个贡献者分别统计他们的提交次数、新增行数和删除行数。你可以将这段代码保存为git_stats.go
,然后使用go run git_stats.go
命令运行它。确保你已经设置好Go环境并安装了Git命令行工具。
🔥 总结
不同的编程语言提供了各自的方法来调用子进程,这使得我们可以灵活地使用Git命令来统计代码提交情况。无论你是bash、Java、Python还是Go开发者,都可以根据自己的需求选择合适的方法。
📚 参考资料
感谢大家阅读,如果有任何问题或建议,欢迎留言交流!🐱🐅🚀🌟🔥📚
原创声明
======= ·
- 原创作者: 猫头虎
作者wx: [ libin9iOak ]
学习 | 复习 |
✔ |
本文为原创文章,版权归作者所有。未经许可,禁止转载、复制或引用。
作者保证信息真实可靠,但不对准确性和完整性承担责任。
未经许可,禁止商业用途。
如有疑问或建议,请联系作者。
感谢您的支持与尊重。
点击
下方名片
,加入IT技术核心学习团队。一起探索科技的未来,共同成长。