gitlink-cli/skills/gitlink-code-review/references/code-review-analyze.md

404 lines
8.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 代码变更分析
本文档详细说明如何使用 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 的元数据信息。
**命令**:
```bash
gitlink-cli pr +view --id <pr_id> --format json
```
**示例**:
```bash
# 获取 PR #123 的基本信息
gitlink-cli pr +view --id 123 --format json
```
**返回结果**:
```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 中所有变更的文件列表,了解代码变更的范围。
**命令**:
```bash
gitlink-cli pr +files --id <pr_id> --format json
```
**示例**:
```bash
# 获取 PR #123 的变更文件列表
gitlink-cli pr +files --id 123 --format json
```
**返回结果**:
```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 代码分析。
**命令**:
```bash
gitlink-cli pr +diff --id <pr_id> --format json
```
**示例**:
```bash
# 获取 PR #123 的 diff 内容
gitlink-cli pr +diff --id 123 --format json
```
**返回结果**:
```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
**过滤规则**:
```javascript
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 分析。
**示例**:
```javascript
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 组织分析数据
**最终数据结构**:
```json
{
"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. 按文件类型分组
将变更文件按语言和类型分组,便于针对性分析:
```javascript
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. 优先审查核心文件
优先审查核心业务逻辑文件:
```javascript
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限制分析范围
```javascript
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 行)建议:
1. 按模块分组分析
2. 优先审查核心文件
3. 分批生成审查报告
4. 建议作者拆分为多个小 PR
### Q: 如何处理重命名文件?
**A**: GitLink 的 PR API 会正确处理重命名:
- `status``renamed`
- `patch` 包含重命名前后的完整路径
- 分析时使用新文件名
### Q: 如何检测文件语言?
**A**: 使用文件扩展名检测:
```javascript
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';
};
```
## 📚 相关文档
- [代码质量检查](code-review-quality.md) - 代码质量分析
- [安全性检查](code-review-security.md) - 安全性分析
- [性能检查](code-review-performance.md) - 性能分析
- [完整工作流](../examples/comprehensive-review-workflow.md) - 完整审查流程
---
*最后更新: 2026-06-12*