🔀 打造更智能的 Git 提交合并命令:gix merge 实战
在前两篇文章中,我们讲了为什么要开发 gix,也完成了 CLI 工具的基础搭建和 squash 命令的实现。
这一篇,我们要挑战一个更「智能」的命令 ------ gix merge。
它的目标是:通过交互选择任意两个 commit,自动合并成一个新的提交,不再受限于 HEAD~n 的范围,体验大大提升!
💡 为什么不用 rebase?
你可能会问,Git 原生的 rebase -i 也能做这事啊,干嘛重复造轮子?
原因有三:
-
记不住命令,交互复杂
-
不能自动化,不适合重复使用
-
无法直接用于团队规范(比如自动生成 message)
我们希望的是:
- 输入 gix merge
- 选择起始和结束的 commit
- 填写 commit message
- 自动 reset + commit + push(可选)
🎯 目标功能
功能项 | 说明 |
---|---|
✅ 支持选择任意 commit 区间 | 不限于最近几次 |
✅ 支持交互式填写 message | 或通过参数传入 |
✅ 支持自动 push | 支持选择是否强推 |
✅ 支持命令参数直接执行 | 非交互场景也能跑 |
🧱 命令结构(入口)
修改 src/index.ts,加上参数定义:
bash
program
.command('merge')
.description('交互式合并两个 commit')
.option('-f, --from <hash>', '起始 commit')
.option('-t, --to <hash>', '结束 commit')
.option('-m, --message <msg>', '新的提交信息')
.option('--push', '是否自动推送')
.option('--force', '是否强推')
.action(runMerge)
🧪 命令实现(核心逻辑)
新建 src/commands/merge.ts:
typescript
import prompts from 'prompts'
import { execGit } from '../utils/git'
import chalk from 'chalk'
export async function runMerge(opts: {
from?: string
to?: string
message?: string
push?: boolean
force?: boolean
}) {
// 自动补全 commit 信息(交互)
if (!opts.from || !opts.to) {
const { from, to } = await prompts([
{
type: 'text',
name: 'from',
message: '请输入起始 commit(hash 或 HEAD~n)',
},
{
type: 'text',
name: 'to',
message: '请输入结束 commit(hash 或 HEAD)',
}
])
opts.from = from
opts.to = to
}
if (!opts.message) {
const { msg } = await prompts({
type: 'text',
name: 'msg',
message: '请输入新的 commit message:'
})
opts.message = msg
}
if (!opts.from || !opts.to || !opts.message) {
console.log(chalk.red('❌ 输入信息不完整,终止操作'))
return
}
// 开始合并
const range = `${opts.from}^..${opts.to}`
await execGit(`reset --soft ${opts.from}`)
await execGit(`commit -m "${opts.message}" --no-verify`)
console.log(chalk.green(`🎉 合并完成!从 ${opts.from} 到 ${opts.to}`))
// 自动推送
if (opts.push) {
const currentBranch = await execGit('rev-parse --abbrev-ref HEAD', { silent: true })
const pushCmd = `push origin ${currentBranch}${opts.force ? ' --force' : ''}`
await execGit(pushCmd)
console.log(chalk.green('🚀 已自动推送'))
}
}
✨ 效果演示
sql
gix merge
终端交互:
sql
? 请输入起始 commit(hash 或 HEAD~n): HEAD~3
? 请输入结束 commit(hash 或 HEAD): HEAD
? 请输入新的 commit message: feat: 合并配置优化相关提交
🎉 合并完成!从 HEAD~3 到 HEAD
再来个直接执行的用法:
sql
gix merge -f HEAD~2 -t HEAD -m "feat: 合并优化项" --push --force
📦 提示:如何查看历史 commit?
可以配合下面的 Git 命令快速浏览历史:
css
git log --oneline --decorate
或直接封装成 gix log 也是后续可扩展的方向。
📌 代码小贴士
如果你希望自动获取当前分支:
rust
const currentBranch = await execGit('rev-parse --abbrev-ref HEAD', { silent: true })
支持 silent 模式,在你的 execGit 函数里可以加个 stdio 控制逻辑。
🔮 下一步计划
下一篇我们来讲讲 CLI 工具怎么"做得像个产品"一样:
- 如何把 gix 发布到 npm
- 如何维护多个版本
- 如何结合 CI/CD 自动发布
🧩 项目地址
欢迎来逛逛 ➜ github.com/nianyi778/g...
欢迎 Star ⭐ + PR,或者提建议~