git log --shortstat 可统计分支增删行数,需用 --no-merges 和 main..branch-name 限定范围,再通过 awk 或 PowerShell 提取累加 insertions(+) 和 deletions(-) 数值,注意过滤 rename/copy 干扰及 rebase 导致的 hash 变更影响。

git log --shortstat 统计单次提交的增删行数
想快速知道某个分支上总共改了多少行代码,最直接的方式是用 git log 配合 --shortstat。它会为每次提交输出类似 “X files changed, Y insertions(+), Z deletions(-)” 的摘要,后续可汇总。
注意:这个统计只对 commit 有效,不包含未提交的改动;如果提交里有 merge(尤其来自其他分支),默认也会被计入——这容易虚高,需要过滤。
- 基础命令:
git log --shortstat branch-name - 排除 merge 提交(避免重复计算):
git log --no-merges --shortstat branch-name - 若只关心与 main 分支的差异(更准确反映“该分支新增”):
git log --no-merges --shortstat main..branch-name
用 awk 汇总 total insertions 和 deletions
git log --shortstat 输出是文本流,人工加总麻烦,直接用 awk 提取并累加更可靠。关键点在于匹配行中 “insertions(+)” 和 “deletions(-)” 后面的数字。
常见坑:有些提交只改文件但没增删行(比如仅修改模式或重命名),对应行可能没有 +/- 统计;awk 要跳过空匹配,否则报错或漏加。
- 安全汇总脚本片段:
git log --no-merges --shortstat main..feature/login | awk '/insertions\(\+\)/ {i += $4} /deletions\(-\)/ {d += $4} END {print "add:", i, "del:", d}' - $4 是因为标准输出格式固定为 “X files changed, Y insertions(+), Z deletions(-)”,数字在第 4 字段;如果 locale 或 git 版本导致字段偏移,建议先
git log -1 --shortstat看一眼实际结构
处理 rename 和 copy 导致的统计偏差
当 git 检测到文件重命名(rename)或复制(copy),--shortstat 默认仍会把旧路径的删除、新路径的插入分别计入——但这不是真实编码行为,只是元信息变化。尤其在重构分支里,这类操作可能占很大比例,严重干扰结果。
解决办法是加 --diff-filter=ACMR(只保留新增、复制、修改、重命名),再配合 --find-renames=0 关闭自动重命名检测,让 git 把 rename 当作 delete + add 处理——这样你至少知道它被算进去了,而不是悄无声息地膨胀数字。
- 更干净的统计(忽略 rename/copy 的“假增删”):
git log --no-merges --shortstat --diff-filter=d main..feature/login(d表示只统计 modified/deleted,排除 added/copy/rename) - 或者保守起见,用
--diff-filter=AM(只算真正新增和修改的文件),再人工核对是否遗漏重要逻辑变更
Windows 上 PowerShell 替代 awk 的写法
Windows 默认没 awk,PowerShell 可以解析,但正则和字段提取不如 shell 直观。关键是别用 ForEach-Object 逐行 split,容易因空格/逗号崩掉;推荐用 Select-String 匹配整行再提取数字。
PowerShell 容易忽略的点:git 输出带 CR/LF,-match 默认区分大小写,且括号在正则里要转义。
- 可用脚本片段:
git log --no-merges --shortstat main..feature/login | Select-String 'insertions$$\+$$' | ForEach-Object { $a = $_.Line.Split(' '); if ($a.Count -gt 3) { $adds += [int]$a[3] } } ; Select-String 'deletions$$-$$' | ForEach-Object { $b = $_.Line.Split(' '); if ($b.Count -gt 3) { $dels += [int]$b[3] } } ; "add: $adds del: $dels" - 更稳的做法是先保存到临时文件,再用
Get-Content+ 正则,避免管道中对象类型混乱
实际跑的时候,main..branch-name 这个范围最接近“该分支独立贡献”,但前提是 branch 从 main 拉出后没 rebase 过。一旦 rebase,commit hash 变了,git log 会当成全新提交,统计就不可比了。这点不留意,前后两次结果差一倍都正常。


















