使用 AI 自動生成 Git Commit 訊息
本篇要解決的問題
每次更新完成式碼,比如修 Bug、開發新功能後,在寫 Git Commit 訊息時都會很懶,基本上寫出的就是當下的自己看得懂,但未來的自己,或是接手的人不一定看得懂的狀態,導致之後要回頭查某次的更新時,會耗掉很長的時間在找哪次的更新是不是有改某某功能。
人類不想花心力的工作,就交給 AI 去作。
August 用了 OpenAI API,再用便宜的 gpt-4o-mini 模型後,Commit 訊息可以秒生成。
因為用的是 API,會需要付費使用,但 gpt-4o-mini 真的便宜,猛用一個月搞不好用不到 1 美金。
會看到這篇筆記文的,應該都是開發一段時間過的攻城獅大大們,所以才也想要省掉寫 Git Commit 的心力,這篇就不細寫了,因為方式很簡單,本篇不再贅述細節,僅附上相關文章連結供參考。
準備好必要東西:OpenAI API Key
因為是調用 OpenAI API 來幫我們寫提交訊息,因此需要 Key。
要再次提醒,使用 AI 來寫提交訊息,是要酷 $$ 的,只是選對模型,可以很省錢。
這個步驟前幾篇有寫過,就不再重寫,請看:
CodiumAI PR-Agent,在 GitLab 上用 AI 來 Code Review
準備好必要的東西:安裝 Node.js
這篇其實也可以跳過的,前端攻城獅的電腦,沒有安裝 Node.js 的可能性比搶到無敵星星還低。
這邊附上 Node.js 的官方網址,請自行下載安裝:https://nodejs.org/zh-tw。
安裝後,可以用終端機執行以下,看是否安裝成功,有成功會回傳安裝的版本:
node -v
npm -v
安裝必要的 packages
為了調用 OpenAI API,需要二個 package:axios、dotenv。
- axios:用於處理 HTTP 請求,支援 Promise 和攔截器。
- dotenv:用於從 .env 檔案載入環境變數,防止敏感資訊外洩。
看大家習慣用什麼工具安裝,這邊附上基本款的 npm install
。
npm install -D axios dotenv
建立 .env 檔
.env 檔是拿來放 OpenAI API Key 用的,畢竟有了 Key,其他人就可以拿來用,為了保障我們 $$ 的生命安全,我們放進 .env 裡。
.env 檔內容如下:
OPEN_API_KEY_COMMIT=從 OpenAI 後台拿到的 Key
.env 檔,除非專案是私人的,或是公司自架的 Git,不然要避免傳上去。
新增 commit.cjs 檔
這步驟,就是要寫調用 OpenAI API 來幫我們產生 commit 訊息的程式碼。
Prompt 的部份,是 August 試過幾次後,覺得有符合自己需求的寫法,如果大家發現有更好的 Prompt,歡迎留言提供。
commit.cjs 內容如下:
const axios = require('axios'); | |
const { execSync } = require("child_process"); | |
require('dotenv').config(); | |
// 使用 OpenAI API Key | |
const apiKey = process.env.OPEN_API_KEY_COMMIT; | |
const apiUrl = 'https://api.openai.com/v1/chat/completions'; | |
// 取得 git 差異內容 | |
function getGitDiff() { | |
try { | |
// 首先獲取所有更改的檔案列表 | |
const changedFiles = execSync("git diff --cached --name-only", { encoding: "utf-8" }) | |
.split('\n') | |
.filter(file => file && !file.includes('.min.') && file.trim() !== ''); | |
console.log('判斷檔案:', changedFiles); | |
// 然後只對這些檔案執行 git diff | |
const diff = changedFiles.map(file => { | |
try { | |
return execSync(`git diff --cached -- "${file}"`, { encoding: "utf-8" }); | |
} catch (error) { | |
console.error(`Error getting diff for file ${file}:`, error); | |
return ''; | |
} | |
}).join('\n'); | |
return diff; | |
} catch (error) { | |
console.error("Error fetching git diff:", error); | |
return ""; | |
} | |
} | |
// 使用 axios 調用 OpenAI 生成 commit 訊息 | |
async function generateCommitMessage(diff) { | |
try { | |
const response = await axios.post(apiUrl, { | |
model: "gpt-4o-mini", // 使用 GPT-4 模型 | |
messages: [ | |
{ | |
role: "system", | |
content: "你是一個優秀的開發者,負責撰寫簡潔又描述清楚的 Git commit 訊息。", | |
}, | |
{ | |
role: "user", | |
content: `根據以下的 git 差異生成一個有意義的 commit 繁體中文訊息,請包含兩個部分:\n1. Summary(不超過50字)\n2. Description(條列描述變更內容):\n${diff}`, | |
}, | |
], | |
}, { | |
headers: { | |
'Authorization': `Bearer ${apiKey}`, | |
'Content-Type': 'application/json' | |
} | |
}); | |
const commitMessage = Array.isArray(response.data.choices) && response.data.choices.length > 0 ? response.data.choices[0].message.content.trim() : "Default commit message."; | |
return commitMessage; // 回傳完整的 commit 訊息,不做拆解 | |
} catch (error) { | |
console.error("Error generating commit message:", error.response ? error.response.data : error.message); | |
return "Refactor code."; // 如果發生錯誤,回傳一個預設的 commit 訊息 | |
} | |
} | |
// 主執行流程 | |
async function main() { | |
const diff = getGitDiff(); | |
if (!diff) { | |
console.log("No changes to commit."); | |
return; | |
} | |
const commitMessage = await generateCommitMessage(diff); | |
console.log(commitMessage); | |
} | |
main(); |
程式碼裡,有避開去檢查 .min.
的檔案。
如果需要再避開什麼,就修改 filter
的部份,比方如果要再避掉 docs
資料夾中的文件,可以改為:
.filter(file => file && !file.includes('.min.') && !file.startsWith('docs/') && file.trim() !== '');
使用方式
我們編輯好程式碼,將要 commit 的檔案 用 git add
stage 以後,專案裡開啟終端機,輸入:
node commit.cjs
接著幾需要幾秒的時間(看檔案異動的多寡),就會看見 OpenAI 回傳了這次的 commit message。
會像這樣:
會提供兩個項目:簡短的 Summary、條例式也較詳細的 Description。
主要是因為大家使用 Git 的工具都不一樣,同事用 Sourcetree 就只有 Summary 可以填,但 August 用的是 Fork,就都可以填。
二項都列出來,大家自由選擇囉。
Top comments (0)