動機與痛點:手動整理 Changelog 有多痛苦?
在現代軟體開發流程中,良好的 Changelog(變更日誌)不僅能幫助開發者追蹤歷史,更是版本管理、發布流程、甚至產品溝通的關鍵橋梁。然而,實務上要維護一份語意清晰、結構一致的 Changelog,往往是一件吃力不討好的工作。多數團隊仰賴手動彙整 Git commit、複製貼上、逐條潤飾,不但耗時繁瑣,也容易遺漏關鍵資訊,導致變更記錄失真、上下游溝通不順,甚至版本發布後才發現文件描述與實際行為不符。
此外,當團隊成員眾多、專案規模龐大,Changelog 的維護難度更是呈指數級上升。不同開發者的 commit 風格不一致,有的使用 fix:、有的使用「修 bug」、有的乾脆不寫訊息,讓自動化彙整難以啟動。即便使用 Conventional Commits 等標準,也難以產生具語意性的自然語言摘要。因此,我們需要一種更智慧、更人性化的方法——讓 AI 協助理解 commit 背後的意圖,自動撰寫出有邏輯、有重點的 Changelog,從根本解決「文件永遠趕不上代碼變更」的老問題。
本篇將進一步結合大型語言模型,讓 changelog 的撰寫邁向智慧化與語意清晰。
自動整理 Changelog 的革命時代
還在手動整理 changelog 嗎?現在只需要 git log + ChatGPT,就能一鍵產出語意清晰的變更摘要!
這篇文章將教你如何打造一個「會說話的 Git 日誌助手」: 透過 Node.js 腳本自動擷取當日的提交紀錄 ➜ 儲存為 JSON ➜ 貼到 ChatGPT ➜ 自動生成 changelog。 不只減少文書負擔,還能大幅提升團隊同步效率。
以下是實戰中使用的 ChatGPT 提示語,歡迎直接複製貼上使用:
以下是今日的 Git log 資訊,請根據此資訊完成今日的 changelog 摘要:
```
<!-- GIT LOG -->
```
1. 分析變更內容(以繁體中文撰寫回答)
根據剛剛產出的 logs/git/YYYY-MM-DD.json 檔案,請針對以下問題進行整理與說明:
今日變更的核心主題是什麼?
主要進行了哪些功能開發、錯誤修正或重構?
涉及的關鍵檔案有哪些?(請列出數個具代表性的檔案路徑)
今日總共包含幾筆 commit?
2. 產出 Markdown 摘要
請根據上方分析結果,撰寫一段簡明扼要的摘要段落,格式採用 Markdown,並適用於部落格或 changelog 使用。
輸出格式範例如下:
```md
## 2025-04-25 變更摘要
今日主要進行了 Git 相關日誌與摘要功能的開發與優化,包含:
- 新增 Git log 收集腳本 `scripts/createChangelog.ts`,自動擷取並格式化當日 commit 記錄。
- 新增 changelog 自動產生腳本 `scripts/createChangelog.ts`,並產出每日 JSON 及 Markdown 摘要。
- 新增與更新日誌檔案:`logs/git/2025-04-25.json`、`logs/summary/2025-04-25.md`。
- 新增部落格圖片資源設定檔 `src/data/images.json`。
今日共 2 筆 commit,核心主題為自動化日誌產出流程與相關檔案維護。
```
如果你希望全自動的話,那麼你可以根據以下的教學,使用指令集直接完成當日的 changelog 摘要生成。
技術選型
我們的 Git 日誌精靈將使用 Node.js 開發,這是一個理想的選擇,原因有三:首先,JavaScript/TypeScript 對於前端和全棧開發者來說門檻較低;其次,Node.js 擁有豐富的檔案系統和子進程操作 API;最後,npm 生態系統提供了大量可用的輔助庫,如 moment.js 用於時間處理。
核心架構將包含以下模組:Git 命令執行與解析模組、日誌格式化與儲存模組、人性化互動介面模組。這種模組化設計使得我們的工具不僅功能齊全,而且易於擴展和客製化。
建立專案與安裝依賴
首先,我們需要建立一個 Node.js 專案並安裝必要的依賴包。我們將使用 TypeScript 來提升代碼的可維護性和類型安全。
mkdir git-diary
cd git-diary
npm init -y
npm install typescript ts-node @types/node moment
接著,創建基本的資料夾結構:
mkdir -p logs/git logs/summary scripts
touch tsconfig.json
在 tsconfig.json
中設置基本的 TypeScript 配置:
{
"compilerOptions": {
"target": "ES2018",
"module": "CommonJS",
"outDir": "./dist",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
}
}
腳本開發環境準備
為了開發我們的 Git 日誌工具,需要確保系統已經安裝了 Git,並且當前資料夾是一個 Git 倉庫。如果不是,可以使用以下命令初始化一個倉庫:
git init
git config user.name "Your Name"
git config user.email "your.email@example.com"
這些準備工作完成後,我們就可以開始編寫核心腳本了。
Git 日誌收集與處理的核心邏輯
Git 命令解析與執行
我們的工具核心是從 Git 提交記錄中獲取有用資訊。我們使用 Node.js 的 child_process.execSync
方法來執行 Git 命令,下面是 Git log 命令的解析:
const raw = execSync(
`git log --since=midnight --date=iso-strict --pretty=format:'__SPLIT__%H|%ad|%s|%b' --name-only`,
{ encoding: "utf-8" }
);
這條命令包含幾個關鍵參數:
--since=midnight
:只獲取當天的提交記錄--date=iso-strict
:使用 ISO 標準格式輸出日期--pretty=format:'__SPLIT__%H|%ad|%s|%b'
:自訂輸出格式,包含哈希值、日期、主題和詳細說明--name-only
:同時列出每次提交修改的檔案
這個命令會返回一個格式化的字串,我們需要解析它將其轉換為結構化資料。
日誌資料結構與格式化
接下來,我們需要將原始的 Git log 輸出解析為可用的 JSON 格式:
const commits: any[] = [];
const lines = raw.split("\n");
let current: any = null;
for (const line of lines) {
if (line.startsWith("__SPLIT__")) {
if (current) commits.push(current);
const [hash, date, subject, body] = line.slice(9).split("|");
current = { hash, date, subject, body, files: [] };
} else if (line.trim()) {
current?.files.push(line.trim());
}
}
if (current) commits.push(current);
這段代碼將 Git 命令的輸出解析為一個結構化的陣列,每個元素代表一個提交記錄,包含哈希值、日期、主題、詳細說明和修改的檔案列表。這種結構使得我們可以輕鬆地進行後續處理和分析。
檔案系統操作與日誌儲存
解析後的提交記錄需要持久化儲存,以便日後查詢和分析。我們使用 Node.js 的 fs
模組來完成這一操作:
writeFileSync(
path.join("logs", "git", `${DATE}.json`),
JSON.stringify(commits)
);
這行代碼將解析後的提交記錄以 JSON 格式儲存到 logs/git
資料夾下,檔名為當天的日期。這樣,我們就有了一個按日期組織的提交記錄資料庫,便於日後查詢和統計。
同時,我們也需要處理摘要檔案的存在性檢查和刪除操作:
if (existsSync(path.join("logs", "summary", `${DATE}.md`))) {
// 如果當天的摘要檔案已存在,則刪除它
unlinkSync(path.join("logs", "summary", `${DATE}.md`));
}
這樣,每次執行腳本時,我們都能確保生成新的摘要檔案,避免資訊重複或過時。
擬人化互動設計:讓你的 CLI 工具更有溫度
擬人化輸出機制的實現
我們的工具最獨特的特點是它具有「人性化」的互動體驗。為了實現這一點,我們設計了一個模擬人類輸入的函數:
async function sleep(ms: number) {
return new Promise((r) => setTimeout(r, ms));
}
async function sayLikeHuman(lines: string[], delay = 1000) {
for (const line of lines) {
console.log(line);
await sleep(delay);
}
}
這個函數接受一組文字行和延遲時間,並按順序輸出它們,每行之間有一定的延遲。這種延遲輸出模擬了人類打字的節奏,使得輸出看起來更像是一個真實的人在和你對話,而不是冰冷的機器輸出。
多場景的擬人化對話設計
根據不同的情境,我們的工具會輸出不同的擬人化訊息。例如,當成功收集到提交記錄時:
await sayLikeHuman([
`📦 今日 Git log 已成功保存至 logs/git/${DATE}.json!`,
`📖 今天共記錄了 ${commits.length} 筆 commit,小心翼翼地封裝在日誌裡了喔~`,
`🧸 請問您要來點……「推進世界的程式碼」嗎?`,
]);
當需要刪除舊的摘要檔案時:
await sayLikeHuman([
`🔍 咦?我發現今天的摘要已經存在了耶。`,
`🧹 為了讓日誌乾乾淨淨,我來幫你把它收拾掉吧~`,
]);
// 刪除操作
await sayLikeHuman([
`🗑️ 嗯哼,舊的摘要已經被我丟進回收桶囉!`,
`✨ 我們可以重新寫下一段更棒的歷史了呢~`,
]);
當當天沒有提交記錄時:
await sayLikeHuman([
`☁️ 咦……今天還沒有任何 commit 呢。`,
`📭 沒關係,靈感總是在悠閒時降臨~`,
`🐰 請問您要來點……寫程式的魔法嗎?`,
]);
這些不同場景下的擬人化訊息讓工具更加生動有趣,同時也提供了清晰的狀態反饋。
個人風格定製與本地化
工具的擬人化風格可以根據個人喜好進行定製。我們在腳本中使用了一種輕鬆、活潑的風格,添加了表情符號和擬態語氣詞,營造一種可愛的助手形象。但這種風格可以根據需要調整為更專業、更嚴肅,或者完全不同的個性。
此外,我們還加入了用戶名稱的獲取和使用:
const user = execSync("git config user.name", { encoding: "utf-8" }).trim();
console.log(`🌸 ${user} にゃっはろ〜 我是你的寫程式小幫手!`);
這種個人化的問候使得工具感覺更加親近和貼心。你可以根據自己的喜好調整問候語和對話風格,甚至可以加入不同語言的元素,如這裡的日語問候語「にゃっはろ〜」。
完整原始碼
// scripts/collectGitlog.ts
import { execSync } from "child_process";
import { writeFileSync, existsSync, unlinkSync } from "fs";
import moment from "moment";
import path from "path";
async function sleep(ms: number) {
return new Promise((r) => setTimeout(r, ms));
}
async function sayLikeHuman(lines: string[], delay = 1000) {
for (const line of lines) {
console.log(line);
await sleep(delay);
}
}
async function main() {
const DATE = moment().format("YYYY-MM-DD");
const user = execSync("git config user.name", { encoding: "utf-8" }).trim();
console.log(`🌸 ${user} にゃっはろ〜 我是你的寫程式小幫手!`);
await sleep(500);
const raw = execSync(
`git log --since=midnight --date=iso-strict --pretty=format:'__SPLIT__%H|%ad|%s|%b' --name-only`,
{ encoding: "utf-8" }
);
if (raw.trim()) {
const commits: any[] = [];
const lines = raw.split("\n");
let current: any = null;
for (const line of lines) {
if (line.startsWith("__SPLIT__")) {
if (current) commits.push(current);
const [hash, date, subject, body] = line.slice(9).split("|");
current = { hash, date, subject, body, files: [] };
} else if (line.trim()) {
current?.files.push(line.trim());
}
}
if (current) commits.push(current);
writeFileSync(
path.join("logs", "git", `${DATE}.json`),
JSON.stringify(commits)
);
await sayLikeHuman([
`📦 今日 Git log 已成功保存至 logs/git/${DATE}.json!`,
`📖 今天共記錄了 ${commits.length} 筆 commit,小心翼翼地封裝在日誌裡了喔~`,
`🧸 請問您要來點……「推進世界的程式碼」嗎?`,
]);
if (existsSync(path.join("logs", "summary", `${DATE}.md`))) {
await sayLikeHuman([
`🔍 咦?我發現今天的摘要已經存在了耶。`,
`🧹 為了讓日誌乾乾淨淨,我來幫你把它收拾掉吧~`,
]);
unlinkSync(path.join("logs", "summary", `${DATE}.md`));
await sayLikeHuman([
`🗑️ 嗯哼,舊的摘要已經被我丟進回收桶囉!`,
`✨ 我們可以重新寫下一段更棒的歷史了呢~`,
]);
}
} else {
await sayLikeHuman([
`☁️ 咦……今天還沒有任何 commit 呢。`,
`📭 沒關係,靈感總是在悠閒時降臨~`,
`🐰 請問您要來點……寫程式的魔法嗎?`,
]);
}
}
main();
實用場景與擴展應用
在團隊開發環境中,這個 Git 日誌工具可以發揮更大的價值。首先,它能夠輔助每日站立會議,自動生成每位成員的日報內容,節省溝通時間。此外,在版本發布準備階段,工具能快速彙整特定時間段內的所有變更,便於撰寫發布說明。對於代碼審查,提供清晰的提交歷史脈絡,幫助審查者理解代碼變更背景。新成員入職時,工具則能幫助他們快速了解項目的最近變更和開發方向。
我們的工具可以與現代開發流程和工具無縫整合。它能夠融入 CI/CD 流程,在持續集成時自動執行,生成每次構建的變更摘要,並將日誌摘要發送到 Slack 或 Discord 等團隊通訊渠道,保持團隊同步。此外,工具還可以與 VuePress、Docusaurus 等文檔系統集成,自動更新變更日誌頁面,並與 Jira、Trello 等項目管理工具連接,自動關聯提交與任務。
雖然我們的基礎工具已經能夠滿足日常需求,但還有許多方向可以進行擴展和改進。首先是智能分類與分析,使用自然語言處理技術對提交訊息進行分類和主題提取。其次是圖表視覺化,生成提交頻率、檔案修改熱圖等視覺化報表。也可以考慮提交品質檢查,評估提交訊息的質量並提供改進建議。工具還可以設計多種互動「人格」,如可愛助手、嚴肅顧問、幽默朋友等,根據心情切換,並支持多語言,適應國際團隊需求。
使用技巧
為了充分發揮工具的價值,建議設置定時任務或整合到工作流程中。首先,可以使用 cron 任務在每天結束時自動執行腳本,收集當天的提交記錄。此外,將腳本作為 Git post-commit 鉤子的一部分,每次提交後自動更新日誌也是一個可行的方案。最後,可以在 VS Code 或其他編輯器中添加自定義命令,一鍵執行日誌生成。
為了讓生成的日誌更有價值,可以考慮使用統一的提交規範,如 Conventional Commits,從而使自動生成的日誌更加結構化。可以在日誌中區分不同成員的貢獻,促進責任感和團隊意識,並在提交訊息中引用議題編號、文檔鏈接等,豐富日誌內容。此外,記錄各類任務所花費的時間,有助於工作量評估和計劃改進。
在使用此工具時,需要注意幾個常見問題。對於非常大的存儲庫,可能需要限制歷史查詢範圍,以避免效能問題。確保正確處理提交訊息中的特殊字符,防止解析錯誤。在生成團隊共享日誌時,應注意是否包含敏感資訊。對於分佈式團隊,需要正確處理不同時區的日期問題,以避免混淆。
AI 支援整合
Windsurf
如果您正在使用 Windsurf 平台,並希望將本工具整合進每日自動化開發流程中,以下是一套可立即上手的指令集。這些指令將協助您快速產出當日的 Git 變更記錄,分析提交內容,並自動生成 Markdown 格式的日誌摘要,無須手動操作任何流程。
只需將下方指令貼上並執行,即可觸發完整流程,從原始 Git 資料擷取、格式化、清理舊日誌到新摘要輸出,全自動完成,是提升開發效率與維護紀錄品質的最佳利器:
# AI 指令開始(請自動執行以下工作流,每次貼上都應重新執行。不需解釋過程,也不需顯示輸出內容)
---
# 自動產出日誌摘要
## 1. 產出當日 Git 變更記錄(JSON 格式)
請先執行以下指令:
```bash
npx tsx scripts/createChangelog.ts
```
這個指令會擷取從今日午夜開始的所有 Git commit 紀錄,並轉換成格式化的 JSON 檔案,儲存路徑為:
```
logs/git/YYYY-MM-DD.json
```
---
## 2. 分析變更內容(以繁體中文撰寫回答)
根據剛剛產出的 `logs/git/YYYY-MM-DD.json` 檔案,請針對以下問題進行分析與回答:
- 今日變更的核心主題是什麼?
- 主要進行了哪些功能開發、錯誤修正或重構?
- 涉及的關鍵檔案有哪些?(請列出數個代表性的檔案路徑)
- 今日總共包含幾筆 commit?
---
## 3. 產出 Markdown 摘要
請根據分析結果撰寫一段簡潔扼要的摘要段落,格式為 Markdown,用於 blog 或 changelog。
輸出到 `logs/summary/YYYY-MM-DD.md`,輸出格式範例如下:
```
## 2025-04-25 變更摘要
今日主要進行了 Git 相關日誌與摘要功能的開發與優化,包含:
- 新增 Git log 收集腳本 `scripts/createChangelog.ts`,自動擷取並格式化當日 commit 記錄。
- 新增 changelog 自動產生腳本 `scripts/createChangelog.ts`,並產出每日 JSON 及 Markdown 摘要。
- 新增與更新日誌檔案:`logs/git/2025-04-25.json`、`logs/summary/2025-04-25.md`。
- 新增部落格圖片資源設定檔 `src/data/images.json`。
今日共 2 筆 commit,核心主題為自動化日誌產出流程與相關檔案維護。
```
任務完成後,請僅回覆「生成成功」。
# AI 指令結束
生成結果
## 2025-04-25 變更摘要
今日主要進行了 Git 日誌與摘要自動化流程的開發與優化,包含:
- 新增 Git log 收集腳本 `scripts/collectGitlog.ts`,自動擷取並格式化當日 commit 記錄。
- 新增 changelog 產生腳本 `scripts/createChangelog.ts`,並產出每日 JSON 及 Markdown 摘要。
- 新增與更新日誌檔案:`logs/git/2025-04-25.json`、`logs/summary/2025-04-25.md`。
- 新增部落格圖片資源設定檔 `src/data/images.json`。
- 新增部落格文章:`src/content/blog/2025/2025-04-25.md`。
今日共 4 筆 commit,核心主題為自動化日誌產出流程、相關檔案維護與部落格內容更新。
結論
我們通過這篇文章,從零開始打造了一個有溫度、會說話的 Git 日誌工具。它不僅能自動收集和整理提交記錄,還能以擬人化的方式與使用者互動,為日常開發工作增添儀式感和樂趣。這個工具雖然簡單,但卻體現了「技術服務人性」的理念,讓我們在數字化工作流程中保留人文關懷。
未來,隨著人工智能技術的發展,我們可以期待這類工具進一步進化:自動總結代碼變更的內容和影響;根據歷史數據預測項目風險和開發節奏;甚至能夠理解開發者的工作狀態和情緒,提供更個性化的互動體驗。這些進步將使得開發工具不僅僅是冰冷的生產力工具,更成為開發者工作中的智能夥伴。
最後,希望本文能夠啟發你在日常工作中尋找技術與人性的平衡點,用創意和關懷改進開發體驗。無論是團隊協作還是個人項目,一個會說話、有個性的工具往往能帶來意想不到的價值和樂趣。