所有的代码规范、接口设计以及各种规定,都是为了在团队内部形成共识,防止个人习惯差异引起的混乱。
当只有你自己一个人在 Git 仓库中的时候,你一般不需要考虑如何协作的问题。
但当你需要与多人一起协作的时候,混乱就诞生了。
对于不同规模的团队,不同的协作模式效率也不一样。本文将介绍不同的 Git 协作流程,以适应不同的团队。同时,带着以下的先验知识阅读文章会对你更有帮助:
- 工作流程需要简单,并且工作流程确实能够提高团队的生产力
- 没有适用于任何情况的万能工作流程
- 业务上的需求会倒逼出更适合团队的工作流程
关于 Git 的操作可以参照《程序员的时间机器 —— Git 与 GitHub 的使用》。
# Git Flow Workflow
Git Flow 适用于有预定发布周期的项目,但不太适用于持续发布的项目。
Git Flow 提出了五种不同的分支,分别是 master
、 develop
、 hotfix
、 release
、 feature
。
其中, master
和 develop
分支是长期存在的,而 hotfix
、 release
、 feature
在被合并进 master
或 develop
分支后,这些分支都会被删掉,因此也是短期分支。
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 的常见命令如下:
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 的大致流程是这样的:
develop
分支由master
分支创建而来feature
分支由develop
分支创建而来- 当一个
feature
分支完成了之后,需要将它合并到develop
分支中 release
分支由develop
分支创建而来- 当一个
release
分支完成了之后,需要将它合并到develop
和master
分支中 hotfix
分支由master
分支创建而来- 当一个
release
分支完成了之后,需要将它合并到develop
和master
分支中
总体来说,虽然 git flow 分支的作用清晰,但是较为复杂:
- 需要同时维护
master
与develop
两个长期分支,且大多数工具都会将master
分支作为默认分支,开发者会需要高频切换,过于繁杂。 hotfix
和release
分支带来的复杂性对于大多数团队来说都是过犹不及的,例如有开发者只把修改合并到master
分支而不合并到develop
分支,有些项目不需要做热修复等等。
# Forking Workflow
Forking Workflow 一般适用于开源项目的贡献同时也适用于私有工作流程。Forking Workflow 一般会与 Git 托管平台结合使用。
以实际的例子举例,使用 Forking Workflow 的流程大致如下:
- 你想对托管在 GitHub 的开源项目 VXenomac/DS_Store_Cleaner 贡献
- 在该仓库页面,使用 GitHub 的 Fork 功能
- 将在自己账号下的该仓库 clone 到本地
- 在本地创建新的
feature
分支 - 开发完成并提交 commit
- 将该
feature
分支 push 到自己账号下的该仓库 - 使用 GitHub 的 Pull Request 功能申请将
feature
分支与原始仓库进行合并 - 由原始仓库的 maintainer 进行判断是否合并
# GitHub flow Workflow
The GitHub flow is useful for everyone, not just developers.
官方文档中提到 GitHub flow 使用起来非常简单,你只需要有一个 GitHub 的账号以及一个 Git 仓库即可。
对于持续发布的产品来说,GitHub flow 是最合适的流程。
使用 GitHub flow 的大致流程如下:
- 从
mater
分支创建新的分支,不区分feature
还是hotfix
分支 - 在新建的分支上开始开发,理想情况下,每次 commit 都包含一个独立(isolated)且完整(complete)的修改
- 当你准备好合并之后或者需要讨论的时候,就发起一个 Pull Request
- 负责代码审核的人可以对该 Pull Request 进行提问、建议、点评等
- 当 Pull Request 被审批通过之后,这部分变动会被合并到
master
分支上 - 当分支被合并之后,需要删除之前创建的分支
GitHub flow 看上去整体确实非常简单、高效,但是是基于 master
分支就是当前线上代码的假设,而有时候业务较为复杂的时候,发布到 master
分支的代码并不是立刻就发布的,例如需要等待到特定时间才能发布等,这会导致线上版本落后于 master
分支的版本,因此这种情况下你不得不创建其他分支来跟踪线上版本,例如 production
分支。
# GitLab Flow Workflow
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 主要提出了几个新的提议:
- 针对 GitHub flow 存在的假设问题:
master
代码是立即发布的,GitLab Flow 中提出用Production branch
来解决问题,即创建一个反映线上代码部署情况的分支,将master
分支部署到 Production branch 来部署新版本(不知道为啥官方文档图中用的是 development 分支)。
- 针对实际的部署环境,GitLab Flow 提出用
Environment branches
来控制部署环境。GitLab Flow Workflow 要求变更只向下游流动,以确保所有变更在所有环境中都经过测试。假设你有一个staging
环境、一个pre-production
和production
环境,则一个完整的上线流程是:- 使用
staging
分支部署到 staging 环境 - 将
staging
分支合并到pre-prod
分支以部署到 pre-production 环境 - 将
pre-prod
分支合并到production
分支以部署到 production 环境
- 使用
- GitLab Flow 提出用
Release branches
来对外发布版本,每一个稳定版本都从master
分支创建。只有在修补严重的 BUG 才允许将代码合并到这些分支上,在此过程遵循上游优先(upstream first)策略,即先合并到master
分支再cherry-pick
到 对应release
分支。
# 一些技巧
不同的 Workflow 都是为了提高协作之间的效率以及减少冲突的发生,我们在使用 Git 过程本身中,也更应该遵循一些原则来减少冲突的发生:
- 逢新必创:每次开发新功能,都应该新建一个单独的分支
- 逢切必拉:每当切换到共有分支,先拉去最新的代码
- 小步快走:每开发完一个小功能就先提交
- 合多为一:如果某一分支由你单独开发且没有和
master
分支合并过,则发起 Pull Request 前,应该把多个 Commit 合并成一个以方便阅读或cherry-pick