一个人的Git

172 阅读3分钟

Git.jpg

背景

花了一年时间断断续续做了个物流项目,从最初的PC-Web、微信小程序演进扩展裂变到维护16个项目,每个项目又维护多个分支。维护难度指数级上升。多个项目联动修改的场景,在Git使用上面临巨大挑战。场景驱动打造一个人的Git。

项目梳理

业务层(8)

  1. PC-Web
  2. 微信小程序
  3. Flutter-App(物流端)
  4. Flutter-App(司机端)
  5. Flutter-App(把枪端)
  6. Flutter-App(发货端)
  7. Flutter-App(收货端)
  8. PC-官网

部署层(1)

  1. Nginx独立项目

公共层(2)

  1. Flutter-Common(公共控件)
  2. Flutter-Api(Api/Model管理)

定制插件层(5)

  1. Flutter-Plugin(定制版amap)
  2. Flutter-Plugin(定制版蓝牙打印btPrinter)
  3. Flutter-Plugin(定制版定位Location)
  4. Flutter-Plugin(定制版扫码Scan)
  5. Flutter-Plugin(定制版把枪扫码Pda)

Git维护梳理

项目分支修改频率类型
PC-Webdev业务层
微信小程序dev业务层
物流端APPdev业务层
司机端APPdev业务层
把枪端APPdev业务层
发货端APPdev业务层
收货端APPdev业务层
PC-官网dev业务层
Nginx项目master部署层
Flutter公共控件master公共层
Flutter APIdev公共层
定制版Amaprefresh(过渡分支)插件层
定制版btPrintermaster插件层
定制版Locationmaster插件层
定制版Scanmaster插件层
定制版PDAmaster插件层

改进思路

参考SVN管理,把所有项目放到一个大目录中,按照类型分小目录。在logistic目录下执行Git指令,同步操作所有项目的Git管理,在business下执行Git指令,同步操作业务层项目的Git管理。

image.png

方案落地

使用子进程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指令

image.png 指令检查

image.png

构建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

image.png node git.js --autopush

image.png

后记

因场景需求开发的小脚本,掘友们有其它真香工具或脚本可以推荐。