git-yike-logger-hook
Version:
A TypeScript Git hook plugin for automatically generating commit logs with TODO/WIP comment scanning
790 lines (612 loc) • 18.5 kB
Markdown
# Git Logger Hook
一个用 TypeScript 编写的 Git hook 插件,用于在每次 commit 时自动生成详细的提交日志,并扫描代码中的 TODO 和 WIP 注释。
## 📋 目录
- [功能特性](#功能特性)
- [开发思路](#开发思路)
- [技术架构](#技术架构)
- [依赖说明](#依赖说明)
- [模块详解](#模块详解)
- [快速开始](#快速开始)
- [配置选项](#配置选项)
- [日志格式](#日志格式)
- [注释扫描功能](#注释扫描功能)
- [API 文档](#api-文档)
- [开发指南](#开发指南)
- [故障排除](#故障排除)
- [许可证](#许可证)
## 功能特性
- 🔍 **自动记录提交信息**:记录提交人、提交时间、提交消息和提交哈希
- 📁 **文件变更跟踪**:详细记录新增、修改、删除和重命名的文件
- 🌿 **分支信息**:记录当前分支和远程仓库信息
- 💬 **代码注释扫描**:自动扫描 JavaScript/TypeScript 文件中的 TODO 和 WIP 注释
- 📊 **JSON 格式**:结构化的 JSON 日志,便于后续处理和分析
- 🧹 **自动清理**:可配置保留最近 N 个日志文件
- ⚙️ **易于配置**:支持自定义日志目录和文件过滤
- 🚀 **零配置启动**:安装后即可使用,无需额外配置
## 开发思路
### 核心设计理念
1. **自动化优先**:通过 Git hook 机制实现完全自动化的日志记录
2. **最小侵入性**:不影响现有开发流程,透明地记录信息
3. **结构化数据**:使用 JSON 格式便于后续分析和处理
4. **可扩展性**:模块化设计,易于添加新功能
### 技术选型理由
- **TypeScript**:提供类型安全,减少运行时错误
- **simple-git**:简化 Git 操作,避免直接调用 Git 命令
- **Node.js**:跨平台支持,与 Git 生态良好集成
- **Git Hooks**:利用 Git 原生机制,无需额外工具
### 工作流程
```mermaid
graph TD
A[开发者执行 git commit] --> B[触发 pre-commit hook]
B --> C[GitLogger 开始工作]
C --> D[获取提交信息]
D --> E[获取文件变更]
E --> F[扫描代码注释]
F --> G[生成 JSON 日志]
G --> H[保存到 .git-logs 目录]
H --> I[提交继续执行]
```
## 技术架构
### 整体架构图
```mermaid
graph TB
subgraph "Git Hook 层"
A[pre-commit hook] --> B[hook.ts]
end
subgraph "核心模块"
B --> C[GitLogger]
C --> D[GitUtils]
C --> E[CommentScanner]
end
subgraph "数据层"
D --> F[Git 仓库]
E --> G[JavaScript/TypeScript 文件]
C --> H[JSON 日志文件]
end
subgraph "类型系统"
I[types.ts] --> C
I --> D
I --> E
end
```
### 模块依赖关系
- `hook.ts` → `GitLogger` → `GitUtils` + `CommentScanner`
- 所有模块都依赖 `types.ts` 进行类型定义
- `install.ts` 独立运行,负责 Git hook 的安装和卸载
## 依赖说明
### 核心依赖
| 依赖 | 版本 | 作用 | 选择理由 |
|------|------|------|----------|
| `simple-git` | ^3.19.0 | Git 操作封装 | 简化 Git 命令调用,提供 Promise 接口 |
| `@types/node` | ^20.0.0 | Node.js 类型定义 | 提供 Node.js API 的类型支持 |
| `typescript` | ^5.0.0 | TypeScript 编译器 | 编译 TypeScript 代码 |
### 依赖作用详解
#### simple-git
```typescript
// 示例:获取提交信息
const git = simpleGit();
const log = await git.log({ maxCount: 1 });
const commit = log.latest;
```
**为什么选择 simple-git?**
- 提供统一的 Promise 接口
- 自动处理 Git 命令的复杂参数
- 内置错误处理和重试机制
- 支持所有主流 Git 操作
#### TypeScript
- 提供编译时类型检查
- 增强代码可读性和维护性
- 提供智能代码补全和重构支持
## 模块详解
### 核心模块
#### 1. `types.ts` - 类型定义模块
```typescript
// 核心数据结构定义
export interface CommitLog { ... }
export interface CodeComment { ... }
export interface GitStatus { ... }
export interface LoggerConfig { ... }
```
**作用:**
- 定义所有模块使用的数据结构
- 提供类型安全保障
- 作为模块间的契约
**关键点:**
- 使用接口而非类型别名,便于扩展
- 所有字段都有明确的注释说明
- 支持可选字段,增强灵活性
#### 2. `git-utils.ts` - Git 操作工具类
```typescript
export class GitUtils {
async getCurrentCommitInfo(): Promise<Partial<CommitLog>>
async getCurrentBranch(): Promise<string>
async getRemoteInfo(): Promise<{ name: string; url: string } | undefined>
async getFileChanges(): Promise<{ added: string[]; modified: string[]; ... }>
}
```
**作用:**
- 封装所有 Git 相关操作
- 提供统一的错误处理
- 处理首次提交等边界情况
**关键点:**
- 使用 simple-git 简化 Git 操作
- 完善的错误处理和降级策略
- 支持首次提交的特殊处理
#### 3. `comment-scanner.ts` - 代码注释扫描器
```typescript
export class CommentScanner {
async scanDirectory(dirPath: string): Promise<{ todos: CodeComment[]; wips: CodeComment[] }>
async scanFile(filePath: string): Promise<{ todos: CodeComment[]; wips: CodeComment[] }>
async scanChangedFiles(changedFiles: {...}): Promise<{ todos: CodeComment[]; wips: CodeComment[] }>
}
```
**作用:**
- 扫描 JavaScript/TypeScript 文件中的注释
- 支持多种注释格式(单行、多行、@todo、@wip 等)
- 智能过滤文件类型和目录
**关键点:**
- 使用正则表达式匹配注释模式
- 支持多种文件扩展名
- 自动跳过 node_modules 等目录
- 提供精确的行号和文件路径信息
#### 4. `logger.ts` - 日志生成器(核心模块)
```typescript
export class GitLogger {
constructor(config: Partial<LoggerConfig> = {})
async generateLog(): Promise<void>
async getAllLogs(): Promise<CommitLog[]>
async cleanupLogs(keepCount: number): Promise<void>
}
```
**作用:**
- 协调各个模块完成日志生成
- 管理日志文件的存储和清理
- 提供统一的配置接口
**关键点:**
- 组合模式:协调 GitUtils 和 CommentScanner
- 异步处理:所有操作都是异步的
- 错误处理:完善的错误处理和用户提示
- 文件管理:自动创建目录和清理旧文件
#### 5. `hook.ts` - Git Hook 入口点
```typescript
#!/usr/bin/env node
async function main() {
const logger = new GitLogger();
await logger.generateLog();
await logger.cleanupLogs(100);
}
```
**作用:**
- 作为 Git hook 的入口点
- 处理命令行参数
- 提供用户友好的输出
**关键点:**
- 使用 shebang 支持直接执行
- 完善的错误处理和退出码
- 清晰的用户反馈
#### 6. `install.ts` - Hook 安装器
```typescript
export class HookInstaller {
async install(): Promise<void>
async uninstall(): Promise<void>
private createPreCommitHook(): void
private createPostCommitHook(): void
}
```
**作用:**
- 自动安装和卸载 Git hooks
- 生成跨平台的 hook 脚本
- 验证 Git 仓库环境
**关键点:**
- 跨平台支持(Windows/Unix)
- 自动检测 Git 仓库
- 生成可执行的 hook 脚本
### 辅助模块
#### `index.ts` - 模块导出
```typescript
export { GitLogger } from './logger';
export { GitUtils } from './git-utils';
export { CommentScanner } from './comment-scanner';
export { CommitLog, GitStatus, LoggerConfig, CodeComment } from './types';
```
**作用:**
- 提供统一的模块导出接口
- 简化外部使用
- 支持默认导出
## 快速开始
### 1. 安装依赖
```bash
npm install
```
### 2. 编译项目
```bash
npm run build
```
### 3. 安装 Git Hook
```bash
npm run install-hook
```
### 4. 开始使用
现在每次执行 `git commit` 时,插件会自动在 `.git-logs` 目录中生成一个 JSON 日志文件。
## 日志格式
生成的日志文件格式如下:
```json
{
"author": {
"name": "用户名",
"email": "user@example.com"
},
"timestamp": "2024-01-01T12:00:00.000Z",
"message": "提交信息",
"commitHash": "abc123def456...",
"changedFiles": {
"added": ["新文件1.js", "新文件2.ts"],
"modified": ["修改的文件.js"],
"deleted": ["删除的文件.js"],
"renamed": [
{
"from": "旧文件名.js",
"to": "新文件名.js"
}
]
},
"branch": "main",
"remote": {
"name": "origin",
"url": "https://github.com/user/repo.git"
},
"comments": {
"todos": [
{
"type": "TODO",
"content": "实现这个功能",
"filePath": "src/example.js",
"lineNumber": 10,
"fullLine": "// TODO: 实现这个功能"
}
],
"wips": [
{
"type": "WIP",
"content": "这个功能还在开发中",
"filePath": "src/example.js",
"lineNumber": 15,
"fullLine": "// WIP: 这个功能还在开发中"
}
]
}
}
```
## 配置选项
可以通过修改 `src/logger.ts` 中的配置来自定义行为:
```typescript
const logger = new GitLogger({
logDir: '.git-logs', // 日志文件保存目录
includeUnstaged: false, // 是否包含未暂存的更改
includeUntracked: false, // 是否包含未跟踪的文件
filePatterns: ['*.js', '*.ts'], // 文件过滤模式(可选)
});
```
## 可用脚本
- `npm run build` - 编译 TypeScript 代码
- `npm run dev` - 监听模式编译
- `npm run install-hook` - 安装 Git hook
- `node dist/install.js uninstall` - 卸载 Git hook
## 项目结构
```
src/
├── index.ts # 主入口文件
├── types.ts # TypeScript 类型定义
├── git-utils.ts # Git 操作工具类
├── comment-scanner.ts # 代码注释扫描器
├── logger.ts # 日志生成器
├── hook.ts # Git hook 入口点
└── install.ts # Hook 安装器
```
## 日志文件命名
日志文件按以下格式命名:
```
YYYY-MM-DD_HH-MM-SS_<commit-hash>.json
```
例如:`2024-01-01_12-30-45_abc12345.json`
## 自动清理
插件会自动保留最近的 100 个日志文件,超出部分会被自动删除。可以通过修改 `logger.ts` 中的 `cleanupLogs(100)` 来调整保留数量。
## 卸载
如果需要卸载 Git hook:
```bash
node dist/install.js uninstall
```
## API 文档
### GitLogger 类
#### 构造函数
```typescript
constructor(config?: Partial<LoggerConfig>)
```
**参数:**
- `config` (可选): 配置选项,支持以下属性:
- `logDir`: 日志文件保存目录,默认 `.git-logs`
- `includeUnstaged`: 是否包含未暂存的更改,默认 `false`
- `includeUntracked`: 是否包含未跟踪的文件,默认 `false`
- `filePatterns`: 文件过滤模式,默认 `undefined`
#### 方法
##### generateLog()
```typescript
async generateLog(): Promise<void>
```
生成并保存当前提交的日志。
**返回值:** `Promise<void>`
**异常:**
- 如果不在 Git 仓库中,抛出错误
- 如果无法获取提交信息,抛出错误
##### getAllLogs()
```typescript
async getAllLogs(): Promise<CommitLog[]>
```
获取所有日志文件。
**返回值:** `Promise<CommitLog[]>` - 按时间倒序排列的日志数组
##### cleanupLogs()
```typescript
async cleanupLogs(keepCount: number): Promise<void>
```
清理旧日志文件。
**参数:**
- `keepCount`: 保留的日志文件数量
**返回值:** `Promise<void>`
### GitUtils 类
#### 方法
##### getCurrentCommitInfo()
```typescript
async getCurrentCommitInfo(): Promise<Partial<CommitLog>>
```
获取当前提交信息。
**返回值:** `Promise<Partial<CommitLog>>` - 包含提交人、时间、消息、哈希等信息
##### getCurrentBranch()
```typescript
async getCurrentBranch(): Promise<string>
```
获取当前分支名称。
**返回值:** `Promise<string>` - 分支名称,如果无法获取则返回 'unknown'
##### getFileChanges()
```typescript
async getFileChanges(): Promise<{
added: string[];
modified: string[];
deleted: string[];
renamed: Array<{ from: string; to: string }>;
}>
```
获取文件变更信息。
**返回值:** 包含新增、修改、删除、重命名文件的对象
### CommentScanner 类
#### 方法
##### scanDirectory()
```typescript
async scanDirectory(dirPath: string): Promise<{
todos: CodeComment[];
wips: CodeComment[];
}>
```
扫描目录下所有 JavaScript/TypeScript 文件。
**参数:**
- `dirPath`: 要扫描的目录路径
**返回值:** 包含 TODO 和 WIP 注释的对象
##### scanFile()
```typescript
async scanFile(filePath: string): Promise<{
todos: CodeComment[];
wips: CodeComment[];
}>
```
扫描单个文件。
**参数:**
- `filePath`: 文件路径
**返回值:** 包含 TODO 和 WIP 注释的对象
##### scanChangedFiles()
```typescript
async scanChangedFiles(changedFiles: {
added: string[];
modified: string[];
deleted: string[];
}): Promise<{
todos: CodeComment[];
wips: CodeComment[];
}>
```
扫描变更的文件。
**参数:**
- `changedFiles`: 变更文件列表
**返回值:** 包含 TODO 和 WIP 注释的对象
## 开发指南
### 环境要求
- Node.js >= 16.0.0
- Git >= 2.0.0
- TypeScript >= 5.0.0
### 开发环境设置
1. **克隆项目**
```bash
git clone <repository-url>
cd git-logger-hook
```
2. **安装依赖**
```bash
npm install
```
3. **编译项目**
```bash
npm run build
```
4. **开发模式**
```bash
npm run dev # 监听模式编译
```
### 添加新功能
#### 1. 添加新的注释类型
在 `src/comment-scanner.ts` 中添加新的正则表达式模式:
```typescript
private newCommentPatterns = [
/\/\/\s*FIXME\s*:?\s*(.+)/gi,
/\/\*\s*FIXME\s*:?\s*(.+?)\s*\*\//gi
];
```
#### 2. 扩展日志数据结构
在 `src/types.ts` 中添加新的字段:
```typescript
export interface CommitLog {
// ... 现有字段
newField?: string; // 新字段
}
```
#### 3. 添加新的 Git 操作
在 `src/git-utils.ts` 中添加新方法:
```typescript
async getNewGitInfo(): Promise<any> {
// 实现新的 Git 操作
}
```
### 测试
#### 单元测试
```bash
# 运行测试(需要先配置测试框架)
npm test
```
#### 集成测试
```bash
# 创建测试提交
git add .
git commit -m "测试提交"
```
#### 手动测试
```bash
# 直接运行 hook
node dist/hook.js
```
### 调试
#### 启用详细日志
```typescript
// 在 logger.ts 中添加
console.log('调试信息:', data);
```
#### 检查 Git Hook
```bash
# 查看 pre-commit hook 内容
cat .git/hooks/pre-commit
```
#### 检查日志文件
```bash
# 查看最新日志
ls -la .git-logs/
cat .git-logs/最新日志文件.json
```
### 性能优化
#### 1. 文件扫描优化
- 只扫描变更的文件,不扫描整个项目
- 使用文件扩展名过滤,减少不必要的文件读取
- 跳过 node_modules 等大型目录
#### 2. 内存优化
- 及时清理旧日志文件
- 使用流式处理大文件
- 避免在内存中保存大量数据
#### 3. 错误处理
- 提供降级策略
- 记录详细的错误信息
- 避免因单个文件错误导致整个流程失败
## 故障排除
### 常见问题
#### 1. Hook 不执行
**症状:** 提交时没有生成日志文件
**解决方案:**
```bash
# 检查 hook 是否存在
ls -la .git/hooks/pre-commit
# 重新安装 hook
node dist/install.js install
# 检查 hook 权限(Unix 系统)
chmod +x .git/hooks/pre-commit
```
#### 2. 编译错误
**症状:** `npm run build` 失败
**解决方案:**
```bash
# 清理并重新安装依赖
rm -rf node_modules package-lock.json
npm install
# 检查 TypeScript 配置
npx tsc --noEmit
```
#### 3. 权限错误
**症状:** 无法写入日志文件
**解决方案:**
```bash
# 检查目录权限
ls -la .git-logs/
# 创建目录
mkdir -p .git-logs
chmod 755 .git-logs
```
#### 4. Git 操作失败
**症状:** 无法获取 Git 信息
**解决方案:**
```bash
# 检查是否在 Git 仓库中
git status
# 检查 Git 配置
git config --list
```
### 调试技巧
#### 1. 启用详细输出
```typescript
// 在代码中添加调试信息
console.log('当前目录:', process.cwd());
console.log('Git 状态:', await git.status());
```
#### 2. 检查环境变量
```bash
# 检查 Node.js 版本
node --version
# 检查 Git 版本
git --version
# 检查环境变量
echo $PATH
```
#### 3. 查看错误日志
```bash
# 查看 Git hook 错误
git commit -m "测试" 2>&1 | tee error.log
```
## 注释扫描功能
插件会自动扫描变更的 JavaScript/TypeScript 文件,提取以下类型的注释:
### 支持的注释格式
**TODO 注释:**
- `// TODO: 描述内容`
- `/* TODO: 描述内容 */`
- `// @todo: 描述内容`
- `/* @todo: 描述内容 */`
**WIP 注释:**
- `// WIP: 描述内容`
- `/* WIP: 描述内容 */`
- `// @wip: 描述内容`
- `/* @wip: 描述内容 */`
- `// WORK IN PROGRESS: 描述内容`
- `/* WORK IN PROGRESS: 描述内容 */`
### 支持的文件类型
- `.js` - JavaScript 文件
- `.jsx` - React JSX 文件
- `.ts` - TypeScript 文件
- `.tsx` - React TypeScript 文件
- `.vue` - Vue 单文件组件
- `.svelte` - Svelte 组件
### 注释信息结构
每个提取的注释包含:
- `type`: 注释类型(TODO 或 WIP)
- `content`: 注释内容
- `filePath`: 文件路径
- `lineNumber`: 行号
- `fullLine`: 完整的注释行
## 注意事项
1. 确保在 Git 仓库根目录中运行安装命令
2. 需要先编译项目才能使用 hook
3. 在 Windows 系统上,hook 文件会同时创建 `.sh` 和 `.cmd` 版本
4. 日志文件默认保存在 `.git-logs` 目录中,该目录已被添加到 `.gitignore`
5. 注释扫描只针对变更的文件,不会扫描整个项目
## 许可证
MIT License