
我先把结论放在最前面IDEA自带的Git集成可以看提交记录、看某个文件的历史、甚至看每一行是谁写的但你要让它直接生成一份“组内成员代码行数排名表”它做不到。真正的快速方案是切到Git命令行用git log加一段统计脚本几秒钟就能输出一张按人汇总的排名表。这篇文章的适用对象很明确马上要做迭代汇报、想盘点个人贡献、被领导要求统计团队提交情况的开发同学。不需要你额外安装什么重量级工具一个IDEA、一个Git环境再加上下面这段命令就够了。我会把统计口径、常用命令、可复用的脚本、以及我实际踩过的坑一起讲清楚。1. 先搞明白你到底想统计什么1.1 一个迭代汇报引发的需求场景往往是这样迭代结束产品或项目负责人问“这个迭代每个人写了多少行代码”或者你想看看自己这个版本提交了多少工作量。打开IDEA的Git Log能看到一条条提交记录每个提交后面有x -y的增删行数但要看“汇总”、看“排名”完全没有。我见过不少同学遇到这个需求后的第一反应是“写个爬虫从网页版仓库抓数据”或者是去IDEA插件市场找一个现成插件。其实这个需求最合适的解法就是Git命令行本身因为它有--numstat、--shortstat这类参数天生支持统计增删行数只是默认不会按人聚合。我们要做的就是把Git输出的原始数据清洗成“作者行数”的排名表。1.2 统计口径决定了结果会不会被吐槽开始写命令之前一定要先想清楚口径否则统计出来的数字拿到会上很容易被质疑。最常见的三个口径差异新增行数指统计周期内每个提交里号开头的行数总和。它反映的是“写了多少新代码”。删除行数指-号开头的行数总和。重构代码、删除过期逻辑时这个数字会明显偏高。净增行数等于新增行数减删除行数。净增为负不代表没干活可能是把一段几百行的重复代码抽成公共方法这是典型的“行数下降但工作量很大”的情况。另外还有一个维度是提交次数。有些人的工作是把一个大需求拆成十几个小提交有些人习惯写完再一次性提交。只看行数容易忽略这种习惯差异配合提交次数看会更全面。我建议的统计口径是按作者统计新增行数、删除行数、净增行数、改动总量新增删除和提交次数不要只给一个净增数字。这样既能看到谁写了大量新代码也能看到谁在做重构和清理信息量更完整也更有说服力。注意统计前先和团队口头确认“周期”和“是否包含合并提交”这两个参数影响最大后面会详细说。2. IDEA 自带功能能做到什么程度查提交可以排名的确不行2.1 Git Log 面板的正确用法IDEA的版本控制面板其实不弱。按Alt9可以打开 Git 面板切到 Log 标签页能看到当前分支的提交历史。右上角有过滤条件可以按作者名过滤也可以按日期、分支筛选。点击某个提交下方会列出这次提交涉及的文件双击文件可以看到具体的 diff 内容。这些能力非常适合以下几个场景查某个文件某段代码是什么时候、被谁的提交改坏的对比两个提交之间发生了什么变化通过 Commit 右侧的x -y快速判断一次提交的规模。但是IDEA 原生定位是“浏览和检索”不是“聚合分析”。它不会帮你把所有提交按作者累加行数也没有“按新增行数排序”的入口。迭代要做排名靠手工翻 Log 简直是一场灾难——几十个提交翻下来统计结果还不一定对。2.2 为什么 IDEA 原生定位不适合做报表汇总原因不复杂IDEA 的提交历史面板是给开发者看“发生了什么”的不是给管理者看“谁贡献了多少”的。它做了blame这类按行标注提交者的功能在编辑器左侧右键选择 Annotate可以看到每一行代码最后一次是谁改的但迟迟不做按提交者的汇总统计说明它的设计重心在代码协作本身。如果你只有 IDEA确实可以通过“在 Log 面板搜索每个成员的名字然后手动把每个提交的 x -y 记下来”来统计。但这只适合提交次数很少的场景只要提交一多手动统计就会漏算或算重。我不是说要放弃 IDEA恰恰相反IDEA 的价值在于定位提交、排查问题统计排名的环节应该交给更底层的 Git 命令。2.3 临时替代方案用 Diff 窗口快速估算版本间差异如果你只是想快速知道“这周代码量整体是增加还是减少”不需要按人排名可以选中两个提交或两个 tag右键选择 Compare Versions。IDEA 会弹出一个差异窗口展示两个版本之间所有文件的变化清单。虽然它不会直接给出行数汇总但配合 Git 命令行一行git diff --shortstat A..B就能得到两个版本之间的增删行数总额。这个方法适合临时估算不适合作为正式统计依据。因为跨版本对比会包含合并提交带来的重复计数也会把版本之间的所有改动不论是谁改的混在一起。3. Git 命令行统计最可靠也最可控3.1 最基础的 git log --shortstat 与输出解析Git 自带的统计能力其实很强。先看第一条最基础的命令git log --shortstat输出大概是这样的commit 3f5c92e1a6f9b1c7d8e2a3b4c5d6e7f8a9b0c1d2 Author: Zhang San zhangsanexample.com Date: Mon Jan 13 10:30:22 2025 0800 feat: 优化用户模块查询逻辑 3 files changed, 45 insertions(), 12 deletions(-)--shortstat会在每次提交下面附加一行“x files changed, xx insertions(), xx deletions(-)”。如果只看单次提交这个信息够用了。但要注意默认情况下它会包含合并提交而合并提交的增删行数会把被合并分支的全部改动重复计算一次数据会虚高。这就是为什么后面的命令都要加--no-merges。--shortstat的问题在于它不能直接在输出里带上作者必须结合--format才能关联到人。更优雅的方案是用--numstat它会把每次提交的文件变更输出成“新增行数、删除行数、文件名”三列非常适合脚本处理。3.2 统计单人的增删行数命令模板只看某一个人的贡献时--author参数就够了git log --authorzhangsan --since2025-01-01 --until2025-02-01 --no-merges --shortstat --prettyformat:把--prettyformat:清空提交信息后输出里就只剩一堆“x files changed”这样的统计行每行代表一次提交。把这些行汇总就是该成员的总改动量。如果改用--numstat还可以进一步累加新增和删除行数git log --authorzhangsan --since2025-01-01 --until2025-02-01 --no-merges --numstat --prettyformat:输出长这样45 12 src/main/java/com/example/UserService.java 3 1 src/main/java/com/example/UserController.java第一列是新增行数第二列是删除行数第三列是文件名。如果文件是二进制文件会有两列-处理脚本时要过滤掉否则累加时会报错。重命名文件也有特殊格式rename from ...和rename to ...同样要处理。3.3 彻底搞懂 numstat为什么它能作为统计基础--numstat之所以好用是因为它输出的数据是机器可读的每一行都是严格的“数字、数字、文件名”格式。和--shortstat相比它多了文件名粒度可以让你按目录、按文件类型过滤。比如想排除package-lock.json这类生成文件或者排除dist/、target/目录都能在脚本里精确处理。转义字符也值得注意如果文件名里有空格--numstat会输出一个\t分隔的三列如果文件名本身含有制表符Git 会把制表符转义成\t正常情况下不会影响按列拆分。所以--numstat是整个统计方案的基石先用它拿到细粒度的行数数据再用awk按作者累加最后输出排名。3.4 按人累计排名核心命令与原理拆解要对所有人做排名最简单的思路是把每次提交的作者名字作为标记行输出后面紧跟着这个提交的--numstat数据然后用awk做累加。关键命令是这个git log --since2025-01-01 --until2025-02-01 --no-merges --prettyformat:%an --numstat--prettyformat:%an是让每次提交先输出一行作者名紧接着输出这个提交的--numstat明细。awk脚本遇到开头就切换当前作者后面每满三列就累加到当前作者名下。这里解释一下为什么用这个前缀因为--prettyformat:全清空的话无法在awk里知道当前统计的是哪个作者。加一个特定前缀是为了让awk能识别“提交开始”的标志。你也可以用别的字符串只要不会和真实作者名冲突就行。4. 一条命令搞定全组排名可直接复用的脚本4.1 完整脚本与逐行解读下面这段是我在项目里实际用过的统计脚本直接复制到 Git Bash 或 Linux/macOS 终端就能跑#!/bin/bash SINCE${1:-$(date %Y-%m-%d -d 30 days ago)} UNTIL${2:-$(date %Y-%m-%d)} BRANCH${3:-HEAD} git log --since$SINCE --until$UNTIL --no-merges \ --prettyformat:%an --numstat $BRANCH \ | awk /^/ { author substr($0, 5) commits[author] if (!seen[author]) { seen[author] 1 order[n] author } next } NF 3 $1 ! - $2 ! - { added[author] $1 deleted[author] $2 } END { for (i 1; i n; i) { a order[i] printf %s\t%d\t%d\t%d\t%d\t%d\n, a, commits[a], added[a], deleted[a], added[a] - deleted[a], added[a] deleted[a] } } | sort -t $\t -k6 -nr -k2 -nr默认参数是最近 30 天也可以手动指定时间段./code-rank.sh 2025-01-01 2025-03-01 feature-xxx脚本会输出 6 列作者、提交次数、新增行数、删除行数、净增行数、改动总量按改动总量降序排列。如果只想看某个分支的提交第三个参数传分支名就行不传默认是当前分支HEAD。注意几个细节macOS 的date参数不兼容上面脚本里-d 30 days ago是 GNU 扩展macOS 要用date -v-30d %Y-%m-%d否则会报错。Windows 环境建议在 Git Bash 里运行而不是在 cmd 或 PowerShell 里直接跑 bash 脚本。提交次数统计脚本会在行累加次数这样即使某个提交全部是二进制文件变更或重命名提交次数也不会被漏掉新增删除行数则保持 0。4.2 扩展一输出 CSV方便导入 Excel 做图表脚本默认输出制表符分隔格式直接复制到 Excel 或 Numbers 里就能自动分列。如果希望生成真正的 CSV 文件把printf里的分隔符改成逗号即可printf %s,%d,%d,%d,%d,%d\n, a, commits[a], added[a], deleted[a], added[a] - deleted[a], added[a] deleted[a]然后把命令最后重定向到文件./code-rank.sh code-rank.csv这样你就可以在 Excel 里生成柱状图、趋势图更直观地展示结果。4.3 扩展二按周/月度自动统计的思路如果你每个迭代都要做一次排名可以把脚本包装成固定任务。我的做法是配合crontab每周一凌晨跑一次把结果输出到一个约定目录0 1 * * 1 /home/user/bin/code-rank.sh $(date -d last monday %Y-%m-%d) $(date %Y-%m-%d) /home/user/logs/code-rank-weekly.txt在持续集成环境里也可以把脚本挂在 Jenkins 或 GitLab CI 上定时跑完以后推送结果到群机器人。这样不仅能省去手工统计数据的时间还能保证每次统计口径一致。5. 插件方案实测GitLocalStats 到底好不好用5.1 安装与入口如果你不想碰命令行IDEA 插件市场里有一个社区插件叫 GitLocalStats可以在Settings - Plugins - Marketplace搜索下载IDEA 官网的插件仓库也能找到它。安装后重启 IDE然后通过右上角或右侧工具栏找到 GitLocalStats 窗口。它的核心功能是分析当前 Git 仓库的提交历史按作者展示提交次数、新增行数、删除行数和时间分布还带一些图表。对不熟悉 Git 命令的同学来说界面化确实更友好点几下鼠标就能得到结果。5.2 统计结果的视觉呈现与实际限制GitLocalStats 打开后有作者列表选中某个作者可以看到他的提交历史、日期热力图、变更行数曲线。整体视觉效果比命令行好适合临时看一下趋势。但实测下来有几个限制大仓库首次分析很慢它会扫描整个 Git 历史构建统计信息仓库提交多的时候可能要等很久期间 IDEA 还会卡顿。统计口径不够灵活默认会把合并提交也算进去虽然部分版本有过滤选项但不如命令行脚本那么容易控制。兼容性风险插件依赖 IDEA 内部 APIIDEA 升级后插件可能暂时失效我遇到过两次大版本升级后需要等插件更新的情况。交互式使用为主它适合“看一眼”但对输出格式、筛选目录、跨仓库报表这些需求支持不足。5.3 什么时候选插件、什么时候选脚本我的建议是分场景只想快速看看某人或某团队大概写了多少不想折腾命令行用 GitLocalStats。需要给别人交表、需要固定口径、需要排除合并提交和生成目录、需要生成 CSV 或接入自动化流程用命令行脚本。团队内部有 GitLab 或 GitHub 平台管理权限的话平台自带的贡献度分析功能也是一种选择但那是平台侧能力和本地开发者的需求不完全一样。6. 统计结果为什么总被质疑我踩过的坑6.1 同一人被拆成多个作者最常见的坑是同一个开发者在不同电脑或不同项目里配置了不同的user.name比如中文名、英文名、加了后缀的邮箱样式。Git 会把这些当作不同作者来统计。解决办法是先看作者清单git log --pretty%an | sort | uniq -c | sort -nr发现明显是同一个人的多个名字后可以在 awk 脚本里做作者名映射比如把zhangsan、Zhang San、张三统一成张三。这个小动作看起来不起眼但能避免排名表里出现“一个真实的人占了三个坑”的尴尬。6.2 合并提交让行数虚高如果不加--no-merges统计结果会严重偏高。合并提交会把合入分支的全部变更再次计入本次提交的行数变化里。假设你合入一个功能分支里面有 1000 行新增merge 提交本身也会显示这 1000 行新增于是总变更变成了 2000 行。在多人协作拉分支频繁的仓库里这个误差非常致命。可以再用一条命令验证有没有被合并提交影响git log --merges --oneline | wc -l只要仓库里存在 merge 提交统计脚本就必须带上--no-merges。6.3 换行符和编码导致的异常数字如果仓库发生过一次大的换行符统一比如从 CRLF 改成 LFGit 可能把这看成所有文件的所有行都被删除然后重新添加统计数字会爆炸式增长。Mac/Linux 开发者和 Windows 开发者协作时尤其容易出现。遇到这种情况先确认core.autocrlf的配置git config --get core.autocrlf如果发现异常高的统计数字排查一下统计周期内是否有人提交过这种全量格式化或换行符变更。这类提交通常不是真实功能工作量排名表里最好单独备注。6.4 大仓库卡死与索引失效仓库提交数很多时不管是 IDEA 的 Log 面板还是 GitLocalStats 插件都可能出现加载慢、卡顿甚至索引失效。IDEA 在首次打开大仓库 Log 时会构建索引需要等待一段时间。此时命令行反而更稳因为git log --numstat是 C 实现的底层命令处理速度比 IDE 层快很多。如果仓库历史极其庞大还可以限制扫描范围比如用--since只看近 90 天别用--all扫全部分支的全部提交。6.5 行数排名不等于代码贡献这可能是最容易被忽视的一点。统计结果出来以后行数最高的人不一定贡献最大可能是他写了大量样板代码净增为负的人不一定没干活可能是他在做重构。单纯把排名表丢出去会引发不必要的比较。我的处理方式是在统计表后面附上“改动总量”这一列并且明确说明这只是一个工作量参考维度真正评估代码贡献还要看代码评审、功能交付和问题修复情况。数据可以辅助决策但不建议直接当考核标准。6.6 生成文件和二进制文件污染统计如果你的项目里有package-lock.json、yarn.lock、dist/、build/、target/这类自动生成目录它们的行数变化会严重干扰排名。最理想的方案是在提交规范上约定不改动生成文件其次是统计时用 pathspec 排除。在 git log 命令的最后加上排除路径git log ... --numstat -- . :(exclude)dist :(exclude)target :(exclude)*.lock这里的:(exclude)是 Git pathspec 的排除语法。如果不处理这些文件一个依赖升级的提交可能让某人的行数瞬间多出几千行排名自然失去参考意义。统计代码行数排名这件事技术上不难难的是定义清楚“有效代码”和“统计周期”。我个人在实际使用中的体会是不要把这个数字上升到绩效工具的高度它更适合用来快速发现团队协作中的异常——比如某个模块为什么长期没人碰、某位同学是不是被大量合并冲突拖住了精力、一次格式化提交到底影响了多少文件。把这些当成数据线索去追问“为什么”比单纯比较排名更有价值。最后再分享一个小技巧统计结果跑出来之后先挑出排名前几位的作者去 Log 面板里抽查他们最近两三笔提交确认没有格式化、Revert 或生成文件混进来。数据只有经得起抽查才有资格拿出去讨论。