一键搞定:如何用自动化脚本拯救“手动合并”焦虑
你是否也经历过这样的时刻:刚写完一大段代码,正准备起身倒杯咖啡放松一下,却猛然想起还有分支需要合并到测试环境。不仅要切换分支、拉代码、合并,还得小心翼翼避免操作失误,仿佛在踩一地的“雷”。更惨的是,这样的操作还不是一次两次,而是反复!
在我们项目的开发初期,这一幕几乎每天都在上演。频繁的手动操作不仅让人疲惫,还极大地浪费了开发时间。于是,我们决定放大招:用脚本解放双手,让开发者能安心享受咖啡的香气,而不是纠结在Git命令中。
问题重现:小操作背后的大痛点
每次将功能分支合并到测试环境分支的流程都差不多是这样的:
- 切换到目标分支(测试环境分支)。
- 拉取最新代码。
- 将当前分支合并到目标分支。
- 推送合并后的代码到远程。
- 切回原来的功能分支。
看起来流程简单?但当你一天需要重复三五次、还要担心是否手抖输错命令时,这种“简单”就变成了开发者的心智噩梦。
问题显而易见:我们需要一种能“傻瓜化”这一切的方式。能不能写个脚本,一键搞定这些事?
决策:写!脚!本!
作为开发者,遇到机械重复的工作,第一个念头当然是:写脚本!解决问题的过程就像RPG游戏闯关一样,让人充满成就感。
于是,我们撸起袖子,干了这件事。目标很明确:
把切换分支、合并、推送这一整套操作“自动化”,让它快到你连咖啡都喝不上一口。
第一关:初版脚本问世
第一版脚本直接用Node.js实现,使用child_process
模块来调用Git命令。逻辑很简单:逐步执行“获取当前分支名”、“切换分支”、“拉取代码”、“合并分支”、“推送代码”、“切换回原分支”这些操作。下面是初版代码:
const { exec } = require('child_process')
// 获取命令行参数
const targetBranch = process.argv[2]
if (!targetBranch) {
console.error('请提供目标分支名')
process.exit(1)
}
// 获取当前分支名
exec('git rev-parse --abbrev-ref HEAD', (err, stdout, stderr) => {
if (err) {
console.error(`exec error: ${err}`)
return
}
const currentBranch = stdout.trim()
// 切换到目标分支
exec(`git checkout ${targetBranch}`, (err, stdout, stderr) => {
if (err) {
console.error(`exec error: ${err}`)
return
}
// 拉取目标分支的最新代码
exec(`git pull origin ${targetBranch}`, (err, stdout, stderr) => {
if (err) {
console.error(`exec error: ${err}`)
return
}
// 将当前分支的代码合并到目标分支
exec(`git merge ${currentBranch} --no-ff`, (err, stdout, stderr) => {
if (err) {
console.error(`exec error: ${err}`)
return
}
// 推送到远端
exec(`git push origin ${targetBranch}`, (err, stdout, stderr) => {
if (err) {
console.error(`exec error: ${err}`)
return
}
console.log(`代码已成功合并到${targetBranch}分支并推送到远端`)
// 切换回原来的分支
exec(`git checkout ${currentBranch}`, (err, stdout, stderr) => {
if (err) {
console.error(`exec error: ${err}`)
return
}
console.log(`已切换回${currentBranch}分支`)
})
})
})
})
})
})
尽管功能完整,但这个脚本的问题也很明显:回调地狱让代码看起来就像个“意大利面条”,不够优雅!而且处理错误的逻辑不够清晰,维护起来比较麻烦。
一键搞定:如何用自动化脚本拯救“手动合并”焦虑
你是否也经历过这样的时刻:刚写完一大段代码,正准备起身倒杯咖啡放松一下,却猛然想起还有分支需要合并到测试环境。不仅要切换分支、拉代码、合并,还得小心翼翼避免操作失误,仿佛在踩一地的“雷”。更惨的是,这样的操作还不是一次两次,而是反复!
在我们国际商城项目的开发初期,这一幕几乎每天都在上演。频繁的手动操作不仅让人疲惫,还极大地浪费了开发时间。于是,我们决定放大招:用脚本解放双手,让开发者能安心享受咖啡的香气,而不是纠结在Git命令中。
问题重现:小操作背后的大痛点
每次将功能分支合并到测试环境分支的流程都差不多是这样的:
- 切换到目标分支(测试环境分支)。
- 拉取最新代码。
- 将当前分支合并到目标分支。
- 推送合并后的代码到远程。
- 切回原来的功能分支。
看起来流程简单?但当你一天需要重复三五次、还要担心是否手抖输错命令时,这种“简单”就变成了开发者的心智噩梦。
问题显而易见:我们需要一种能“傻瓜化”这一切的方式。能不能写个脚本,一键搞定这些事?
决策:写!脚!本!
作为开发者,遇到机械重复的工作,第一个念头当然是:写脚本!解决问题的过程就像RPG游戏闯关一样,让人充满成就感。
于是,我们撸起袖子,干了这件事。目标很明确:
把切换分支、合并、推送这一整套操作“自动化”,让它快到你连咖啡都喝不上一口。
第一关:初版脚本问世
第一版脚本直接用Node.js实现,使用child_process
模块来调用Git命令。逻辑很简单:逐步执行“获取当前分支名”、“切换分支”、“拉取代码”、“合并分支”、“推送代码”、“切换回原分支”这些操作。下面是初版代码:
const { exec } = require('child_process')
// 获取命令行参数
const targetBranch = process.argv[2]
if (!targetBranch) {
console.error('请提供目标分支名')
process.exit(1)
}
// 获取当前分支名
exec('git rev-parse --abbrev-ref HEAD', (err, stdout, stderr) => {
if (err) {
console.error(`exec error: ${err}`)
return
}
const currentBranch = stdout.trim()
// 切换到目标分支
exec(`git checkout ${targetBranch}`, (err, stdout, stderr) => {
if (err) {
console.error(`exec error: ${err}`)
return
}
// 拉取目标分支的最新代码
exec(`git pull origin ${targetBranch}`, (err, stdout, stderr) => {
if (err) {
console.error(`exec error: ${err}`)
return
}
// 将当前分支的代码合并到目标分支
exec(`git merge ${currentBranch} --no-ff`, (err, stdout, stderr) => {
if (err) {
console.error(`exec error: ${err}`)
return
}
// 推送到远端
exec(`git push origin ${targetBranch}`, (err, stdout, stderr) => {
if (err) {
console.error(`exec error: ${err}`)
return
}
console.log(`代码已成功合并到${targetBranch}分支并推送到远端`)
// 切换回原来的分支
exec(`git checkout ${currentBranch}`, (err, stdout, stderr) => {
if (err) {
console.error(`exec error: ${err}`)
return
}
console.log(`已切换回${currentBranch}分支`)
})
})
})
})
})
})
尽管功能完整,但这个脚本的问题也很明显:回调地狱让代码看起来就像个“意大利面条”,不够优雅!而且处理错误的逻辑不够清晰,维护起来比较麻烦。
加入快捷命令:让脚本更方便运行
初版脚本虽然功能完整,但每次都要在命令行手动输入 node ./scripts/mergeBranch.js <目标分支>
来运行,还是略显麻烦。为了让团队成员能够更快捷地使用脚本,我们决定将它集成到项目的package.json
文件中,通过npm run
命令轻松调用。
配置步骤
- 打开项目根目录下的
package.json
文件。 - 在
scripts
字段中新增一条命令:
"merge:dev": "node ./scripts/mergeBranch.js dev"
这条命令的作用是:将当前分支的代码合并到dev
分支,并触发脚本的所有操作。
修改后的package.json
文件示例:
{
"name": "your-project",
"version": "1.0.0",
"scripts": {
"start": "vite",
"build": "vite build",
"merge:dev": "node ./scripts/mergeBranch.js dev"
},
"dependencies": {
// 省略其他依赖
}
}
使用方法
在终端运行以下命令:
npm run merge:dev
这条命令会自动执行脚本,将当前分支的代码合并到dev
分支,无需再手动输入目标分支名称。脚本完成所有操作后,会提示合并完成并切换回原分支。
第二关:优化脚本,解放灵魂
为了解决初版的缺陷,我们进行了优化:使用Promise
和async/await
重构代码。这样一来,不仅代码逻辑更清晰,还能轻松扩展和处理错误。优化后的代码如下:
const { exec } = require('child_process')
// 封装exec为Promise返回
const execPromise = command => {
return new Promise((resolve, reject) => {
exec(command, (err, stdout, stderr) => {
if (err) {
reject(err)
} else {
resolve(stdout)
}
})
})
}
async function mergeBranch() {
// 获取命令行参数
const targetBranch = process.argv[2]
if (!targetBranch) {
console.error('请提供目标分支名')
process.exit(1)
}
try {
// 获取当前分支名
let currentBranch = await execPromise('git rev-parse --abbrev-ref HEAD')
currentBranch = currentBranch.trim()
// 切换到目标分支
await execPromise(`git checkout ${targetBranch}`)
// 拉取目标分支的最新代码
await execPromise(`git pull origin ${targetBranch}`)
// 将当前分支的代码合并到目标分支
await execPromise(`git merge ${currentBranch} --no-ff`)
// 推送到远端
await execPromise(`git push origin ${targetBranch}`)
console.log(`代码已成功合并到${targetBranch}分支并推送到远端`)
// 切换回原来的分支
await execPromise(`git checkout ${currentBranch}`)
console.log(`已切换回${currentBranch}分支`)
} catch (error) {
console.error(error)
}
}
mergeBranch()
是不是清爽多了?借助async/await
,脚本的流程一目了然,处理错误也变得优雅可靠。