3.6 Git 的开发流程

    到这里为止,我们一起了解了分布式版本管理系统所具有的灵活性,以及 Git 的分支、合并、标签功能的便捷和高速。

    那么,在实际使用 Git 进行团队开发的过程中,应该采用怎样的开发流程呢?

    以 Subversion 为代表的中央集权型版本管理系统中能执行的项目并不多,所以开发流程也自然而然地只有一种。另一方面,因为 Git 过于灵活,所以容易让人产生困惑,不知道应该采用怎样的开发流程。

    老实说,Git 开发流程现在似乎还没有固定的模式。原因之一是 Git 不仅功能丰富而且非常灵活,即便不规定流程也还是能正常使用。本节将介绍比较常用的 Git 工作流的模式。

    3.6.1 Git 工作流的模式

    Git 的工作流大致有如下几种模式。

    • 中央集权型工作流

    • GitHub 型工作流

    ●…… 中央集权型工作流

    Pro Git 48 中也举过这样的例子,即像以前的 Subversion 那样设置 1 个中央代码库,全体开发人员以此为唯一的 Push/Pull 对象,将环境克隆到本地机器上(图 3.6)。

    48 该书第 2 版将由人民邮电出版社出版。——编者注

    3.6 Git 的开发流程 - 图1

    图 3.6 中央集权型工作流

    该工作流的优点是操作和 Subversion 基本相同,思考方式也不需要太大的改变。另外,借助把 Subversion 的代码库视作 Git 来进行交互的工具 git-svn,实际的中央代码库可以仍然是 Subversion。当现有的代码库是 Subversion,并且移植到 Git 的成本很高时,这种情况下该工具是非常有效的。

    ●…… GitHub 型工作流

    Pro Git 中称之为“整合经理型工作流”。因为该流程和 GitHub 的机制基本相同,所以本书称之为 GitHub 型工作流。

    GitHub 型工作流同样也设置 1 个代码库为中央代码库,但开发人员会各自从中央代码库 Fork 出自己的远程代码库,并将其克隆到本地机器上。

    GitHub 型工作流的方式是,在日常开发中将修改 Push 到 Fork 出的自己专用的远程代码库上,当修改相对稳定后,请中央代码库的管理者进行 Pull 操作(图 3.7)。

    3.6 Git 的开发流程 - 图2

    图 3.7 GitHub 型工作流

    这样的流程基本就是 GitHub 的流程。其优点在于不需要等待中央代码库的维护或合并操作,各开发人员能够并行地进行作业。开发人员拥有自己独立的代码库,可以在代码库之间自由地相互 Push/Pull。这也可以说是只有分布式版本管理系统才具备的优点。

    在 Git 的系统上应用该流程时,因为没有任何约束,所以运用中不注意的话容易造成混乱。如果想利用这种方式,推荐使用提供以这种方式调整后的工作流的 GitHub。

    3.6.2 分支策略的模式

    在已经设置中央代码库的情况下,关于发布时的发布分支应该如何处理、开发时是否要创建 topic 分支、修正 bug 的分支要怎样处理等分支运用的策略也有着各种各样的模式。

    ●…… git-flow

    git-flow 是 2010 年 Vincent Driessen 在“A successful Git branching model”这篇博客 49 中提出的分支运用策略。同时也指为了支持该分支策 略而编写的工具。

    49 http://nvie.com/posts/a-successful-git-branching-model/

    该分支策略在分布式版本管理系统的工作流中稍许引入了中央集权型版本管理系统的长处,可以说是结合了双方优点的团队开发流程。通过在团队内部统一管理创建分支的方法、合并的做法以及关闭分支的方法,来实现 git-flow 分支策略。

    git-flow 提议以固定的模式在中央代码库中创建两个主分支,在各开发人员的代码库中创建 3 个辅助分支(图 3.8)。

    3.6 Git 的开发流程 - 图3

    "A successful Git branching model" by Vincent Driessen(引自http://nvie.com/posts/a-successful-git-branching-model/

    图 3.8 git-flow

    想详细了解该分支策略的读者请参考上述博客或相关资料。

    图 3.8 中的各个分支的含义如下。

    • 主分支

    在中央代码库和从中央代码库克隆的各开发人员的代码库中一直存在的主要的分支

    • Master

    为发布而建的分支。每次发布时都打上标签

    • Develop

    开发用的分支。发布之前的最新版本

    • 辅助分支

    原则上只存在于各开发人员的代码库中,是发挥相应的功能后就被删除的临时分支

    • feature

    从 develop 分离出来的被用于开发特定功能的分支。功能开发结束后被合并到 develop 中

    • release

    从 develop 分离出来的为发布做准备的分支。在发布的准备工作期间,为了避免多余的 feature 混杂到发布中而创建的分支。发布结束后被合并到 master 和 develop 中

    • hotfix

    主要是在发布后的产品发生故障时紧急创建的分支。直接从 master 分离,bug 修正后再合并到 master 并打上标签。为了避免将来遗漏这个 bug 的修正,还要合并到 develop。如果此时有正在发布作业中的 release 分支,还要向 release 进行合并

    这样的分支策略条理清晰且容易理解,能够立刻投入到实际运用中。为了支持该分支策略,还提供有 Git 扩展脚本(git-flow 脚本)。通过使用脚本,运用会变得更加容易。

    在有一定数量的人员的开发中,按照 git-flow 分支策略这样整理、运用分支,管理也会变得简单。

    问题在于运用有些复杂,需要记忆的内容比较多。并且如果没有 git-flow 提供的 git-flow 脚本的话,运用会比较困难。特别是在使用 GUI 工具的情况下就无法沾到 git-flow 脚本的光了,这点需要注意 50 。

    50 Atlassian 提供的 SourceTree 工具好像支持 git-flow 分支策略。

    ●…… github-flow

    github-flow 是由 Pro Git 的作者兼 GitHub 长官 Scott Chacon 在博客 51 中发表的 GitHub 的工作流。

    51 http://scottchacon.com/2011/08/31/github-flow.html

    Scott Chacon 也认为 git-flow 是非常出色的,但就实际运用比较复杂这方面,他列举了如下问题。

    问题之一在于 Git 本身就绝非容易理解,此外还必须理解分支策略。

    问题之二在于使用 GUI 工具的话就无法使用 git-flow 脚本,因此就不得不自己充分理解分支策略。何况难以理解分支策略的人往往也无法合理使用 git-flow 脚本,这样的人最终就无法合理运用 git-flow。

    针对上述问题,GitHub 采用了下面这些更为简单的做法。这就是所谓的 github-flow。

    • master 的内容都可以进行发布

    • 添加内容时直接从 master 新建分支

    • 创建的分支在本地环境上提交,并以同名的分支定期向远程代码库进行 Push

    • 开发结束后向 master 发送 Pull Request

    • Pull Request 通过 review 之后合并到 master,并从 master 向正式环境发布

    还有一点在上述项目中没有提到,那就是 github-flow 是以使用 GitHub 进行开发为前提的 52 。

    52 因为是 github-flow,所以这也是理所应当的。

    从博客的图片中可以看出,github-flow 没有 Fork 中央代码库,而是采用了代码库唯一的方式(中央集权型版本管理系统)。

    该方式的特点在于简单、易于理解。开发人员只需要记住以下 3 点就行了。

    • master 是用于发布的,不要直接在 master 上进行修改

    • 开始作业时要先创建分支

    • 作业结束后向 master 发送 Pull Request53

    53 Pull Request 不仅在代码库之间,在同一代码库的分支之间也能发送。令人感到意外的是不知道这一点的人似乎还挺多的。

    为了使 Pull Request 在通过 review 之后能立即进行合并并发布,在 Pull Request 发送之前需要在本地进行测试,或者保持使用 Jenkins 等 CI 工具的自动化测试一直运行,这是 github-flow 的前提。

    当正式环境出现故障时,也只需要简单地从 master 创建分支并进行修正,发送 Pull Request 并合并,直接进行发布就行了。

    像 GitHub 这样,通过保持 master 随时都能发布来简化实际的运用,这的确是一个不错的办法。GitHub 自身一天之内要进行几十次发布。为了实现这样频度的发布,就必须准备好 CI 以及 CD 的环境。而准备这样的环境是比较困难的。

    ●…… 笔者的例子(折衷方案)

    git-flow 比较倾向于发布间隔较长的大规模项目,github-flow 则适用于需要时常发布的具有速度感的项目,例如 Web 服务等。下面举一个稍许极端的例子。

    笔者所属的团队,因为 git-flow 比较复杂所以没有使用,实际运用的是定制过的 github-flow 形式。具体来说,就是像下面这样。

    • 以使用 GitHub 为前提

    • 采用 GitHub 形式的工作流,各自在 GitHub 上拥有 Fork 出来的远程代码库。

    • 从中央代码库的 master 分支进行发布

    • 各开发人员可以在自己的本地环境和远程代码库上随意地操作

    • 开发结束后向中央代码库的 master 发送 Pull Request

    • Pull Request 通过 review 后合并到 master

    • 在发布准备阶段从中央代码库的 master 创建发布分支

    • 在发布分支上进行回归测试、部署测试等发布的准备工作

    • 在进行发布的准备工作的过程中,开发人员仍然可以向 master 发送新功能开发的 Pull Request

    • 发布结束后合并到 master,在 master 上打上标签后删除发布分支

    大体的形式是只对中央代码库的 master 和发布分支进行严格管理,其他的都可以随意 Fork,自由使用。这种方式下的权限管理也变得相对简单,只需要对向 master 发送的 Pull Request 认真地进行代码 review 及测试,其余的事情就不用考虑了,这也是该方式的优点之一。

    正式环境发生故障时的处理流程是:先将发布时打上的标签 checkout 到本地机器上并进行修正,修正后向中央代码库的 master 发送 Pull Request,合并 Pull Request 后创建发布分支,发布结束后将发布分支合并回 master 并删除。虽然比 github-flow 步骤稍微多了一些,但还并不是太复杂。

    3.6.3 最合适的流程和分支策略因项目而异

    本节我们了解了使用 Git 的开发流程以及分支策略。Git 系统中没有中央代码库的概念,因此能组建各种形态的工作流程。这样的灵活性正是 Git 的魅力所在,但过度的自由事实上也会造成很多麻烦。

    接着我们简单地看了具有代表性的流程和分支策略。还介绍了笔者实际运用的例子。具体运用方面在很大程度上会受到团队的商业模式的影响。Web 服务的话,只需要时常管理好最新版本和已经发布的版本这两个就行了。而如果是套装软件的话,就必须同时维护多个版本,所以还是有所差异的。

    另外,在发布分支和开发分支的操作方面,如果该产品是不经过长时间的回归测试就不能发布的产品的话,还是将发布分支和开发分支区分开来进行管理比较好。另一方面,如果是应该尽早发布的服务的话,则可以说像 github-flow 那样,完全不区分比较好。

    Git 的开发流程能够很灵活地定制,所以请大家一定要结合项目的具体情况,试着思考一下最合适的流程。