本文灵感来源于文章《The Git Commands I Run Before Reading Any Code》

一、为什么读代码前要先看Git历史

作为一个 C++ 工程师,我接手过很多新项目。以前我总是迫不及待地打开代码编辑器,试图从第一行代码开始理解整个系统。但我发现,这种方法效率很低——我常常在代码迷宫中迷失方向,不知道哪里是核心、哪里是坑。

后来我学到了一个重要的技巧:在打开任何代码文件之前,先运行几个 Git 命令,从提交历史中获取代码库的诊断画像。

这就像看医生之前,护士会先测体温、量血压一样。Git 历史能告诉我们:

  • 谁构建了这个系统?
  • 哪里是问题集中的地方?
  • 团队是充满信心地迭代,还是小心翼翼地拆炸弹?
  • 项目是在加速还是在衰退?

二、命令一:谁是代码改动最频繁的文件

1
git log --format=format: --name-only --since="1 year ago" | sort | uniq -c | sort -nr | head -20

运行结果示例:

1
2
3
4
5
156 src/core/engine.cpp
89 src/utils/logger.cpp
72 include/config.h
58 src/net/server.cpp
45 src/database/connection.cpp

这个命令会列出过去一年中改动最频繁的20个文件。

解读:

排在最前面的文件,通常就是团队最害怕触碰的文件。"哦对,那个文件。谁都不想碰它。"

高改动频率本身不一定是坏事,可能只是活跃开发的表现。但如果一个文件改动频繁,却没人愿意负责,那就是最明确的危险信号——这个文件充满了补丁上的补丁,一个小小的改动可能引发不可预测的连锁反应。

微软研究院的一项研究发现,相对改动率(按组件大小归一化后的改动次数)是预测缺陷密度的好指标。我通常会把这个命令的输出和下面的"bug 热点"命令交叉比对——一个既高改动又高 bug 的文件,就是你最大的风险点。

三、命令二:谁构建了这个系统

1
git shortlog -sn --no-merges

运行结果示例:

1
2
3
4
456  Zhang San
234 Li Si
89 Wang Wu
45 Zhao Liu

解读:

这个命令按提交数量对所有贡献者排序。

关键观察点:

  1. 巴士因子(Bus Factor):如果某个人贡献了60%以上的代码,那就是一个严重的风险。如果这个人已经离开半年了,那就是危机。

  2. 贡献者断层:30个贡献者,但过去一年只有3个人活跃——构建系统的人已经不是维护系统的人了。

  3. 活跃窗口对比:比较整体和近6个月的贡献者分布:

1
git shortlog -sn --no-merges --since="6 months ago"

如果整体排名第一的贡献者不在近6个月的列表中,这是一个需要立即关注的信号。

注意事项: 如果团队使用 squash-merge 工作流,这个命令反映的是合并者,而不是实际编写代码的人。在得出结论之前,最好先了解团队的合并策略。

四、命令三:Bug集中在哪里

1
git log -i -E --grep="fix|bug|broken" --name-only --format='' | sort | uniq -c | sort -nr | head -20

运行结果示例:

1
2
3
23 src/core/engine.cpp
15 src/utils/logger.cpp
8 src/net/server.cpp

解读:

这个命令和改动频率命令类似,但只过滤包含 bug 相关关键词的提交。

交叉分析:

把这个列表和改动频率列表对比。同时出现在两个列表中的文件,就是最高风险的代码——它们不断出问题,不断被修补,但从未被真正修复。

这依赖于团队的提交信息规范。如果团队每次提交都写"update stuff",你什么也得不到。但即使是一个粗略的 bug 密度地图,也比没有地图好。

五、命令四:项目在加速还是在衰退

1
git log --format='%ad' --date=format:'%Y-%m' | sort | uniq -c

运行结果示例:

1
2
3
4
5
6
23 2025-01
28 2025-02
31 2025-03
15 2025-04
12 2025-05
8 2025-06

解读:

这个命令按月份统计提交数量,展示整个仓库历史的提交节奏。

关键形状:

  1. 稳定节奏:健康的信号,说明团队持续迭代。

  2. 突然下降:单个月提交量减半,通常意味着有人离职。

  3. 持续下降:6到12个月的下降曲线,说明团队正在失去动力。

  4. 周期性尖峰:尖峰后跟着安静的月份,说明团队把工作批量打包成版本发布,而不是持续交付。

我曾经给一个 CTO 展示他们的提交速度图表,他说:"那就是我们失去第二个高级工程师的时候。" 在此之前,他从未把时间线联系起来。这是团队数据,不是代码数据,但同样重要。

六、命令五:团队在救火还是在正常开发

1
git log --oneline --since="1 year ago" | grep -iE 'revert|hotfix|emergency|rollback'

运行结果示例:

1
2
3
abc1234 revert "fix: 紧急修复登录问题"
def5678 hotfix: 修复内存泄漏
ghi9012 emergency: 回滚到上一个稳定版本

解读:

这个命令统计 revert 和 hotfix 的频率。

判断标准:

  • 一年中只有几次:正常。
  • 每几周就有一次:团队不信任部署流程,这是更深层次问题的证据——测试不可靠、缺少 staging 环境、或者部署管道让回滚变得困难。
  • 零结果:要么团队很稳定,要么没人写描述性的提交信息。

危机模式很容易识别——要么存在,要么不存在。

七、我的实践:代码库健康度检查脚本

作为一个 C++ 工程师,我喜欢把常用命令封装成脚本。下面是我自己写的代码库健康度检查脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#!/bin/bash

echo "========================================"
echo "代码库健康度检查报告"
echo "========================================"

echo ""
echo "【1】高频改动文件(近一年)"
echo "----------------------------------------"
git log --format=format: --name-only --since="1 year ago" | sort | uniq -c | sort -nr | head -10

echo ""
echo "【2】贡献者分布"
echo "----------------------------------------"
echo "整体贡献者:"
git shortlog -sn --no-merges | head -10
echo ""
echo "近6个月活跃贡献者:"
git shortlog -sn --no-merges --since="6 months ago" | head -10

echo ""
echo "【3】Bug集中文件"
echo "----------------------------------------"
git log -i -E --grep="fix|bug|broken" --name-only --format='' | sort | uniq -c | sort -nr | head -10

echo ""
echo "【4】提交节奏(近一年)"
echo "----------------------------------------"
git log --format='%ad' --date=format:'%Y-%m' --since="1 year ago" | sort | uniq -c

echo ""
echo "【5】紧急修复统计"
echo "----------------------------------------"
emergency_count=$(git log --oneline --since="1 year ago" | grep -iE 'revert|hotfix|emergency|rollback' | wc -l)
echo "近一年紧急修复/回滚次数:$emergency_count"
if [ $emergency_count -gt 12 ]; then
echo "⚠️ 警告:紧急修复频率较高,建议检查部署流程"
fi

echo ""
echo "========================================"
echo "检查完成"
echo "========================================"

把这个脚本保存为 health-check.sh,运行方式:

1
2
chmod +x health-check.sh
./health-check.sh

运行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
========================================
代码库健康度检查报告
========================================

【1】高频改动文件(近一年)
----------------------------------------
156 src/core/engine.cpp
89 src/utils/logger.cpp
72 include/config.h

【2】贡献者分布
----------------------------------------
整体贡献者:
456 Zhang San
234 Li Si
89 Wang Wu

近6个月活跃贡献者:
120 Li Si
89 Wang Wu

【3】Bug集中文件
----------------------------------------
23 src/core/engine.cpp
15 src/utils/logger.cpp

【4】提交节奏(近一年)
----------------------------------------
23 2025-07
28 2025-08
31 2025-09

【5】紧急修复统计
----------------------------------------
近一年紧急修复/回滚次数:5
========================================
检查完成
========================================

八、这些命令告诉我们什么

这五个命令只需要几分钟就能运行完。它们不会告诉你一切,但会告诉你:

  1. 应该先读哪些代码:从低风险、稳定的模块开始,而不是一头扎进地雷区。

  2. 应该关注什么:当你打开 src/core/engine.cpp 时,你会知道这是一个既高频改动又高频出 bug 的文件,需要格外小心。

  3. 团队的状况:提交节奏、贡献者分布、紧急修复频率——这些都是团队健康度的重要指标。

  4. 代码库的历史:你能看到系统是如何演进的,哪些部分经历了最多的迭代。

九、总结

作为一个 C++ 工程师,我越来越意识到:理解代码库的历史和文化,和理解代码本身同样重要。

这五个 Git 命令给了我一个快速诊断代码库的工具:

命令 用途 关键信号
git log --name-only 高频改动文件 高改动+高bug=最大风险
git shortlog -sn 贡献者分布 单人大占比=巴士因子风险
git log --grep="fix" Bug集中文件 与高频改动交叉分析
git log --date=format 提交节奏 突然下降=人员变动
`git log grep revert` 紧急修复频率

记住:在打开代码之前,先问 Git 几个问题。答案会让你的代码审查之旅更加高效。


参考文章:The Git Commands I Run Before Reading Any Code