领导夸我日报越写越详细了,其实我只敲了 npm run commit

前言

上周群里突然说要查绩效,每个人每天交一份日报。

我这人记性不太好,到下班点根本想不起来今天到底干了啥。只能打开 git log,翻一遍提交记录,复制粘贴,再润色成领导能看懂的"人话"。一来二去半小时没了,本来能准点走的,结果又坐了半小时。

而且我这 commit message 写得也不咋样,改了一堆文件,到提交那一下脑子是空的,经常就敲个 update: 代码更新 完事。回头自己看都懵。

有天突然反应过来:信息不都在 git log 里吗?我只是缺个帮我总结的人。

DeepSeek 接口挺便宜,百万 token 一块钱。那就让它干这活呗。花了一个下午摸了个小工具,干两件事:

  • 提交代码的时候,AI 看一眼 diff,帮我生成 commit message,我确认完再提交
  • 提交完,AI 把今天所有 commit 拉一遍,自动生成工作日报

从此不用自己写了。下面说下怎么搞的,顺便记下踩的坑。


一、整体结构

就一个 git-hooks 文件夹,放俩脚本:

bash 复制代码
项目根目录/
├── git-hooks/
│   ├── commit.js             # 提交用的,AI 生成 message + 我确认
│   ├── generate-report.js    # 日报的,AI 读 commit 生成日报
│   ├── package.json          # 单独管 node-fetch 依赖
│   └── node_modules/
├── .git/hooks/
│   └── post-commit           # 提交后自动跑日报脚本
├── package.json              # 根目录,加个 npm run commit
└── daily-report.md           # 日报输出到这里(加进 .gitignore 了)

没啥花里胡哨的,俩脚本一个钩子,够用了。


二、提交那部分:commit.js

一开始踩的坑

我一开始想的是用 prepare-commit-msg 钩子------AI 生成后直接写进 commit message 文件,然后 Git 打开编辑器让我改。听起来挺优雅,结果一用就翻车:

  • Git 配的编辑器路径是 VS Code 的,但我实际用的是 Trae,路径不对,提交直接报错
  • 后来用 IDE 的 Git 面板提交,根本不触发编辑器,AI 写完就被拿走了,我想改都没机会

折腾半天,干脆换思路:不挂钩子了,手动跑命令,在终端里确认。

csharp 复制代码
git add .  →  AI 生成 message  →  终端敲 Y/N  →  提交

土是土了点,但稳。

实现

核心代码就这些,其他是错误处理:

javascript 复制代码
const { execSync } = require('child_process');
const fs = require('fs');
const os = require('os');
const path = require('path');
const readline = require('readline');
const fetch = require('node-fetch');

const AI_API_URL = 'https://api.deepseek.com/v1/chat/completions';
const AI_API_KEY = 'your-api-key';

function ask(rl, question) {
  return new Promise(resolve => {
    rl.question(question, answer => resolve(answer));
  });
}

async function main() {
  // 1. 先 git add .
  execSync('git add .', { stdio: 'pipe' });

  // 2. 拿 diff,概览和详情都给 AI
  const diffStat = execSync('git diff --cached --stat', { encoding: 'utf-8' });
  const diffDetail = execSync('git diff --cached --unified=3', {
    encoding: 'utf-8',
    maxBuffer: 1024 * 1024 * 5
  });

  // 3. 喂给 AI
  const prompt = `你是一个专业的开发人员。请根据以下 Git 代码变更,生成一条简洁的中文 commit message。
要求:
1. 格式:类型: 简短描述(如 "修复: xxx" / "新增: xxx" / "优化: xxx")
2. 只输出一行,不要解释
3. 不超过 50 个字

变更文件概览:
${diffStat}

代码变更详情:
${diffDetail}
`;

  const response = await fetch(AI_API_URL, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${AI_API_KEY}`
    },
    body: JSON.stringify({
      model: 'deepseek-chat',
      messages: [{ role: 'user', content: prompt }],
      max_tokens: 100,
      temperature: 0.3
    })
  });
  const data = await response.json();
  const aiMsg = data.choices[0].message.content.trim().replace(/^["']|["']$/g, '');

  // 4. 终端确认
  console.log('AI 生成: ' + aiMsg);
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
  const choice = await ask(rl, '[Y]使用 / [N]修改 / [其他]取消: ');

  let finalMsg = aiMsg;
  if (choice.toLowerCase() === 'n') {
    finalMsg = (await ask(rl, '改一下: ')).trim();
  } else if (choice.toLowerCase() !== 'y' && choice !== '') {
    rl.close(); return;
  }
  rl.close();

  // 5. 提交
  const tmpFile = path.join(os.tmpdir(), `git-msg-${Date.now()}.txt`);
  fs.writeFileSync(tmpFile, finalMsg, 'utf-8');
  execSync(`git commit -F "${tmpFile}"`, { stdio: 'inherit' });
  fs.unlinkSync(tmpFile);
}

main();

几个细节

为啥用 git commit -F 不用 -m

message 里万一有个引号、有个 $ 啥的,-m "${msg}" 就炸了。写进临时文件用 -F 读最省心:

javascript 复制代码
// 别这么写,message 含引号就完蛋
execSync(`git commit -m "${finalMsg}"`);

// 这样写,啥特殊字符都不怕
fs.writeFileSync(tmpFile, finalMsg, 'utf-8');
execSync(`git commit -F "${tmpFile}"`);

temperature: 0.3 是啥意思?

温度低点,AI 输出更稳,不会给我整花活------比如给 commit message 加个标题党,或者后面跟一段"以上是 AI 生成的说明"。

AI 挂了咋办?

接口会抖、会限流,不能让它把提交流程卡死。所以 catch 里直接降级成手动输入:

javascript 复制代码
catch (err) {
  console.error('AI 挂了:', err.message);
  const rl = createRl();
  aiMsg = (await ask(rl, '自己写吧: ')).trim();
  rl.close();
}

工具是来帮忙的,不能变成负担。


三、日报那部分:generate-report.js

思路

每次 git commit 完,post-commit 钩子在后台跑这个脚本。它干三件事:

  1. git log --since="midnight" 拿今天所有提交
  2. 让 AI 归总成日报
  3. 写进 daily-report.md

第 3 步有个坑,单拎出来说。

同一天别重复追加(重点)

第一版我直接 fs.appendFileSync,每提交一次就追加一条。结果某天提交了 5 次,日报文件里就有 5 条同一天的日报,内容还都差不多------这玩意给领导看是要挨骂的。

改成:先把今天的旧块全删掉,再追加一条新的。

javascript 复制代码
const reportPath = path.resolve(__dirname, '../daily-report.md');
const dateStr = new Date().toLocaleDateString('zh-CN'); // 2026/8/25
const newBlock = `\n\n## 📅 ${dateStr} 工作日报\n\n${aiReport}\n`;

// 读已有内容,没有就空串
let oldContent = '';
try { oldContent = fs.readFileSync(reportPath, 'utf-8'); } catch (e) {}

// 把今天的旧块全部匹配出来删掉
// 日期里的 / 要转义,加 g 标志匹配所有(一天可能有多条旧的)
const escapedDate = dateStr.replace(/\//g, '\\/');
const todayBlockRegex = new RegExp(
  '\\n*## 📅 ' + escapedDate + '[\\s\\S]*?(?=\\n## 📅|$)', 'g'
);

const cleanedContent = oldContent.replace(todayBlockRegex, '');

if (cleanedContent !== oldContent) {
  // 今天已经有旧的,清掉再追加新的
  fs.writeFileSync(reportPath, cleanedContent.trimEnd() + newBlock, 'utf-8');
} else {
  // 今天还没写过,直接追加
  fs.appendFileSync(reportPath, newBlock, 'utf-8');
}

那个正则拆开看:/\\n*## 📅 2026\\/8\\/25[\\s\\S]*?(?=\\n## 📅|$)/g

  • \\n* --- 前面的空行也一起带走
  • ## 📅 2026/8/25 --- 今天的标题
  • [\\s\\S]*? --- 内容,非贪婪
  • (?=\\n## 📅|$) --- 遇到下一天的标题或者文件末尾就停
  • g --- 全局匹配,一天多条旧日报全清掉

这么搞完,一天不管提交多少次,日报文件里始终就一条,内容是最后一次提交后的全量总结。

Prompt

javascript 复制代码
const prompt = `
你是一个专业的项目经理。请根据以下 Git 提交记录,帮我生成一份工作日报。
要求:
1. 语言简练,结构清晰,分为【今日完成】、【进行中/遇到的问题】两个部分。
2. 将相似的提交合并,不要逐条翻译 commit message。
3. 只输出 Markdown 格式的日报内容,不要输出任何解释性的废话。

Git 提交记录如下:
${logs}
`;

关键是第 2 条------别逐条翻译。不然 AI 就把 5 条 commit 原样翻一遍写成 5 行,那跟我自己复制粘贴有啥区别。让它自己归类,输出才有"日报"的样子。


四、钩子配置

post-commit(后台跑,别挡道)

bash 复制代码
#!/bin/sh
node "git-hooks/generate-report.js" > git-hooks/report.log 2>&1 &

最后那个 & 一定得加。我一开始没加,结果每次 git commit 都得等 AI 接口返回才能完成提交,卡得我想砸键盘。加个 & 后台跑,提交瞬间完成,日报慢慢生成去。

package.json 加一条

json 复制代码
{
  "scripts": {
    "commit": "node git-hooks/commit.js"
  }
}

以后提交就一句 npm run commit

.gitignore 别忘了

gitignore 复制代码
# 日报是私人物品,别进代码库
daily-report.md
git-hooks/report.log

五、实际跑起来啥样

提交

ini 复制代码
$ npm run commit

📦 正在暂存变更 (git add .)...
🤖 AI 正在生成 commit message...

──────────────────────────────────────────
📝 AI 生成的 commit message:
   新增: 添加AI辅助提交工具及日报更新
──────────────────────────────────────────

是否使用?[Y]使用 / [N]修改 / [其他键]取消: y

[main 6f663da] 新增: 添加AI辅助提交工具及日报更新
 4 files changed, 165 insertions(+), 4 deletions(-)
✅ 提交成功

日报

markdown 复制代码
## 📅 2026/8/25 工作日报

## 今日完成
- 开发并引入AI辅助提交工具,支持自动暂存变更并联动更新日报,提升提交效率
- 重构日报生成逻辑,完善省份映射关系,优化生成准确性

## 进行中/遇到的问题
- 期间存在多次零散代码更新,提交信息不够规范,已通过工具化手段逐步改善提交质量

提交多少次,日报始终就一条,内容是当天全量总结。


六、踩的坑

坑 1:API 地址写半截

javascript 复制代码
// ❌ 这样调,返回的是网页 HTML,不是 JSON
const AI_API_URL = 'https://api.deepseek.com';

// ✅ 得用完整接口地址
const AI_API_URL = 'https://api.deepseek.com/v1/chat/completions';

报错 invalid json response body,因为请求打到根路径,人家给你返回一网页。

坑 2:post-commit 阻塞提交

bash 复制代码
# ❌ 前台跑,提交得等 AI 返回
node "git-hooks/generate-report.js"

# ✅ 后台跑,提交秒完成
node "git-hooks/generate-report.js" > git-hooks/report.log 2>&1 &

坑 3:Windows 没 chmod

想给钩子文件加执行权限,结果 PowerShell 压根没这命令。后来才知道,Windows 上 Git 钩子只要文件在、能访问,就会自动执行,不用额外设权限。

坑 4:prepare-commit-msg + 编辑器

前面说过了,钩子写入 message 后让 Git 开编辑器给我改------编辑器路径不对、IDE 面板不触发编辑器,各种不对付。最后还是扔了钩子,改成手动跑 + 终端 readline 交互,最省心。

坑 5:日报重复追加

第一版每提交一次追加一条,一天 5 次提交就有 5 条重复日报。后来用正则 + g 标志先把今天的旧块全清掉,再追加新的,搞定。


七、花了多少钱

DeepSeek 价格:输入 0.001 元/千 token,输出 0.002 元/千 token。

算下来,生成一次 commit message 大概 2000 token,成本 0.004 元。日报一次 500 token 左右,0.001 元。

一天提交 10 次 + 生成 10 次日报,总共 5 分钱。一个月一块五。比一瓶水还便宜。


八、说在最后

这个工具的核心就一句话:

git diff 和 git log 里啥都有,AI 只是个翻译官,把它变成人话。

所以重点不在 AI 有多强,而在:

  • 信息喂全乎------概览 + 详情都给,AI 才能总结准
  • 给它兜底------AI 挂了就退回手动,别把提交卡死
  • 日报别重复------同一天只留一条,幂等性这事儿
  • 后台跑------日报生成慢,别挡着提交

代码上面都贴了,改下 API_KEY 就能用。key 去 platform.deepseek.com 注册,充一块钱能跑很久。

领导要查日报是吧,让 AI 写去,咱先走了。

相关推荐
yuqifang1 小时前
var deferred = jQuery.Deferred(); 使用示例
前端·javascript·面试
Aloudata1 小时前
企业级 AI 问数安全指南:如何兼顾可用性、权限与审计?
大数据·人工智能·数据分析·agent·语义编织
广东帝工智能安防1 小时前
BCAS桥梁防撞预警系统五层架构深度解析:从感知层到对接层的技术实现与选型指南
开发语言·人工智能·架构·边缘计算·桥梁防撞预警系统
ms365copilot1 小时前
Copilot Excel真实数据实战
人工智能·excel·copilot
lichenyang4531 小时前
实时团队邀请的架构与数据流
前端·后端
迪康coolmu1 小时前
企业IT运维闭环——工单管理与远程协助一体化实践
java·大数据·运维·网络·数据库·人工智能·安全
一鸣AI编程1 小时前
AI UI 测试平台从 0 到 1:8 次跑通一条 19 步用例的实战复盘
前端
Logintern091 小时前
sklearn中pipeline学习
人工智能·学习·sklearn
mONESY1 小时前
搞懂 Session 与 JWT 区别 + Axios 拦截器实战
javascript