Gitflow 是一个基于 feature 分支管理的版本发布方案。它是由荷兰程序猿 Vincent Driessen 设计研发,开源项目地址 gitflow-avh。 大致流程是:

  • 不同 feature 在不同 feature 分支上单独开发(或测试)。
  • 确定版本号和此版本将要发布的功能后,将相应 featustre 分支统一向 develop 分支合并,然后拉出新的 release 预发布分支。
  • release 分支作为持续集成关注的分支,修复 bug。
  • 待 release 分支测试验收通过后,统一向 master 分支和 develop 分支合并,并在 master 分支打 tag。
  • 根据 tag 发布 apk 版本。

若线上发现严重 bug,需走 hotfix 流程。

  • 基于 master 分支拉出 hotfix 分支修复线上问题。
  • bug 修复完成统一向 master 和 develop 分支合并。
  • master 分支打上新的 tag,发布新版本。

下面将介绍如何使用 Gitflow 命令完成上述版本发布,一条 Gitflow 指令可能对应了一系列 git 命令,为的是规范化开发流程,提高代码管理效率。

Mac 平台安装

brew install git-flow

brew 表示 Homebrew,它是 mac 平台常用的包管理器,没有安装则需先安装,安装可参考 Mac OS 下 brew 的安装和使用。

初始化

先将远程仓库克隆到本地。

git clone <project_url>

各种初始化 Gitflow 配置。

git flow init

命令行会提示你是否修改 Gitflow 提供的默认分支前缀。不同场景的分支前缀不同,默认情况下分支前缀是这样的:

场景分支前缀
新功能feature
预发布release
热修复hotfix
打 tag

分支前缀的作用是区分不同分支的使用场景,同时当你使用 Gitflow 命令时就不需手动添加分支前缀了,Gitflow 会帮你加上。 比如开发新功能需创建一个 feature 分支,名为 gitworkflow,使用下面的代码将会创建一个名为 feature/gitworkflow 本地分支。

git flow feature start gitworkflow

通常情况下不需要修改默认的命名前缀,只需加上-d 就可跳过修改命名阶段。

git flow init -d

行为/Action

通常来说,一种场景的完整生命周期应至少包含以下几种行为:

  • start 开始开发
  • publish 发布到远程分支
  • finish 完成开发、合并到主分支

我们首先以 feature 场景为例,看看如何完成工作流。

feature 流程

start

新功能开始开发前,需准备好开发分支。

git flow feature start <feature_name>

执行上面的命令将会在本地创建名为<feature_name>的分支,并切换到该分支,而且不论当前所处哪个分支都是基于 develop 分支创建,相当于执行了下面的 git 的命令。

git checkout -b feature/<feature_name> develop

需要注意基于的是本地的 develop 分支,执行此命令前一般需要拉取最新的远程代码。

publish

在本地开发完成新功能并 commit 后,需要将本地代码 push 到远程仓库。

git flow feature publish <feature_name>

这行指令做了三件事。

  • 创建一个名为 feature/<feature_name>的远程分支。
  • 本地分支 track 上述远程分支。
  • 如果本地有未 push 代码,则执行 push。

转换成 git 命令就是下面的样子:

git push origin feature/<feature_name>
git push --set-upstream origin feature/<feature_name>
git push origin

注意:如果已经执行过 publish 后又有新的代码需 push,再次执行将报错,因为它始终会试图创建一个远程分支。此时需执行正常的 push 命令 git push origin。

finish

当功能开发完毕后就将进入测试阶段,此时需将一个或多个 feature 分支统一合并到 develop 分支。

git flow feature finish <feature_name>

这行指令也做了三件事。

  • 切换到 develop 分支。
  • 合并代码到 develop 分支
  • 删除本地 feature/<feature_name>分支。 等价于执行下面的 git 命令:
git checkout develop
git merge feature/<feature_name>
git branch -d feature/<feature_name>

如果 merge 时发生了冲突,则在第二步 merge 时终止流程,即不会再删除本地分支。但当前已处于 develop 分支,待本地冲突解决并 commit 后,重新执行git flow feature finish <feature_name>即可完成 finish 流程。 细心的同学可以已经发现 finish 还有两件事没做。

  • develop 分支代码还未 push。
  • 未删除远程分支 feature/<feature_name>。

也就是还需执行

git push origin develop
git push origin :feature/<feature_name>

release 流程

当新功能开发完毕,将进入测试阶段,此时需要基于 develop 分支拉出 release 分支进行集成测试,也有将 release 场景作为预发布环境进行测试的,即 feature 场景已完成常规测试,在这种情况下,一般而言 release 只有少数改动。在这里我们先不讨论项目流程问题。 使用 start 指令开启一个 release 场景,通常以版本号命令,我们以 v2.0 为例:

git flow release start v2.0

此命令会基于本地的 develop 分支创建一个 release/v2.0 分支,并切换到这个分支上。 为了让其他协同人员也能看到此分支,需要将其发布出去。

git flow release publish v2.0

以上和 feature 场景十分类似。 待测试通过需要发布正式版:

git flow release finish v2.0

这一步做的动作有点多,大致是:

  • git fetch
  • release/v2.0 分支代码向 master 合并。
  • 生成名为 v2.0 的 tag。
  • release/v2.0 分支代码向 develop 合并。
  • 删除本地 release/v2.0 分支。
  • 切换回 develop 分支。

如果 merge 产生冲突不会终止流程,只是不会将本地的 release 分支删除,待解决完冲突后需再次执行 finish 指令。 另外需要注意的是,如果本地还有未 finish 的 release 分支,将不允许使用 start 指令开启新的 release 分支,这一点是对并行发布的一个限制。 release finish 只是完成了本地代码的一系列操作,还需要同步到远程仓库。

git push origin develop
git push origin master
git push origin v2.0

或者使用下面的命令推送所有的分支和 tag。

git push origin --all
git push origin --tags

hotfix 流程

当 tag 打完,也表示正式版本发布出去了,如果此时在线上发现了严重的 bug,需要进行紧急修复。 此时我们假设版本号变为 v2.0-patch。

git flow hotfix start v2.0-patch

这将创建一个 hotfix/v2.0 本地分支并切换到该分支。 hotfix 没有 publish 指令,认为 hotfix 应该是个小范围改动,不需要其他协同人员参与。 待本地修改结束 commit 后,执行 finish 指令。

git flow hotfix finish v2.0-patch

按照 Gitflow 工作流,它会执行下面的任务,与 release 基本一致。

  • git fetch
  • hotfix/v2.0-patch 分支代码向 master 合并。
  • 生成名为 v2.0-patch 的 tag。
  • hotfix/v2.0-patch 分支代码向 develop 合并。
  • 删除本地 hotfix/v2.0-patch 分支。
  • 切换回 develop 分支。