一种基于git分支的开发和部署流程

前言

如今在多人协作开发的团队中,免不了要用到版本控制系统(Version control system),常见的有SVNGit。但是当公司和团队增长到一定程度时,就需要考虑一些涉及到稳定性的问题。比如

  1. 如何严格控制线上代码的合并权限
  2. 如何管理多个并行开发的feature的测试
  3. 线上产生问题时如何快速回滚
  4. 如何减少开发人员合并代码的人工疏漏

这篇文章会介绍一种基于git分支的开发部署流程,大部分思路来自于实习部门的实践,我对其做了一些抽象和补充。相信大公司内部肯定有自己成熟的开发和部署流程,这边只是简单介绍思路,推荐开发还比较原始的小公司或者小团队使用,可以更好地管理项目迭代。

分支管理

项目中将主要分为三种分支

  1. master —— 线上稳定代码
  2. dev/x.x.x —— 部署专用feature分支,一个版本号代表一个feature,使用Semantic Versioning 2.0.0 语义化版本规范。
  3. * —— 个人开发分支,随意命名

两个角色可以对分支进行操作,部署系统和开发者。下面介绍各个分支的具体作用与特点

master

master分支代表已经运行在线上的稳定代码,只有部署系统才有权限修改master分支。其他分支必须在本地合并master的最新修改之后才能发布或者push到远程,保证远程的分支的代码始终领先于master分支。

dev

dev分支命名格式固定为dev/x.x.x(前缀随意,但各dev分支一定要相同),方便脚本识别。版本号根据当前feature决定,应始终大于master的版本号。

在部署系统中可以选择某个版本号的dev分支,将其发布至任意机器(日常/预发/线上)。发布线上时系统会自动将代码合进master分支(因为开发时本地已经合并过master所以不会有代码冲突),线上发布之后会将对应的dev分支删除。

个人分支

分支名随意,所有开发的操作都应该在这个分支下完成(因为dev分支会被删除,master分支没有权限,只有这个是可控的分支吗)

开发流程

  1. 在个人分支上进行开发,保证领先于master分支并处理相关冲突
  2. push时由另一名同事进行code review之后才能提交成功
  3. 往dev分支merge代码,通过部署系统发布测试环境
  4. 需要修改代码时,重新走一遍步骤1-3
  5. 最后上线时,在部署系统选择对应版本号的dev分支

部署流程

  1. 部署系统读取dev分支,检查版本号以及commit是否领先于master
  2. 部署系统将原有master分支用tag存下来,命名为相应版本号(用于快速回滚)
  3. 部署系统在master分支进行merge dev分支操作
  4. 部署系统删除dev分支

回顾问题

我们再来看这个系统是如何解决之前提到的问题:

  1. 如何严格控制线上代码的合并权限 —— 只有部署系统才有权限修改master分支,减少了开发的误操作。
  2. 如何管理多个并行开发的feature的测试 —— 多个并行开发的feature现在用不同的版本号代表,各自有独立的dev分支,不同的测试机器可以选择不同的分支部署进行测试。
  3. 线上产生问题时如何快速回滚 —— 部署线上时始终会产生一个以版本号为名称的tag版本的代码(什么是tag),这样部署系统可以快速找到上个稳定版本的代码进行回滚操作。
  4. 如何减少开发人员合并代码的人工疏漏 —— 强制远程代码必须领先于master,这样开发在日常迭代时必须多次合并master的改动,每次合并小量代码,更方便解决冲突,防止在部署前一次性合并大量代码导致人工疏漏。

总结

在团队逐渐扩张,项目越来越大的过程中,流程的重要性就渐渐超过了开发者素质的重要性,大型项目迭代中要切记不能过于依赖开发者自身水平,因为这是一个不可控因素。很多问题都能通过完善流程去解决,这边也只是介绍其中一个流程,其他还包括评审,测试等各种流程,未来或许在这几个方面也会做一些研究。

附录:git hook pre-push

因为公司内部部署系统的种种限制,上面的想法我只在我们团队实现了很小一部分。其中如何在提交时强制要求领先于master就是用git hookpre-push实现的。

git hook是git提供的工具,可以在某些操作的前后触发特定脚本,顾名思义pre-push就是在push前触发的脚本。一般来说脚本应该放在git服务器上,方便统一管理,但是我并没有公司git服务器的权限,所以只能放在项目本地,但在本地还有一个问题就是git hook脚本是放在.git文件夹下的,无法随着项目一起提交维护。所以这里用到了一个npm包husky来帮助我管理git hook脚本,pre-push检查脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/bin/bash

while read local_ref local_sha remote_ref remote_sha
do
commit=`git rev-list -n 1 origin/master ^$local_ref`
echo $commit
if [ -n "$commit" ]
then
echo >&2 -e "Local branch $local_ref is behind origin/master"
echo >&2 -e "Please run ' git merge origin/master ' first"

exit 1
fi
done

exit 0