lex0c/gitcortex
GitHub: lex0c/gitcortex
一款专注于 Git 仓库本地指标提取与统计的 CLI 工具,帮助开发者在离线环境下洞察代码质量与协作风险。
Stars: 0 | Forks: 0
# gitcortex
提取提交元数据、文件变更、blob 大小和开发者信息到 JSONL。生成顶级贡献者、文件热点、巴士因子、耦合分析、变更风险、工作模式以及开发者协作网络等统计信息。
## 性能
在开源仓库上进行基准测试。`extract` 读取裸克隆;`stats` 和 `report` 读取生成的 JSONL。在单台机器上使用预构建二进制文件进行测量(非受控实验室基准;仅作方向性参考,非绝对值)。
| 仓库 | 提交数 | 开发者数 | Extract | Stats (JSON) | Report (HTML) | JSONL 行数 |
|------------|---------|------|---------|-------------|--------------|------------|
| [Pi-hole](https://github.com/pi-hole/pi-hole) | 7,077 | 281 | 1.5s | 0.18s | 0.24s | 23K 行 / 6.5 MB |
| [Praat](https://github.com/praat/praat) | 10,221 | 19 | 25s | 0.96s | 0.95s | 95K 行 / 30 MB |
| [WordPress](https://github.com/WordPress/WordPress) | 52,466 | 131 | 47s | 2.9s | 2.8s | 298K 行 / 96 MB |
| [Kubernetes](https://github.com/kubernetes/kubernetes) | 137,016 | 5,295 | 2m 4s | 11.7s | 14s | 943K 行 / 314 MB |
| [Linux kernel](https://github.com/torvalds/linux) | 1,438,634 | 38,832 | 12m 57s | 1m 15s | 1m 53s | 6M 行 / 1.9 GB |
`extract`、`stats` 和 `report` 的扩展性大致与数据规模线性相关。`report` 中的每开发者协作图谱在文件遍历过程中通过一次遍历预先计算(O(F × D_per_file²));在 Kubernetes 快照上这会增加约 2 秒,Linux 上约 40 秒。若之前的实现在每个开发者循环内嵌套了文件遍历(O(D × F × D_per_file)),则在 Kubernetes 上慢 6 倍,在 Linux 上慢 11 倍。如果只需要聚合数据,`stats --format json` 始终是最快的路径;当你真正需要 HTML 仪表板时再使用 `report`。
## 供应商与生成的代码
**这是每个统计中最大的实际失真。** 行数统计将 5 万行的 `generated.pb.go` 与 5 万行的手写模块视为等同。`package-lock.json` 这类锁文件会随每次依赖更新而重新生成。供应商依赖在每次更新时都会增加变更计数。OpenAPI 规范、压缩的 JS、`bindata.go` 风格的嵌入文件——这些都很常见,都会增加变更计数和巴士因子,却不能反映真实的人类贡献。
在不加过滤的情况下运行 gitcortex 处理 Kubernetes,前十大历史热点将是 `vendor/golang.org/x/tools/…/manifest.go`、`api/openapi-spec/v3/…v1alpha3_openapi.json` 和 `staging/…/generated.pb.go` —— 从数据上看技术上正确,但从决策角度看实际上毫无用处。
通过在提取时使用 `--ignore` 通配模式来缓解。匹配的文件会完全从 JSONL 中丢弃,因此 **所有下游统计**(热点、变更风险、巴士因子、耦合、开发者网络、个人资料)都将只反映手工编写的代码:
```
# 典型入门套件
gitcortex extract --repo . \
--ignore "vendor/*" \
--ignore "node_modules/*" \
--ignore "dist/*" \
--ignore "build/*" \
--ignore "*.min.js" \
--ignore "*.min.css" \
--ignore "package-lock.json" \
--ignore "yarn.lock" \
--ignore "Cargo.lock" \
--ignore "go.sum" \
--ignore "poetry.lock" \
--ignore "*.pb.go" \
--ignore "*_generated.go"
```
模式匹配 `git log --raw` 输出的文件路径(使用正斜杠,相对于仓库根目录)。目录模式如 `vendor/*` 会排除该前缀下的所有内容。文件名模式如 `*.pb.go` 在任意深度匹配。
从宽松的规则开始,运行 `gitcortex stats --stat hotspots --top 20` 和 `--stat churn-risk --top 20`,然后为输出中占主导地位的文件类型添加 `--ignore` 条目。重新提取,直到前十大列表代表真正值得理解的变更。
## 隐私与可靠性
所有处理均在 **本地 100% 完成**。不依赖外部服务、不进行网络调用、**不使用 AI**、不发送遥测数据。gitcortex 仅读取 Git 元数据(提交、作者、日期、文件路径、行数)——它永远不会读取源代码内容。提交消息默认不包含,仅在使用 `--include-commit-messages` 时包含。数据保留在你的机器上,作为一个由你控制的 JSONL 文件。
## 安装
### 下载二进制文件(无需 Go)
适用于 Linux、macOS 和 Windows 的预构建二进制文件可在 [GitHub Releases](https://github.com/lex0c/gitcortex/releases/latest) 获取:
```
# Linux (x64)
curl -L https://github.com/lex0c/gitcortex/releases/latest/download/gitcortex-linux-amd64 -o gitcortex
chmod +x gitcortex
sudo mv gitcortex /usr/local/bin/
# macOS (Apple Silicon)
curl -L https://github.com/lex0c/gitcortex/releases/latest/download/gitcortex-darwin-arm64 -o gitcortex
chmod +x gitcortex
sudo mv gitcortex /usr/local/bin/
# macOS (Intel)
curl -L https://github.com/lex0c/gitcortex/releases/latest/download/gitcortex-darwin-amd64 -o gitcortex
chmod +x gitcortex
sudo mv gitcortex /usr/local/bin/
```
### Go 安装
```
go install github.com/lex0c/gitcortex/cmd/gitcortex@latest
```
### 从源码构建
```
git clone https://github.com/lex0c/gitcortex.git
cd gitcortex
make build
```
其他目标:`make test`、`make vet`、`make check`(vet + test)、`make install`、`make clean`。
检查版本:`gitcortex --version`
要求 Git 2.31+ 和 Go 1.21+。CI 在每次推送/拉取请求时通过 GitHub Actions 自动运行。
### 发布
```
git tag v0.1.0
git push origin main --tags
```
版本在构建时从 `git describe --tags` 注入。标记后执行 `make build && gitcortex --version` 将显示 `v0.1.0`。
## 使用
### 提取
```
# 从当前目录提取
gitcortex extract
# 从特定仓库和分支提取
gitcortex extract --repo /path/to/repo --branch main
# 在输出中包含提交信息
gitcortex extract --repo /path/to/repo --include-commit-messages
# 自定义输出路径
gitcortex extract --repo /path/to/repo --output data.jsonl
# 通过 .mailmap 规范化作者标识
gitcortex extract --repo /path/to/repo --mailmap
# 排除提取的文件
gitcortex extract --repo /path/to/repo --ignore package-lock.json --ignore "*.min.js"
# 排除整个目录
gitcortex extract --repo /path/to/repo --ignore "dist/*" --ignore "vendor/*"
```
默认分支从 `origin/HEAD` 自动检测,若不可用则回退到 `main`、`master` 或 `HEAD`。
`--mailmap` 标志使用 Git 内置的 `.mailmap` 支持来统一开发者身份。启用它可避免同一人以不同邮箱(例如 `alice@work.com` 和 `alice@personal.com`)被当作不同贡献者。
输出为 JSONL 文件,每行一条记录。四种记录类型:
```
{"type":"commit","sha":"abc...","tree":"def...","parents":["ghi..."],"author_name":"Alice","author_email":"alice@example.com","author_date":"2024-01-15T10:30:00Z","committer_name":"Alice","committer_email":"alice@example.com","committer_date":"2024-01-15T10:30:00Z","message":"","additions":42,"deletions":7,"files_changed":3}
{"type":"commit_parent","sha":"abc...","parent_sha":"ghi..."}
{"type":"commit_file","commit":"abc...","path_current":"src/main.go","path_previous":"src/main.go","status":"M","old_hash":"111...","new_hash":"222...","old_size":1024,"new_size":1087,"additions":10,"deletions":3}
{"type":"dev","dev_id":"sha256hash...","name":"Alice","email":"alice@example.com"}
```
### 恢复
提取过程可恢复。状态会保存在文件中(默认 `git_state`),在每个检查点保存:
```
# 首次运行(中断或已完成)
gitcortex extract --repo /path/to/repo --output data.jsonl
# 从中断处恢复
gitcortex extract --repo /path/to/repo --output data.jsonl
```
检查点间隔由 `--batch-size` 控制(默认 1000 次提交)。
### 统计
```
# 全部统计(表格格式)
gitcortex stats --input data.jsonl
# 单个统计
gitcortex stats --input data.jsonl --stat contributors --top 20
# 多仓库:跨仓库聚合统计
gitcortex stats --input svc-auth.jsonl --input svc-payments.jsonl --input svc-gateway.jsonl
# 导出为 CSV 或 JSON
gitcortex stats --input data.jsonl --stat hotspots --format csv > hotspots.csv
gitcortex stats --input data.jsonl --format json > report.json
# 按周活动
gitcortex stats --input data.jsonl --stat activity --granularity week
# 过滤到最近时段
gitcortex stats --since 7d # last 7 days
gitcortex stats --since 3m --stat contributors # last 3 months
gitcortex report --since 30d --output monthly.html
```
可用统计项:
| 统计项 | 描述 |
|------|-------------|
| `summary` | 总提交数、开发者数、文件数、增加/删除行数、合并次数、平均值、日期范围 |
| `contributors` | 按提交数排名的开发者,含每位开发者的增加/删除行数 |
| `hotspots` | 最常变更的文件及其变更次数与唯一开发者数 |
| `activity` | 按天、周、月或年统计的提交与变更行数 |
| `busfactor` | 变更占比超过 80% 的开发者数最少的文件 |
| `coupling` | 经常一起变更的文件,揭示隐藏的架构依赖 |
| `churn-risk` | 按近期变更频率排序的文件,并标记为 `cold` / `active` / `active-core` / `silo` / `legacy-hotspot` |
| `working-patterns` | 按小时和星期几统计的提交热度图 |
| `dev-network` | 基于共享文件所有权的开发者协作图 |
| `profile` | 每个开发者的个人报告:范围、贡献类型、节奏、协作、顶级文件 |
| `top-commits` | 按变更行数排序的最大提交(若提取时包含 `--include-commit-messages`,则包含提交信息) |
| `pareto` | 文件、开发者(双视角:提交与变更)、目录的集中度(80% 阈值) |
输出格式:`table`(默认,人可读)、`csv`(每个 `--stat` 一个干净表格)、`json`(包含所有部分的统一对象)。
详见 [`docs/METRICS.md`](docs/METRICS.md) 了解每个指标的计算方式,包括时区处理(聚合桶使用 UTC、工作模式使用作者本地时间)以及重命名跟踪(基于 Git 检测到的重命名合并历史)。
### 开发者个人资料
面向管理者的每位开发者报告,展示其范围、贡献类型、节奏、协作及顶级。
```
# 所有开发者,按提交数排序
gitcortex stats --input data.jsonl --stat profile
# 单个开发者
gitcortex stats --input data.jsonl --stat profile --email alice@company.com
# JSON 导出
gitcortex stats --input data.jsonl --stat profile --format json
```
每个个人资料包含:
- **范围**:该开发者工作的主要目录(按唯一文件数,占比%)
- **贡献**:增长(增加 >> 删除)、平衡,或重构(删除 >> 增加)
- **节奏**:活跃日的提交次数
- **协作**:共享相同文件的最重要开发者
- **周末占比**:非工作时间工作的比例
- **顶级文件**:受变更影响最大的文件
### 耦合分析
文件耦合检测在同一提交中共同变更的文件,揭示代码中不可见的架构依赖。基于 Adam Tornhill 的 ["Your Code as a Crime Scene"](https://pragprog.com/titles/atcrime/your-code-as-a-crime-scene/) 方法学。
```
gitcortex stats --input data.jsonl --stat coupling --top 20
gitcortex stats --input data.jsonl --stat coupling --coupling-min-changes 10 --coupling-max-files 30
```
```
FILE A FILE B CO-CHANGES COUPLING CHANGES A CHANGES B
ApplicationDbContext.cs ApplicationDbContextModelSnapshot.cs 54 61% 100 89
GuardianPortalControllerTests.cs GuardianPortalController.cs 40 91% 44 61
IWorkspaceRepository.cs WorkspaceRepository.cs 19 100% 19 29
```
- **耦合百分比**:共同变更次数 / 两者中较小变更次数 —— 衡量两者关联的紧密程度
- **100% 耦合**:每当变更次数较少的文件时,另一文件也必然变更
### 变更风险
按近期变更频率对文件进行排序并标记类别,以便区分健康的核心模块与遗留瓶颈,无需逐列比对。
```
gitcortex stats --input data.jsonl --stat churn-risk --top 15
gitcortex stats --input data.jsonl --stat churn-risk --churn-half-life 60 # faster decay
```
Pi-hole 仓库的真实输出(每种标签一个示例):
```
PATH LABEL CHURN BF AGE TREND
automated install/basic-install.sh active 115.3 15 4121d 0.00
.github/workflows/codeql-analysis.yml legacy-hotspot 66.2 2 1640d 0.26
advanced/bash-completion/pihole-ftl.bash silo 16.5 1 240d 1.00
test/_alpine_3_23.Dockerfile active-core 7.1 1 120d 1.00
advanced/Templates/gravity.db.schema cold 0.0 1 2616d 1.00
```
| 标签 | 含义 |
|-------|---------|
| `cold` | 近期变更少 —— 可忽略 |
| `active` | 共享所有权(巴士因子 ≥ 3)。健康。 |
| `active-core` | 新代码(<180 天),单一作者。通常正常。 |
| `silo` | 旧、集中、稳定/增长。知识瓶颈 —— 需规划转移。 |
| `legacy-hotspot` | **紧急。** 旧、集中、下降。仍在被修改的废弃路径。 |
排序键为 `recent_churn`;标签回答“这些活动是否构成问题?”。复合字段 `risk_score`(`recent_churn / bus_factor`)仍用于 CI 网关向后兼容。
`--churn-half-life` 控制旧变更的衰减速度(默认 90 天,即每 90 天权重减半)。
### 工作模式
按小时和星期几统计提交分布。揭示时区、过劳模式与部署习惯。
```
gitcortex stats --input data.jsonl --stat working-patterns
gitcortex stats --input data.jsonl --stat working-patterns --format csv > patterns.csv
```
```
HOUR Mon Tue Wed Thu Fri Sat Sun
09:00 1 1 3 . . . .
10:00 7 4 2 2 1 6 1
11:00 10 13 3 1 2 14 7
...
19:00 35 15 7 10 12 16 13
22:00 26 9 . 1 13 9 8
```
### 开发者网络
协作图谱,连接修改过相同文件的开发者。权重反映重叠比例。
```
gitcortex stats --input data.jsonl --stat dev-network --top 20
gitcortex stats --input data.jsonl --stat dev-network --network-min-files 10
gitcortex stats --input data.jsonl --stat dev-network --format csv > network.csv
```
```
DEV A DEV B SHARED FILES WEIGHT
alice@company.com bob@company.com 142 34.5%
carol@company.com alice@company.com 87 21.2%
```
### 多仓库
跨多个仓库聚合统计。文件路径会自动加上文件名前缀以避免冲突。
```
# 提取每个仓库
gitcortex extract --repo ./svc-auth --output auth.jsonl
gitcortex extract --repo ./svc-payments --output payments.jsonl
# 聚合统计
gitcortex stats --input auth.jsonl --input payments.jsonl
gitcortex stats --input auth.jsonl --input payments.jsonl --stat coupling --top 20
```
路径显示为 `auth:src/main.go`,贡献者按邮箱跨仓库去重 —— 同一开发者在多个仓库的贡献只计一次。
### 差异:比较时间段
比较两个时间段的统计,或筛选到单一时期。
```
# 对比 Q1 与 Q2
gitcortex diff --input data.jsonl \
--from 2024-01-01 --to 2024-03-31 \
--vs-from 2024-04-01 --vs-to 2024-06-30
# 过滤到单月(运行该时段全部统计)
gitcortex diff --input data.jsonl --from 2024-03-01 --to 2024-03-31
# JSON 导出
gitcortex diff --input data.jsonl \
--from 2024-01-01 --to 2024-06-30 \
--vs-from 2024-07-01 --vs-to 2024-12-31 \
--format json > comparison.json
```
```
=== Summary: 2024-01-01 to 2024-03-31 vs 2024-04-01 to 2024-06-30 ===
Commits 812 → 945 (+133)
Additions 45420 → 62830 (+17410)
Deletions 12300 → 18900 (+6600)
Files touched 320 → 410 (+90)
Merge commits 45 → 38 (-7)
```
### HTML 报告
生成包含全部统计可视化图表的自包含 HTML 仪表板。纯 HTML+CSS,无外部依赖,可在任意浏览器打开。
```
gitcortex report --input data.jsonl --output report.html
gitcortex report --input data.jsonl --output report.html --top 30
# 每位开发者的个人报告(可与经理共享)
gitcortex report --input data.jsonl --email alice@company.com --output alice.html
```
包含:概览卡片、活动热力图(带表格切换)、顶级贡献者、文件热点、变更风险、巴士因子、文件耦合、工作模式热力图、顶级提交、开发者网络与开发者个人资料。典型体积:50-500KB,取决于贡献者数量。
## CI:流水线质量门禁
运行自动化检查并在阈值超标时失败构建。
输出格式:`text`(默认)、`github-actions`(注解)、`gitlab`(Code Quality JSON)、`json`。
检测到违规时退出码为 1,清洁时退出码为 0。
## 架构
```
cmd/gitcortex/main.go CLI entry point (cobra)
internal/
model/model.go JSONL output types
git/
stream.go Single git log streaming parser
catfile.go Long-running cat-file blob size resolver
commands.go Utility functions (branch detection, SHA validation)
parse.go Shared types (RawEntry, NumstatEntry)
discard.go Malformed entry tracking
extract/extract.go Extraction orchestration, state, JSONL writing
stats/
reader.go Streaming JSONL aggregator (single-pass)
stats.go Stat computations (9 stats)
format.go Table/CSV/JSON output formatting
```
### 提取流水线
两个长时间运行的 Git 进程处理整个提取过程,与仓库大小无关:
```
git log --raw --numstat -M --- single stream ---- parse ---- emit JSONL
|
git cat-file --batch-check -- long-running ---- resolve blob sizes
```
### 统计流水线
单次遍历流式聚合。JSONL 文件仅读取一次,逐行处理,聚合到紧凑的映射中。原始记录永不存储 —— 仅保留预计算的聚合状态驻留内存。
标签:EVTX分析, Git, HTML报告, JSONL, 二进制分发, 仓库指标, 代码分析, 代码耦合, 凭证管理, 单机分析, 变更风险, 可扩展分析, 工作模式, 开发者协作网络, 开源项目分析, 性能基准, 总线因子, 提交数据提取, 数据提取, 文档结构分析, 日志审计, 本地分析, 热点文件, 统计报告, 统计计算