所有的代码规范、接口设计以及各种规定,都是为了在团队内部形成共识,防止个人习惯差异引起的混乱。

当只有你自己一个人在 Git 仓库中的时候,你一般不需要考虑如何协作的问题。

但当你需要与多人一起协作的时候,混乱就诞生了。

对于不同规模的团队,不同的协作模式效率也不一样。本文将介绍不同的 Git 协作流程,以适应不同的团队。同时,带着以下的先验知识阅读文章会对你更有帮助:

  1. 工作流程需要简单,并且工作流程确实能够提高团队的生产力
  2. 没有适用于任何情况的万能工作流程
  3. 业务上的需求会倒逼出更适合团队的工作流程

:::info

关于 Git 的操作可以参照《程序员的时间机器 —— Git 与 GitHub 的使用》

:::

Git Flow Workflow

Git Flow timeline by Vincent Driessen, used with permission

Git Flow 适用于有预定发布周期的项目,但不太适用于持续发布的项目。

Git Flow 提出了五种不同的分支,分别是 masterdevelophotfixreleasefeature

其中,masterdevelop 分支是长期存在的,而 hotfixreleasefeature 在被合并进 masterdevelop 分支后,这些分支都会被删掉,因此也是短期分支。

Git Flow 主要为不同的分支分配了非常具体的作用,以及定义了它们之间应该如何以及何时产生互动。

分支名称 分支属性 分支作用
master 长期分支 主要用来存放稳定、随时可以上线的版本,开发者不会直接 commit 到此分支上。因为是稳定版本,通常会在 master 分支上的 commit 贴上版本标签。
develop 长期分支 作为主要开发的分支,是所有短期分支的基础分支。当要发布时,在 master 分支上对 develop 分支进行合并。
hotfix 短期分支 从 master 分支创建进行修复,当修复完成后合并回 master 分支,也同时合并回 develop 分支。
release 短期分支 在 develop 分支发布正式版本到 master 分支之前可以进行预发布进行测试。
feature 短期分支 从 develop 分支创建,用来新增功能的分支,完成开发后再合并回 develop 分支。

在 macOS 上只需要使用 brew install git-flow 即可安装 git-flow 的命令行工具。安装完 git-flow 后,就可以通过 git flow init 来使用。git-flow 本质上是对 Git 的一个封装,git flow init 命令就是默认的 git init 命令的扩展,除了为你创建分支外,并不改变仓库中的任何东西。git-flow 的常见命令如下:

1
2
3
4
5
6
7
git flow init # 初始化
git flow feature start feature-a # 创建 feature
git flow feature finish feature-a # 完成 feature
git flow release start 0.0.1 # 创建 release
git flow release finish 0.0.1 # 完成 release
git flow hotfix start bug-a # 创建 hotfix
git flow hotfix finish bug-a # 完成 hotfix

因此,使用 git flow 的大致流程是这样的:

  1. develop 分支由 master 分支创建而来
  2. feature 分支由 develop 分支创建而来
  3. 当一个 feature 分支完成了之后,需要将它合并到 develop 分支中
  4. release 分支由 develop 分支创建而来
  5. 当一个 release 分支完成了之后,需要将它合并到 developmaster 分支中
  6. hotfix 分支由 master 分支创建而来
  7. 当一个 release 分支完成了之后,需要将它合并到 developmaster 分支中

总体来说,虽然 git flow 分支的作用清晰,但是较为复杂:

  1. 需要同时维护 masterdevelop 两个长期分支,且大多数工具都会将 master 分支作为默认分支,开发者会需要高频切换,过于繁杂。
  2. hotfixrelease 分支带来的复杂性对于大多数团队来说都是过犹不及的,例如有开发者只把修改合并到 master 分支而不合并到 develop 分支,有些项目不需要做热修复等等。

Forking Workflow

../_images/fork-flow.png

Forking Workflow 一般适用于开源项目的贡献同时也适用于私有工作流程。Forking Workflow 一般会与 Git 托管平台结合使用。

以实际的例子举例,使用 Forking Workflow 的流程大致如下:

  1. 你想对托管在 GitHub 的开源项目 VXenomac/DS_Store_Cleaner 贡献
  2. 在该仓库页面,使用 GitHub 的 Fork 功能
  3. 将在自己账号下的该仓库 clone 到本地
  4. 在本地创建新的 feature 分支
  5. 开发完成并提交 commit
  6. 将该 feature 分支 push 到自己账号下的该仓库
  7. 使用 GitHub 的 Pull Request 功能申请将 feature 分支与原始仓库进行合并
  8. 由原始仓库的 maintainer 进行判断是否合并

GitHub flow Workflow

github-flow

The GitHub flow is useful for everyone, not just developers.

官方文档中提到 GitHub flow 使用起来非常简单,你只需要有一个 GitHub 的账号以及一个 Git 仓库即可。

对于持续发布的产品来说,GitHub flow 是最合适的流程。

使用 GitHub flow 的大致流程如下:

  1. mater 分支创建新的分支,不区分 feature 还是 hotfix 分支
  2. 在新建的分支上开始开发,理想情况下,每次 commit 都包含一个独立(isolated)且完整(complete)的修改
  3. 当你准备好合并之后或者需要讨论的时候,就发起一个 Pull Request
  4. 负责代码审核的人可以对该 Pull Request 进行提问、建议、点评等
  5. 当 Pull Request 被审批通过之后,这部分变动会被合并到 master 分支上
  6. 当分支被合并之后,需要删除之前创建的分支

GitHub flow 看上去整体确实非常简单、高效,但是是基于 master 分支就是当前线上代码的假设,而有时候业务较为复杂的时候,发布到 master 分支的代码并不是立刻就发布的,例如需要等待到特定时间才能发布等,这会导致线上版本落后于 master 分支的版本,因此这种情况下你不得不创建其他分支来跟踪线上版本,例如 production 分支。

GitLab Flow Workflow

基础·Gitlab Flow 工作流程

Frequently, the reaction to this problem is to adopt a standardized pattern such as Git flow and GitHub flow. We think there is still room for improvement. In this document, we describe a set of practices we call GitLab flow.

官方文档中提到 GitLab Flow 结合了 Git Flow 和 GitHub flow 的优势。

GitLab Flow 主要提出了几个新的提议:

  1. 针对 GitHub flow 存在的假设问题:master 代码是立即发布的,GitLab Flow 中提出用 Production branch 来解决问题,即创建一个反映线上代码部署情况的分支,将 master 分支部署到 Production branch 来部署新版本(不知道为啥官方文档图中用的是 development 分支)。

image-20220227152753416

  1. 针对实际的部署环境,GitLab Flow 提出用 Environment branches 来控制部署环境。GitLab Flow Workflow 要求变更只向下游流动,以确保所有变更在所有环境中都经过测试。假设你有一个 staging 环境、一个 pre-productionproduction 环境,则一个完整的上线流程是:
    1. 使用 staging 分支部署到 staging 环境
    2. staging 分支合并到 pre-prod 分支以部署到 pre-production 环境
    3. pre-prod 分支合并到 production 分支以部署到 production 环境

image-20220227152843201

  1. GitLab Flow 提出用 Release branches 来对外发布版本,每一个稳定版本都从 master 分支创建。只有在修补严重的 BUG 才允许将代码合并到这些分支上,在此过程遵循上游优先(upstream first)策略,即先合并到 master 分支再 cherry-pick 到 对应 release 分支。

一些技巧

不同的 Workflow 都是为了提高协作之间的效率以及减少冲突的发生,我们在使用 Git 过程本身中,也更应该遵循一些原则来减少冲突的发生:

  1. 逢新必创:每次开发新功能,都应该新建一个单独的分支
  2. 逢切必拉:每当切换到共有分支,先拉去最新的代码
  3. 小步快走:每开发完一个小功能就先提交
  4. 合多为一:如果某一分支由你单独开发且没有和 master 分支合并过,则发起 Pull Request 前,应该把多个 Commit 合并成一个以方便阅读或 cherry-pick