Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
195 changes: 54 additions & 141 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,193 +1,106 @@
<div align="center">

# ai-commit

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Python](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/)
[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit)](https://pre-commit.com/)
[![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-%23FE5196?logo=conventionalcommits)](https://conventionalcommits.org/)
Zero-dependency Git prepare-commit-msg hook for Conventional Commits via any OpenAI-compatible API.

[![CI](https://github.com/mcocdaa/ai-commit/actions/workflows/ci.yml/badge.svg)](https://github.com/mcocdaa/ai-commit/actions/workflows/ci.yml)
[![Latest Release](https://img.shields.io/github/v/release/mcocdaa/ai-commit?color=blue&label=latest%20release)](https://github.com/mcocdaa/ai-commit/releases/latest)
[![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/)
[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit)](https://pre-commit.com/)
[![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-%23FE5196?logo=conventionalcommits)](https://conventionalcommits.org/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

### 🎬 Live Demo

<p align="center">
<img src="docs/assets/demo_commit.gif" alt="ai-commit Live Demo" width="820">
</p>
[English](README.md) · [简体中文](README_CN.md)

AI-powered Git commit message generator hook. Generates [Conventional Commits](https://www.conventionalcommits.org/) messages using any OpenAI-compatible API.
<img src="docs/assets/demo_commit.gif" alt="ai-commit demo" width="840">

**Zero external dependencies** — uses only Python standard library (`json`, `urllib`, `subprocess`, `fnmatch`).
</div>

## Features
## ✨ Highlights

- Generates Conventional Commits format messages from your staged diff
- Works with any OpenAI-compatible API (DeepSeek, OpenAI, etc.)
- **Zero external dependencies** — pure Python standard library
- Respects `.opencommitignore` for excluding files from diff analysis
- Abbreviates large diffs (configurable threshold, default 1000 lines)
- Multi-language support (en, zh, zh-TW, ja, ko)
- Graceful degradation: if AI fails, your commit still proceeds
- `git commit` → AI generates the full message
- `git commit -m "aaa"` → AI appends details after your message "aaa"
- Native Windows support (no WSL required)
- Debug mode with full pipeline visibility (`verbose: true` in pre-commit config)
- **Zero Third-Party Dependencies** — Powered strictly by the Python 3.9+ standard library (`json`, `urllib`, `subprocess`, `fnmatch`) with no external `pip` packages required.
- **Seamless `prepare-commit-msg` Workflow** — Generates full [Conventional Commits](https://www.conventionalcommits.org/) messages on `git commit`, or appends structured details when you run `git commit -m "summary"`.
- **Smart Diff Compression & `.opencommitignore` Filtering** — Automatically excludes lockfiles, minified bundles, and custom `.opencommitignore` patterns while truncating oversized diffs to stay within token budgets.
- **Universal OpenAI-Compatible Support** — Works out of the box with DeepSeek, OpenAI, Ollama, vLLM, and any `/v1/chat/completions` endpoint.
- **Multi-Language Output** — Supports commit generation in English (`en`), Simplified/Traditional Chinese (`zh`, `zh-TW`), Japanese (`ja`), and Korean (`ko`).
- **Graceful Fallback** — Never blocks your Git workflow; if the network or API fails, your commit proceeds normally.

## Quick Start
## 🚀 Quick Start

### Via pre-commit Framework (Recommended)
### 1. Configure `pre-commit`

1. Install [pre-commit](https://pre-commit.com/): `pip install pre-commit`
2. Add to your `.pre-commit-config.yaml`:
Add `ai-commit` to your `.pre-commit-config.yaml` and install the `prepare-commit-msg` hook:

```yaml
repos:
- repo: https://github.com/mcocdaa/ai-commit.git
rev: main # or specify the latest release tag (see badge above)
rev: v1.0.0 # Run `pre-commit autoupdate` for the latest release
hooks:
- id: ai-commit
```

> 💡 **Tip — Always stay on the latest version**:
> - Run `pre-commit autoupdate` anytime to automatically update `ai-commit` to the latest release tag.
> - Or use `rev: main` if you prefer to automatically track the newest changes on `main`.

3. Install the hook:

```bash
pip install pre-commit
pre-commit install --hook-type prepare-commit-msg
```

> **Tip**: If you also ran `pre-commit install` (without `--hook-type`), other hooks may run twice. Add `default_stages: [pre-commit]` at the top of your `.pre-commit-config.yaml` to prevent this. ai-commit's own `stages: [prepare-commit-msg]` is defined in the hook and is not affected.
### 2. Set Your API Key & Commit

### Local / Testing
```bash
export AI_COMMIT_API_KEY="sk-..."
git add -A && git commit
```

For local development or testing without a published repo:
## ⚙️ Configuration

```yaml
repos:
- repo: /path/to/ai-commit
hooks:
- id: ai-commit
```
Configure via environment variables, project `.ai-commit.json`, or global `~/.ai-commit.json` (precedence: `ENV` > `./.ai-commit.json` > `~/.ai-commit.json`):

Or use `repo: .` if the hook files are in your project root.
| Environment Variable | `.ai-commit.json` Key | Default | Description |
| :--- | :--- | :--- | :--- |
| `AI_COMMIT_API_KEY` | `api_key` | `""` | API key for the OpenAI-compatible provider |
| `AI_COMMIT_API_BASE_URL` | `api_base_url` | `https://api.deepseek.com` | Base URL for chat completions API |
| `AI_COMMIT_MODEL` | `model` | `deepseek-v4-flash` | Model identifier used for generation |
| `AI_COMMIT_LANGUAGE` | `language` | `en` | Output language (`en`, `zh`, `zh-TW`, `ja`, `ko`) |
| `AI_COMMIT_MAX_DIFF_LINES` | `max_diff_lines` | `1000` | Max diff lines per file before abbreviation |
| `AI_COMMIT_MAX_OUTPUT_TOKENS` | `max_output_tokens` | `2048` | Max tokens for generated response |
| `AI_COMMIT_IGNORE_FILE` | `ignore_file` | `.opencommitignore` | Ignore file for excluding paths from diff analysis |
| `AI_COMMIT_THINKING` | `thinking` | `false` | Enable/disable reasoning mode on DeepSeek models |
| `AI_COMMIT_DEBUG` | `debug` | `false` | Print diagnostic pipeline logs to `stderr` |

## Configuration
<details>
<summary><b>Advanced Configuration & Troubleshooting</b></summary>

Create `.ai-commit.json` in your project root (or `~/.ai-commit.json` for global):
### Example `.ai-commit.json`

```json
{
"api_key": "",
"api_base_url": "https://api.deepseek.com",
"model": "deepseek-v4-flash",
"max_diff_lines": 1000,
"max_output_tokens": 2048,
"debug": false,
"language": "en",
"ignore_file": ".opencommitignore",
"thinking": false
}
```

### Config Priority
### Custom Ignore Rules (`.opencommitignore`)

Environment variables > project `.ai-commit.json` > global `~/.ai-commit.json`
Lockfiles (`uv.lock`, `package-lock.json`, `pnpm-lock.yaml`, `Cargo.lock`, `poetry.lock`) and `*.min.js` / `*.min.css` are ignored by default. Add custom `.gitignore`-style patterns in `.opencommitignore`:

| Config Key | Env Variable | Default |
|---|---|---|
| `api_key` | `AI_COMMIT_API_KEY` | `""` |
| `api_base_url` | `AI_COMMIT_API_BASE_URL` | `https://api.deepseek.com` |
| `model` | `AI_COMMIT_MODEL` | `deepseek-v4-flash` |
| `max_diff_lines` | `AI_COMMIT_MAX_DIFF_LINES` | `1000` |
| `max_output_tokens` | `AI_COMMIT_MAX_OUTPUT_TOKENS` | `2048` |
| `debug` | `AI_COMMIT_DEBUG` | `false` |
| `language` | `AI_COMMIT_LANGUAGE` | `en` |
| `ignore_file` | `AI_COMMIT_IGNORE_FILE` | `.opencommitignore` |
| `thinking` | `AI_COMMIT_THINKING` | `false` |

### API Key Security

- **Recommended**: Set `AI_COMMIT_API_KEY` environment variable
- **Per-project**: Use `.ai-commit.json` (auto-added to `.gitignore`)
- **Global**: Use `~/.ai-commit.json` with restricted permissions
- **Never** commit API keys to version control

### .opencommitignore

Exclude files from diff analysis:

```
```gitignore
*.md
package-lock.json
dist/
fixtures/*.json
```

### Debug Mode

Set `debug: true` in `.ai-commit.json` or `AI_COMMIT_DEBUG=true` env var. To see debug output during `git commit`, add `verbose: true` to the hook config:

```yaml
repos:
- repo: https://github.com/mcocdaa/ai-commit.git
rev: main
hooks:
- id: ai-commit
verbose: true
```

### Thinking Mode (DeepSeek)

DeepSeek V4 models support a reasoning/thinking mode (`deepseek-v4-flash`, `deepseek-v4-pro`, etc.). Set `thinking: true` to enable it, or `thinking: false` for standard chat mode:

```json
{
"thinking": false
}
```

When thinking is disabled, the model outputs the commit message directly without intermediate reasoning. This reduces token usage and response time. Use `thinking: false` if you encounter empty responses from the AI (reasoning consumed all output tokens before the model could write the commit message).

## Dependencies

- **Python 3.9+** — No pip packages required
- **Git** — Obviously

## File Structure

```
ai-commit/
├── prepare_commit_msg_hooks/
│ ├── __init__.py
│ ├── ai_commit_gen.py # Entry point & orchestration
│ └── util/
│ ├── __init__.py
│ ├── api.py # OpenAI-compatible API client
│ ├── config.py # Configuration & constants
│ ├── diff_processor.py # Diff filtering & abbreviation
│ ├── git_util.py # Git subprocess wrappers
│ └── gitignore.py # .gitignore-style pattern matching
├── .pre-commit-hooks.yaml # pre-commit framework hook definition
├── setup.py # Editable install stub
├── pyproject.toml # Package metadata, build & tool config
├── tests/
│ └── test_ai_commit_gen.py # Pytest test suite (24 tests)
├── README.md # This file
├── AGENTS.md # AI agent integration guide
├── LICENSE # MIT License
└── .ai-commit.json # Configuration (gitignored)
```
### Debugging & Pre-Commit Hook Stages

## How It Works
- **Verbose Hook Output**: Set `AI_COMMIT_DEBUG=true` and add `verbose: true` under `- id: ai-commit` in `.pre-commit-config.yaml` to inspect diff filtering and API payloads.
- **Avoid Duplicate Hook Runs**: If you use both `pre-commit` and `prepare-commit-msg` hooks, add `default_stages: [pre-commit]` at the top of `.pre-commit-config.yaml`.

1. The `prepare-commit-msg` hook is triggered by Git before the editor opens
2. The script reads staged diff via `git diff --cached`
3. Files matching `.opencommitignore` patterns are excluded
4. Large diffs (per `max_diff_lines`) are abbreviated
5. The diff + file summary is sent to the OpenAI-compatible chat completions API
6. The generated commit message is written to the commit message file
7. If `git commit -m "..."` was used, AI appends after your message
8. If AI fails for any reason, the commit proceeds normally
</details>

## License
## 📄 License

MIT
Released under the [MIT License](LICENSE).
106 changes: 106 additions & 0 deletions README_CN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<div align="center">

# ai-commit

零外部依赖、支持任意 OpenAI 兼容接口的 Git Conventional Commits 自动生成钩子。

[![CI](https://github.com/mcocdaa/ai-commit/actions/workflows/ci.yml/badge.svg)](https://github.com/mcocdaa/ai-commit/actions/workflows/ci.yml)
[![Latest Release](https://img.shields.io/github/v/release/mcocdaa/ai-commit?color=blue&label=latest%20release)](https://github.com/mcocdaa/ai-commit/releases/latest)
[![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/)
[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit)](https://pre-commit.com/)
[![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-%23FE5196?logo=conventionalcommits)](https://conventionalcommits.org/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

[English](README.md) · [简体中文](README_CN.md)

<img src="docs/assets/demo_commit.gif" alt="ai-commit demo" width="840">

</div>

## ✨ 核心特性

- **零第三方依赖** — 仅使用 Python 3.9+ 标准库(`json`、`urllib`、`subprocess`、`fnmatch`),无需安装任何额外 `pip` 依赖包。
- **无缝融入 Git 工作流** — 基于 `prepare-commit-msg` 钩子:直接运行 `git commit` 自动生成完整 [Conventional Commits](https://www.conventionalcommits.org/) 提交信息;使用 `git commit -m "摘要"` 时自动在摘要后追加结构化变更详情。
- **智能 Diff 压缩与 `.opencommitignore` 过滤** — 自动剔除各类 Lockfile、压缩产物及 `.opencommitignore` 匹配文件,并对超大 Diff 智能截断以控制 Token 消耗。
- **通用 OpenAI 兼容接口支持** — 开箱即用支持 DeepSeek、OpenAI、Ollama、vLLM 等任意兼容 `/v1/chat/completions` 的服务。
- **多语言生成** — 支持英文(`en`)、简体/繁体中文(`zh`、`zh-TW`)、日文(`ja`)与韩文(`ko`)提交信息。
- **优雅降级** — 绝不阻塞提交流程;若网络超时或 API 调用失败,Git 提交将静默回退并正常继续。

## 🚀 快速开始

### 1. 配置 `pre-commit`

在项目的 `.pre-commit-config.yaml` 中添加 `ai-commit` 并安装 `prepare-commit-msg` 钩子:

```yaml
repos:
- repo: https://github.com/mcocdaa/ai-commit.git
rev: v1.0.0 # 可运行 `pre-commit autoupdate` 自动更新至最新版本
hooks:
- id: ai-commit
```

```bash
pip install pre-commit
pre-commit install --hook-type prepare-commit-msg
```

### 2. 配置 API Key 并提交

```bash
export AI_COMMIT_API_KEY="sk-..."
git add -A && git commit
```

## ⚙️ 配置说明

支持通过环境变量、项目根目录 `.ai-commit.json` 或全局 `~/.ai-commit.json` 配置(优先级:`环境变量` > `./.ai-commit.json` > `~/.ai-commit.json`):

| 环境变量 | `.ai-commit.json` 键名 | 默认值 | 说明 |
| :--- | :--- | :--- | :--- |
| `AI_COMMIT_API_KEY` | `api_key` | `""` | OpenAI 兼容接口的 API Key |
| `AI_COMMIT_API_BASE_URL` | `api_base_url` | `https://api.deepseek.com` | Chat Completions 接口基础地址 |
| `AI_COMMIT_MODEL` | `model` | `deepseek-v4-flash` | 用于生成提交信息的模型名称 |
| `AI_COMMIT_LANGUAGE` | `language` | `en` | 输出语言(`en`、`zh`、`zh-TW`、`ja`、`ko`) |
| `AI_COMMIT_MAX_DIFF_LINES` | `max_diff_lines` | `1000` | 单文件 Diff 触发缩写的最大行数阈值 |
| `AI_COMMIT_MAX_OUTPUT_TOKENS` | `max_output_tokens` | `2048` | 模型输出的最大 Token 数 |
| `AI_COMMIT_IGNORE_FILE` | `ignore_file` | `.opencommitignore` | 排除 Diff 分析的忽略规则文件名 |
| `AI_COMMIT_THINKING` | `thinking` | `false` | 是否开启 DeepSeek 模型的思考/推理模式 |
| `AI_COMMIT_DEBUG` | `debug` | `false` | 是否向 `stderr` 输出调试日志 |

<details>
<summary><b>高级配置与常见问题排查</b></summary>

### `.ai-commit.json` 配置示例

```json
{
"api_base_url": "https://api.deepseek.com",
"model": "deepseek-v4-flash",
"max_diff_lines": 1000,
"language": "zh",
"ignore_file": ".opencommitignore",
"thinking": false
}
```

### 自定义忽略规则(`.opencommitignore`)

默认已忽略常见锁文件(`uv.lock`、`package-lock.json`、`pnpm-lock.yaml`、`Cargo.lock`、`poetry.lock`)与 `*.min.js` / `*.min.css`。可在项目根目录创建 `.opencommitignore` 添加自定义规则:

```gitignore
*.md
dist/
fixtures/*.json
```

### 调试模式与钩子阶段配置

- **查看详细调试输出**:设置 `AI_COMMIT_DEBUG=true`,并在 `.pre-commit-config.yaml` 的 `- id: ai-commit` 下添加 `verbose: true` 即可在提交时查看完整流水线日志。
- **避免其他钩子重复执行**:若同时安装了 `pre-commit` 与 `prepare-commit-msg` 钩子,建议在 `.pre-commit-config.yaml` 顶部添加 `default_stages: [pre-commit]`。

</details>

## 📄 License

本项目基于 [MIT License](LICENSE) 开源。
Loading