一个用 Rust 编写的 CLI 工具,能够递归发现 Git 仓库、捕获状态变更、生成差异对比、提取包含完整片段的代码元素,并为代码审查与审计工作流生成安全相关的报告。
如果本项目对您的工作有帮助,请支持我们的持续维护和新特性开发。
ETH 捐赠钱包
0x11282eE5726B3370c8B480e321b3B2aA13686582
扫描二维码或复制上方钱包地址。
为什么不用 bash 脚本?
像
ls | while read line; do git -C "$line" diff HEAD~1 HEAD || true; done这样的单行命令只能显示原始差异。 DiffCatcher 增加了递归发现、代码元素提取、安全模式检测、 SARIF 输出用于 CI/CD、并行处理和跨仓库安全聚合。 请参阅下面的完整对比。
git clone https://github.com/Teycir/DiffCatcher.git
cd DiffCatcher
cargo build --release
./target/release/diffcatcher --help
# 扫描目录中的所有仓库(仅获取,不修改)
diffcatcher ~/projects
# 拉取更新并生成安全报告
diffcatcher ~/projects --pull -o ./report
# 对单个仓库的两个分支进行差异对比(PR 评审模式)
diffcatcher ./my-repo --diff main..feature/auth -o ./pr-report
# 生成 SARIF 输出以供 GitHub 代码扫描
diffcatcher ~/projects --summary-format sarif,json -o ./report
# 干运行,查看将要扫描的内容
diffcatcher ~/projects --dry-run
# 快速扫描,使用 8 个并行工作线程
diffcatcher ~/projects -j 8 --quiet
# 使用默认设置扫描(仅获取)
diffcatcher <ROOT_DIR>
# 自定义输出目录
diffcatcher ~/projects -o ./my-report
# 包含嵌套仓库并跟随符号链接
diffcatcher ~/projects --nested --follow-symlinks
# 跳过隐藏目录
diffcatcher ~/projects --skip-hidden
# 仅获取(默认 - 不更改工作树)
diffcatcher ~/projects
# 实际拉取更改
diffcatcher ~/projects --pull
# 强制拉取,对脏仓库使用 stash/pop
diffcatcher ~/projects --pull --force-pull
# 使用变基策略
diffcatcher ~/projects --pull --pull-strategy rebase
# 完全跳过获取/拉取(仅历史差异)
diffcatcher ~/projects --no-pull
# 跳过元素提取(仅原始差异)
diffcatcher ~/projects --no-summary-extraction
# 提取元素但跳过代码片段
diffcatcher ~/projects --no-snippets
# 调整片段上下文和限制
diffcatcher ~/projects --snippet-context 10 --max-snippet-lines 300
# 限制每个差异的元素数量
diffcatcher ~/projects --max-elements 1000
# 跳过安全标记
diffcatcher ~/projects --no-security-tags
# 在安全分析中包含测试文件
diffcatcher ~/projects --include-test-security
# 使用自定义安全模式
diffcatcher ~/projects --security-tags-file ./custom-patterns.json
DiffCatcher 可以自动加载项目本地配置,来源包括:
<ROOT_DIR>/.diffcatcher.toml(默认)--config <FILE> 指定自定义文件--no-config 禁用示例:
output = "reports-local"
no_pull = true
history_depth = 2
summary_formats = ["json", "txt"]
no_security_tags = false
[plugins]
security_pattern_files = ["plugins/security-extra.json"]
extractor_files = ["plugins/extractors.json"]
当显式设置时,CLI 标志仍会覆盖配置值。
DiffCatcher 支持两种插件类型:
--security-plugin-file <FILE> 指定(可重复)--extractor-plugin-file <FILE> 指定(可重复)安全插件格式与 --security-tags-file JSON 格式一致(version、mode、tags)。
提取器插件格式:
{
"version": 1,
"extractors": [
{
"name": "policy-rule",
"kind": "Config",
"regex": "^policy\\s+([A-Za-z_][A-Za-z0-9_]*)"
}
]
}
# 对单个仓库的两个分支进行差异对比
diffcatcher ./my-repo --diff main..feature/auth
# 对比特定提交
diffcatcher ./my-repo --diff abc123..def456
# 使用 SARIF 输出进行 CI 集成
diffcatcher ./my-repo --diff origin/main..HEAD --summary-format sarif -o ./pr-report
--diff BASE..HEAD 标志跳过仓库发现和获取/拉取——直接对比两个引用(分支、标签或提交哈希),并对结果运行完整的提取和安全标记流水线。
# 与其他格式一起生成 SARIF
diffcatcher ~/projects --summary-format sarif,json,md
# 仅 SARIF 用于 CI/CD 上传
diffcatcher ~/projects --summary-format sarif -o ./report
当 --summary-format 中包含 sarif 时,会在报告根目录写入 results.sarif 文件。该文件遵循 SARIF 2.1.0 标准,并可集成 GitHub 代码扫描、VS Code SARIF 查看器、Azure DevOps 及其他兼容 SARIF 的工具。
# 增量模式(跳过未更改的仓库)
diffcatcher ~/projects --incremental -o ./report
# 按分支模式过滤
diffcatcher ~/projects --branch-filter "main"
# 调整历史深度
diffcatcher ~/projects --history-depth 5
# JSON 输出用于 CI/CD
diffcatcher ~/projects --quiet --json > result.json
# 详细输出,显示发现的路径
diffcatcher ~/projects --verbose
<report_dir>/
├── summary.json # 全局摘要
├── summary.md # Markdown 摘要
├── results.sarif # SARIF 2.1.0 输出(当 --summary-format 包含 sarif 时)
├── security_overview.json # 跨仓库安全聚合
├── security_overview.md
├── <repo-name>/
│ ├── status.json # 仓库状态
│ ├── pull_log.txt
│ └── diffs/
│ ├── diff_N_vs_N-1.patch # 原始统一差异
│ ├── changes_N_vs_N-1.txt # 文件清单
│ ├── summary_N_vs_N-1.json # 元素提取
│ ├── summary_N_vs_N-1.md
│ └── snippets/
│ ├── 001_validate_token_ADDED.rs
│ ├── 002_check_permissions_BEFORE.rs
│ ├── 002_check_permissions_AFTER.rs
│ └── 002_check_permissions.diff
└── ...
| 标志 | 默认值 | 描述 |
|---|---|---|
-o, --output | ./reports/<timestamp> | 报告输出目录 |
-j, --parallel | 4 | 并发仓库处理数 |
-t, --timeout | 120 | Git 操作超时(秒) |
-d, --history-depth | 2 | 需对比的历史提交数 |
--snippet-context | 5 | 变更周围的上下文行数 |
--max-snippet-lines | 200 | 每个片段的最大行数 |
--max-elements | 500 | 每个差异的最大元素数 |
--diff | — | 对单个仓库的两个引用进行差异对比(BASE..HEAD) |
--summary-format | json,md | 输出格式:json、md、txt、sarif |
查看 diffcatcher --help 获取所有选项。
创建一个包含自定义模式的 JSON 文件:
{
"version": 1,
"mode": "extend",
"tags": [
{
"tag": "pii-handling",
"description": "PII 数据处理",
"severity": "High",
"patterns": ["ssn", "social_security", "passport"]
}
]
}
使用 --security-tags-file ./patterns.json
src/
├── cli.rs # 参数解析
├── scanner.rs # 仓库发现
├── git/ # Git 操作
│ ├── commands.rs # Git 封装
│ ├── state.rs # 状态捕获
│ ├── diff.rs # 差异生成
│ └── file_retrieval.rs
├── extraction/ # 元素提取
│ ├── parser.rs # 统一差异解析器
│ ├── elements.rs # 元素检测
│ ├── snippets.rs # 代码片段提取
│ ├── boundary.rs # 括号/缩进跟踪
│ └── languages/ # 语言特定模式
├── security/ # 安全标记
│ ├── tagger.rs # 模式匹配
│ ├── patterns.rs # 内置模式
│ └── overview.rs # 跨仓库聚合
└── report/ # 报告生成
├── writer.rs # 目录结构
├── json.rs # JSON 序列化
├── sarif.rs # SARIF 2.1.0 输出
├── markdown.rs # Markdown 格式化
└── snippet_writer.rs
一个简单的 bash 单行命令可以列出差异:
ls | while read line; do git -C "$line" diff HEAD~1 HEAD || true; done
这对于快速检查有用,但 DiffCatcher 增加了显著的能力: