forked from Gitlink/gitlink-cli
8.8 KiB
8.8 KiB
代码变更分析
本文档详细说明如何使用 gitlink-cli 分析 PR 的代码变更。
📋 概述
代码变更分析是智能代码审查的第一步,通过获取 PR 的文件列表和 diff 内容,为后续的 AI 分析提供数据基础。
🎯 分析流程
开始
↓
1. 获取 PR 基本信息
├─ 使用 pr +view 获取 PR 详情
└─ 确认 PR 存在且可访问
↓
2. 获取变更文件列表
├─ 使用 pr +files 获取文件列表
└─ 识别新增/修改/删除的文件
↓
3. 获取 diff 内容
├─ 使用 pr +diff 获取完整 diff
└─ 解析代码变更详情
↓
4. 数据预处理
├─ 过滤无关文件(如二进制文件)
├─ 提取代码片段
└─ 组织分析数据
↓
完成
🔧 步骤详解
步骤 1:获取 PR 基本信息
目的: 确认 PR 存在且可访问,获取 PR 的元数据信息。
命令:
gitlink-cli pr +view --id <pr_id> --format json
示例:
# 获取 PR #123 的基本信息
gitlink-cli pr +view --id 123 --format json
返回结果:
{
"ok": true,
"data": {
"id": 123,
"project_issues_index": 123,
"title": "Feature: Add user authentication",
"body": "This PR adds user authentication...",
"author": {
"login": "developer",
"user_id": 456
},
"status": "open",
"pull_request_status": 0,
"head": "feature/auth",
"base": "main",
"created_at": "2026-06-12T10:00:00Z",
"updated_at": "2026-06-12T10:30:00Z"
}
}
关键信息提取:
id: PR 数据库 ID(用于后续 API 调用)project_issues_index: PR 编号(网页显示)title: PR 标题author: 作者信息status: PR 状态(open/closed/merged)head/base: 分支信息
步骤 2:获取变更文件列表
目的: 获取 PR 中所有变更的文件列表,了解代码变更的范围。
命令:
gitlink-cli pr +files --id <pr_id> --format json
示例:
# 获取 PR #123 的变更文件列表
gitlink-cli pr +files --id 123 --format json
返回结果:
{
"ok": true,
"data": {
"files": [
{
"filename": "src/auth/login.go",
"status": "modified",
"additions": 50,
"deletions": 20,
"changes": 70,
"patch": "@@ -1,10 +1,15 @@\n+func login() {"
},
{
"filename": "src/auth/user.go",
"status": "added",
"additions": 80,
"deletions": 0,
"changes": 80,
"patch": "+package auth\n+\n+func User() {"
},
{
"filename": "README.md",
"status": "modified",
"additions": 5,
"deletions": 2,
"changes": 7,
"patch": "@@ -1,5 +1,7 @@\n+## Usage\n ..."
}
],
"total_files": 3,
"total_additions": 135,
"total_deletions": 22,
"total_changes": 157
}
文件状态说明:
added: 新增文件modified: 修改文件deleted: 删除文件renamed: 重命名文件
统计信息:
total_files: 变更文件总数total_additions: 新增行数total_deletions: 删除行数total_changes: 总变更行数
步骤 3:获取 diff 内容
目的: 获取 PR 的完整 diff 内容,用于 AI 代码分析。
命令:
gitlink-cli pr +diff --id <pr_id> --format json
示例:
# 获取 PR #123 的 diff 内容
gitlink-cli pr +diff --id 123 --format json
返回结果:
{
"ok": true,
"data": {
"diff": "diff --git a/src/auth/login.go b/src/auth/login.go\nindex 1234567..abcdefg 100644\n--- a/src/auth/login.go\n+++ b/src/auth/login.go\n@@ -1,10 +1,15 @@\n package auth\n\n+func login(username, password string) error {\n+\tdb, _ := sql.Open(\"mysql\", dsn)\n+\tquery := \"SELECT * FROM users WHERE username = '\" + username + \"'\"\n+\t...\n+}\n",
"files_count": 3,
"additions": 135,
"deletions": 22
}
}
diff 格式说明:
- 标准 unified diff 格式
- 包含文件头、变更块、代码行
+表示新增行-表示删除行
步骤 4:数据预处理
目的: 清理和组织数据,为 AI 分析做准备。
4.1 过滤无关文件
需要过滤的文件类型:
- 二进制文件(图片、字体、压缩包)
- 配置文件(package.json、tsconfig.json)
- 文档文件(README.md、CHANGELOG.md)
- 测试文件(_test.go、.spec.js)
过滤规则:
const shouldSkip = (filename) => {
// 跳过二进制文件
const binaryExts = ['.png', '.jpg', '.gif', '.pdf', '.zip', '.exe'];
if (binaryExts.some(ext => filename.endsWith(ext))) {
return true;
}
// 跳过配置文件
const configFiles = ['package.json', 'tsconfig.json', '.gitignore'];
if (configFiles.includes(filename)) {
return true;
}
// 跳过文档文件
if (filename.match(/^(README|CHANGELOG|CONTRIBUTING)\.md$/i)) {
return true;
}
return false;
};
4.2 提取代码片段
目的: 从 diff 中提取变更的代码片段,便于 AI 分析。
示例:
const extractCodeSnippets = (diff) => {
const lines = diff.split('\n');
const snippets = [];
let currentSnippet = [];
let inHunk = false;
lines.forEach(line => {
if (line.startsWith('@@')) {
// 开始新的代码块
if (currentSnippet.length > 0) {
snippets.push(currentSnippet.join('\n'));
}
currentSnippet = [line];
inHunk = true;
} else if (inHunk && (line.startsWith('+') || line.startsWith('-') || line.startsWith(' '))) {
// 收集代码行
currentSnippet.push(line);
}
});
if (currentSnippet.length > 0) {
snippets.push(currentSnippet.join('\n'));
}
return snippets;
};
4.3 组织分析数据
最终数据结构:
{
"pr_info": {
"id": 123,
"title": "Feature: Add user authentication",
"author": "developer",
"branch": "feature/auth → main"
},
"files": [
{
"filename": "src/auth/login.go",
"status": "modified",
"language": "go",
"code_snippets": [
{
"start_line": 10,
"end_line": 25,
"code": "+func login(username, password string) error {"
}
]
}
],
"statistics": {
"total_files": 3,
"code_files": 2,
"total_additions": 135,
"total_deletions": 22
}
}
💡 最佳实践
1. 按文件类型分组
将变更文件按语言和类型分组,便于针对性分析:
const groupFilesByLanguage = (files) => {
const groups = {
go: [],
javascript: [],
python: [],
other: []
};
files.forEach(file => {
const ext = file.filename.split('.').pop();
const lang = detectLanguage(ext);
groups[lang].push(file);
});
return groups;
};
2. 优先审查核心文件
优先审查核心业务逻辑文件:
const prioritizeFiles = (files) => {
const priority = {
'high': [], // 核心业务逻辑
'medium': [], // 工具函数
'low': [] // 配置、测试
};
files.forEach(file => {
if (file.filename.includes('core') || file.filename.includes('service')) {
priority.high.push(file);
} else if (file.filename.includes('util') || file.filename.includes('helper')) {
priority.medium.push(file);
} else {
priority.low.push(file);
}
});
return priority;
};
3. 限制分析范围
对于大型 PR,限制分析范围:
const limitAnalysisScope = (files, maxFiles = 10, maxLines = 1000) => {
let totalLines = 0;
const selectedFiles = [];
for (const file of files) {
if (selectedFiles.length >= maxFiles) break;
if (totalLines + file.changes > maxLines) break;
selectedFiles.push(file);
totalLines += file.changes;
}
return selectedFiles;
};
🔍 常见问题
Q: 如何处理大型 PR?
A: 大型 PR(>1000 行)建议:
- 按模块分组分析
- 优先审查核心文件
- 分批生成审查报告
- 建议作者拆分为多个小 PR
Q: 如何处理重命名文件?
A: GitLink 的 PR API 会正确处理重命名:
status为renamedpatch包含重命名前后的完整路径- 分析时使用新文件名
Q: 如何检测文件语言?
A: 使用文件扩展名检测:
const detectLanguage = (filename) => {
const ext = filename.split('.').pop();
const languageMap = {
'go': 'go',
'js': 'javascript',
'ts': 'typescript',
'py': 'python',
'java': 'java',
'rb': 'ruby',
'php': 'php'
};
return languageMap[ext] || 'other';
};
📚 相关文档
最后更新: 2026-06-12