使用 git 进行模块化开发部署

作者:frank 发表日期:2017-04-25 22:07:52 更新日期:2017-04-25 22:09:38 分类:猿文色

摘要

使用 git 进行模块化开发部署

正文

现状

  1. 负责的项目越来越大,功能越来越多;
  2. 前端虽然是一个人,但是后台已经由多个人分别负责不同的功能模块了;
  3. 前端要在同一段时间与不同的后台人员对接,调试接口;
  4. 各个功能模块的开发周期不一样,上线时间也不同;
  5. 除了功能模块外的公共功能部分(比如组件库)难以更新维护。

问题

  1. 前端由于要对接不同的后台功能,导致前端代码的分支越来越多,几乎每个功能模块都在一个分支中;
  2. 每天同时要对接不同的后台功能,引起频繁的切换分支,导致有些提交只是为了暂存代码,失去了代码管理的意义;
  3. 如果在功能模块分支修改了公共功能部分(比如更新或添加了组件),则必须要等到此功能模块发布后(合并到 stable 分支后)才可以共享公共部分的功能;
  4. 代码合并容易出现冲突,尤其在多人开发的时候,解决冲突可能导致功能丢失。

理想中

  1. 核心代码不必为了某个功能开发开辟不同的分之;
  2. 各个功能模块可以独立开发,独立部署;
  3. 整个项目可以按需添加所需的功能模块,按需部署。

实现

  1. 首先将公告模块部分分离出来,独立为一个代码仓库 M;
  2. 各个功能模块分离出来,独立为一个个代码仓库 F1,F2,F3...;
  3. 各个功能模块拥有不同的分支:master,stable,develop,bugfix...;
  4. 如果需要部署一个新的项目(拥有不同的功能模块),必须从 A 仓库 使用 git fork 一份代码形成一个新的代码仓库 M1,M1 中开发人员可以修改公共部分代码,比如添加自己的主题;
  5. 视 M1 的功能需求使用 git submodule 添加不同的功能模块;
  6. 每当 M 有更新的时候,使用 git fetch 将更新合并到 M1 仓库。

仍然存在的问题

  1. 公共功能部分可能仍然需要根据不同的功能切换不同的分支,如果某个功能开发整的影响到公共部分,比如某个功能模块需要在用户创建应用的时候多输入一个字段,这就比较坑了,但是这种概率比较小。一般来说,公共功能部分只需要 master 和 stable 分支就足够了;
  2. 每次更新功能模块 F 后,都必须更新 M1,因为 submodule 的 commit log 更新了,这个导致 M1 存在很多“子模块更新”等类似的无实质性的提交;
  3. M 更新后,需要将代码合并到 M1,导致 M1 存在很多 merge 提交;
  4. 不能使 M1 更新后的代码合并到 M,因为 M1 中可能包含属于 M1 的特殊更新,比如主题色,项目配置,所有公共部分的更新必须从 M 合并到 M1;
  5. Jenkins 持续集成时可能 git submodule 会遇到权限问题,网上已有解决方案;

备注 git 命令

如何使 fork 出的代码保持最新

  1. 在 fork 出的代码根目录配置上游代码路径:git remote add upstream git@... (M 的代码仓库地址)
  2. 获取最新的上游代码:git fetch upstream
  3. 切换到本地 master 分支:git checkout master
  4. 合并最新的上游代码:git merge upstream/master

如何在 M1 中更新子模块

  1. 先 clone 一份 M1 的代码,git clone ...
  2. 在代码根目录执行 git submodule init 和 git submodule update;
  3. 如果子模块有更新,则要进入到子模块所在目录,执行 git pull;
  4. 也可以批量更新子模块 git submodule foreach git pull;

附打包脚本

# 判断 M1 是否处于 stable 分支
branch=`git branch | sed -n -e 's/^\* \(.*\)/\1/p'`
echo "main module's current branch is $branch\n"
if [ $branch != 'stable' ];
then
    echo "not in stable branch, exit...."
    exit -1
fi

# 判断各个功能模块 F1,F2... 是否处于 stable 分支
sub_module_branch=`git submodule foreach git branch | sed -n -e 's/^Entering\(.*\)/submodule\1/p' -e 's/^\* \(.*\)/\1/p'`

oldIFS=$IFS
IFS=$'\n'
index=0
for item in $sub_module_branch;
do
    index=$(($index+1))
    if [[ $((index%2)) = 0 ]] && [[ $item != 'stable' ]];
    then
        IFS=$oldIFS
        echo "current branch is $item, not in stable branch, exit..."
        exit -1
    elif [ $((index%2)) = 0 ];
    then
        echo "current branch is $item\n"
    else
        echo "$item"
    fi
done

IFS=$oldIFS

# 使用 gulp dist 打包
echo "start build dist"

gulp dist