跳至内容

自动化Git提交信息

在软件开发领域,编写一致且信息丰富的提交信息至关重要,但这一点经常被忽视。 这项任务可能变得乏味,特别是当您沉浸在编码流程中时。 为了帮助解决这个问题,我们精心设计了一个专门用于自动生成Git提交信息的脚本, 确保这些信息有意义并节省您的时间。

该脚本作为一个常规的node.js自动化脚本运行,使用runPrompt向LLM发起调用,并让用户确认生成的文本。

脚本说明

首先,我们检查Git仓库中是否有任何暂存的更改:

let { stdout } = await host.exec("git", ["diff", "--cached"])

如果没有暂存的更改,我们会询问用户是否想要暂存所有更改。如果用户确认,我们将暂存所有更改。否则,我们将中止操作。

const stage = await host.confirm("No staged changes. Stage all changes?", {
default: true,
})
if (stage) {
await host.exec("git", ["add", "."])
stdout = (await host.exec("git", ["diff", "--cached"])).stdout
}
if (!stdout) cancel("no staged changes")

我们使用暂存的更改生成初始提交信息:

message = (
await runPrompt(
(_) => {
_.def("GIT_DIFF", stdout, { maxTokens: 20000 })
_.$`GIT_DIFF is a diff of all staged changes, coming from the command:
\`\`\`
git diff --cached
\`\`\`
Please generate a concise, one-line commit message for these changes.
- do NOT add quotes`
},
{ cache: false, temperature: 0.8 }
)
).text

上述提示配置表明,消息应当简洁明了,与“git diff —cached”输出相关,并且不应包含引号。

用户选择如何处理生成的消息:

choice = await host.select(
message,
[{ name: "commit", value: "commit", description: "accept message and commit" },
...],
)

提供了编辑或重新生成消息的选项。如果用户选择编辑消息,我们会要求他们输入新消息:

if (choice === "edit") {
message = await host.input("Edit commit message", { required: true })
choice = "commit"
}

如果用户选择提交消息,我们将提交更改:

if (choice === "commit" && message) {
console.log((await host.exec("git", ["commit", "-m", message])).stdout)
}

运行脚本

您可以通过CLI运行此脚本。

终端窗口
genaiscript run gcm

你可以将这个命令封装在gcm.sh文件中,或者放在你的package.json文件的script部分中:

{
"devDependencies": {
"genaiscript": "*"
},
"scripts": {
"gcm": "genaiscript run gcm"
}
}

然后你可以使用以下命令运行脚本:

终端窗口
npm run gcm

使用git钩子

你也可以附加到commit-msg git钩子上按需运行消息生成。 使用huksy框架,我们可以在.husky/commit-msg文件中注册genaiscript的执行。

commit-msg钩子会接收存储提交消息的文件位置。我们将此参数传递给脚本,以便它填充到env.files变量中。

.husky/commit-msg
genaiscript run commit-msg "$1"

在脚本中,我们检查文件内容是否已包含用户消息,否则生成新消息。

commit-msg.genai.mts
const msg = env.files[0] // file created by git to hold the message
const msgContent = msg.content // check if the user added any message
?.split(/\n/g)
.filter((l) => l && !/^#/.test(l)) // filter out comments
.join("\n")
if (msgContent) cancel("commit message already exists")
...
await host.writeText(msg.filename, message)

致谢

这个脚本的灵感来源于Karpathy的 commit message generator