背景
花了一年时间断断续续做了个物流项目,从最初的PC-Web、微信小程序演进扩展裂变到维护16个项目,每个项目又维护多个分支。维护难度指数级上升。多个项目联动修改的场景,在Git使用上面临巨大挑战。场景驱动打造一个人的Git。
项目梳理
业务层(8)
- PC-Web
- 微信小程序
- Flutter-App(物流端)
- Flutter-App(司机端)
- Flutter-App(把枪端)
- Flutter-App(发货端)
- Flutter-App(收货端)
- PC-官网
部署层(1)
- Nginx独立项目
公共层(2)
- Flutter-Common(公共控件)
- Flutter-Api(Api/Model管理)
定制插件层(5)
- Flutter-Plugin(定制版amap)
- Flutter-Plugin(定制版蓝牙打印btPrinter)
- Flutter-Plugin(定制版定位Location)
- Flutter-Plugin(定制版扫码Scan)
- Flutter-Plugin(定制版把枪扫码Pda)
Git维护梳理
| 项目 | 分支 | 修改频率 | 类型 |
|---|---|---|---|
| PC-Web | dev | 高 | 业务层 |
| 微信小程序 | dev | 中 | 业务层 |
| 物流端APP | dev | 高 | 业务层 |
| 司机端APP | dev | 高 | 业务层 |
| 把枪端APP | dev | 中 | 业务层 |
| 发货端APP | dev | 高 | 业务层 |
| 收货端APP | dev | 高 | 业务层 |
| PC-官网 | dev | 低 | 业务层 |
| Nginx项目 | master | 低 | 部署层 |
| Flutter公共控件 | master | 中 | 公共层 |
| Flutter API | dev | 高 | 公共层 |
| 定制版Amap | refresh(过渡分支) | 低 | 插件层 |
| 定制版btPrinter | master | 低 | 插件层 |
| 定制版Location | master | 低 | 插件层 |
| 定制版Scan | master | 低 | 插件层 |
| 定制版PDA | master | 低 | 插件层 |
改进思路
参考SVN管理,把所有项目放到一个大目录中,按照类型分小目录。在logistic目录下执行Git指令,同步操作所有项目的Git管理,在business下执行Git指令,同步操作业务层项目的Git管理。
方案落地
使用子进程child_process执行git命令
// 使用子进程执行git命令
startChildProcess(command, params, project) {
return new Promise((resolve, reject) => {
var process = spawn(command, params, {
cwd: this.cwd,
});
var logMessage = `${command} ${params[0]}`;
var cmdMessage = '';
process.stdout.on('data', (data) => {
if (!data) {
reject(`${logMessage} error1 : ${data}`);
} else {
if (params[0] === 'pull') {
cmdMessage += data.toString();
} else cmdMessage = data.toString();
}
});
process.on('close', (data, e1, e2, e3) => {
if (data) {
reject(`${logMessage} error2 ! ${cmdMessage}`);
} else {
resolve(cmdMessage);
}
});
});
}
封装node指令
指令检查
构建git任务队列
node判断当前执行的目录,检索出目录下所有项目及分支。匹配预设队列构建完整任务队列信息
// 在目标目录下执行--branch,获取执行队列
node git.js --branch
// 预设队列
[
{ "v": "common/logistic-app-api", "l": "API", "name": "logistic-app-api"},
{ "v": "common/logistic-app-common", "l": "公共控件", "name": "logistic-app-common" },
{ "v": "business/logistic-app", "l": "物流端", "name": "logistic-app" },
{ "v": "business/logistic-cee-app", "l": "收货端", "name": "logistic-cee-app"},
{ "v": "business/logistic-cor-app", "l": "发货端", "name": "logistic-cor-app"},
{ "v": "business/logistic-driver-app", "l": "司机端", "name": "logistic-driver-app" },
{ "v": "business/logistic-pda-app", "l": "把枪PDA", "name": "logistic-pda-app" },
{ "v": "plugin/logistic-btprinter-plugin", "l": "蓝牙打印插件", "name": "logistic-btprinter-plugin" },
{ "v": "plugin/logistic-pda-plugin", "l": "把枪PDA插件", "name": "logistic-pda-plugin" },
{ "v": "plugin/logistic-amap", "l": "地图插件", "name": "logistic-amap" },
{ "v": "plugin/logistic-amap-location", "l": "定位插件", "name": "logistic-amap-location", "fixedBranch": "" },
{ "v": "plugin/logistic-scan", "l": "扫码插件", "name": "logistic-scan" }
]
执行队列和预设队列name匹配,补充中文项目名称、是否固定分支信息。检测执行分支和预设分支,如果遇到执行分支不同于预设分支,询问是否强制执行执行分支。
yes继续no执行队列中忽略掉当前项目
批量pull
function batchPull() {
var singleProject = process.argv[3] || '';
var promises = [];
var pullProjects = projects;
if (singleProject) {
pullProjects = pullProjects.filter((v) => v.name === singleProject);
}
pullProjects.forEach((item) => {
promises.push(
new Promise((resolve, reject) => {
var isLinux = os.type() == 'Darwin' || os.type() == 'Linux';
var path = isLinux ? `./${item.v}` : `./${item.v}`.replace(/\//g, '\\');
var git = new GitTools(path);
var currentBranch = await git.currentBranch();
var branch = currentBranch.replace(/\s/g, '') || 'master';
var branchLog = `\x1B[36m${branch}\x1B[0m`;
git
.pull(branch, item.l)
.then((res) => {
console.log(`[${item.l} ${item.v}${branchLog}]`);
if (res.includes('Already up-to-date')) {
console.log(`\x1B[33m❤ 已经是最新状态\x1B[0m\n`);
} else {
console.log(res);
console.log(`\x1B[32m✔ Success git pull\x1B[0m\n`);
}
resolve(true);
})
.catch((err) => {
console.log(`[${item.l} ${item.v}${branchLog}]`);
console.log(err);
console.log('\x1B[31m✘ Failed git pull,Please check Conflict\x1B[0m\n');
resolve(false);
});
})
);
});
Promise.all(promises);
}
效果
node git.js --pull
node git.js --autopush
后记
因场景需求开发的小脚本,掘友们有其它真香工具或脚本可以推荐。