开发 CLI 工具
如果追求极小的二进制体积、无依赖且执行速度极快,Node.js 确实不适合(打包后通常有几十 MB)。最佳的选择是使用 Go 或 Rust。
其中 Go 语言 是开发 CLI 工具的绝对利器,语法简单,交叉编译极强。编译后的二进制文件只有 几 MB,且压缩后能控制在 2MB-3MB 左右。
下面是使用 Go 语言 开发的完整方案。
第一步:初始化 Go 项目
确保你本地安装了 Go 环境,在空目录中运行:
bash
mkdir git-m-cli && cd git-m-cli
go mod init git-m-cli
请谨慎使用此类代码。
第二步:编写核心代码
创建 main.go 文件,写入以下代码。为了保持体积小和零第三方依赖,我们直接使用 Go 原生的 net/http 库来请求大模型。
go
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"os/exec"
"strings"
)
// 配置大模型信息(你可以直接硬编码,或者编译时注入)
const (
API_KEY = "你的_DEEPSEEK_API_KEY" // 💡 替换为你的 API Key
BASE_URL = "https://deepseek.com"
MODEL = "deepseek-chat"
)
// OpenAI/DeepSeek 请求体结构
type Message struct {
Role string `json:"role"`
Content string `json:"content"`
}
type ChatRequest struct {
Model string `json:"model"`
Messages []Message `json:"messages"`
Temperature float64 `json:"temperature"`
}
type ChatResponse struct {
Choices []struct {
Message struct {
Content string `json:"content"`
} `json:"message"`
} `json:"choices"`
}
func main() {
// 1. 获取 Git 暂存区的 Diff
diffCmd := exec.Command("git", "diff", "--cached")
var diffOut bytes.Buffer
diffCmd.Stdout = &diffOut
if err := diffCmd.Run(); err != nil {
fmt.Println("❌ 错误: 当前目录似乎不是一个 Git 仓库或没有配置 Git。")
os.Exit(1)
}
diff := strings.TrimSpace(diffOut.String())
if diff == "" {
fmt.Println("⚠️ 提示: 没有发现已暂存(Staged)的文件,请先运行 `git add` 。")
os.Exit(0)
}
// 限制 Diff 长度,防止超出 Token 限制(截取前 15000 个字符)
if len(diff) > 15000 {
diff = diff Harvey[:15000]
}
fmt.Println("🤖 正在分析暂存区代码并生成备注...")
// 2. 构造 Prompt
prompt := fmt.Sprintf(`你是一个专业的 Git 提交助手。请根据以下代码的 diff 内容,生成一条精炼、准确、结构清晰的 Git commit message。
请严格使用 Angular 规范格式(例如: feat(scope): add something 或 fix: resolve bug)。
不要输出任何解释性文本、不要包裹 markdown 代码块(如 \`\`\`),只输出 commit message 本身。
---
%s
---`, diff)
// 3. 构建 HTTP 请求
reqBody := ChatRequest{
Model: MODEL,
Messages: []Message{
{Role: "user", Content: prompt},
},
Temperature: 0.1,
}
jsonData, err := json.Marshal(reqBody)
if err != nil {
fmt.Printf("❌ 序列化失败: %v\n", err)
os.Exit(1)
}
req, err := http.NewRequest("POST", BASE_URL, bytes.NewBuffer(jsonData))
if err != nil {
fmt.Printf("❌ 创建请求失败: %v\n", err)
os.Exit(1)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+API_KEY)
// 4. 发送请求并解析
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
fmt.Printf("❌ 请求大模型失败: %v\n", err)
os.Exit(1)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
if resp.StatusCode != http.StatusOK {
fmt.Printf("❌ 接口响应错误 (状态码 %d): %s\n", resp.StatusCode, string(body))
os.Exit(1)
}
var chatResp ChatResponse
if err := json.Unmarshal(body, &chatResp); err != nil || len(chatResp.Choices) == 0 {
fmt.Println("❌ 解析大模型返回数据失败。")
os.Exit(1)
}
commitMessage := strings.TrimSpace(chatResp.Choices[0].Message.Content)
fmt.Printf("\n📝 AI 建议的备注: %s\n\n", commitMessage)
// 5. 执行真正地 Git Commit
fmt.Println("🚀 正在提交到 Git...")
commitCmd := exec.Command("git", "commit", "-m", commitMessage)
commitCmd.Stdout = os.Stdout
commitCmd.Stderr = os.Stderr
if err := commitCmd.Run(); err != nil {
fmt.Printf("❌ Git 提交失败: %v\n", err)
os.Exit(1)
}
fmt.Println("\n✅ 提交成功!")
}
请谨慎使用此类代码。
第三步:极致体积压缩编译 (关键)
Go 默认编译出来的二进制文件会包含调试信息和符号表。我们可以通过编译参数和压缩工具让体积缩减 70% 以上。
在终端运行以下编译命令:
bash
# -s -w 参数用于移除调试信息和符号表,极大缩减体积
go build -ldflags="-s -w" -o git-m
请谨慎使用此类代码。
此时编译出来的二进制文件 git-m 大概只有 5MB 左右。
进一步压榨体积(可选,推荐)
你可以使用终端著名的压缩加壳工具 UPX。如果你的电脑没有安装,可以通过包管理器安装(如 brew install upx 或 apt install upx)。
安装后对二进制文件进行压缩:
bash
upx --best git-m
请谨慎使用此类代码。
经过 UPX 压缩后,这个二进制文件会直接缩减到 1.5MB - 2.5MB 左右,且完全不影响运行速度!
第四步:配置全局 Git 别名
把编译好的
git-m移动到系统的环境变量目录(例如/usr/local/bin),让它在任何地方都能被敲出来:bash
mv git-m /usr/local/bin/请谨慎使用此类代码。
配置 Git 别名:
bash
git config --global alias.m "!git-m"请谨慎使用此类代码。
现在你在任何项目里输入 git m,就能享受到仅有 2MB 体积、零延时启动、一键 AI 提交的极致体验了。
为了让这个 Go 语言工具更完美,你需要我补充哪部分呢?
如何在编译时动态注入 API_KEY(这样就不用把密钥写死在源码里了)
增加一个确认机制(AI 生成备注后,需要你敲击回车或输入 y 才会真正 Commit)
改为 Rust 语言 版本(Rust 编译后不经过 UPX 就能做到 3MB 左右,但代码稍显复杂)