2

git flow 管理实践

 1 year ago
source link: https://www.codesky.me/archives/git-flow-intro.wind
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

git flow 管理实践

本文不含 Git Commands 教程,如果需要,可以刷一遍 githug,可以在最快最短的时间内帮你熟悉 git commands 和很多的 case,如果题目没变,可以参考我 15 年写的通关手册(反复谷歌后卡关再看)。

在实践中,我们发现光会 git 指令还不够,还会遇到很多复杂场景的问题,如果没有一个很好的管理策略,就会陷入一团乱麻中。

如果你还不会使用包括 git pull / git push / git rebase / git cherrypick / git checkout 等在内的常用指令,请先从 git 使用开始学习,绕回本文开头。
注:强烈建议每天进行至少一次拉取分支,并且使用 git pull --rebase 取代简单的 git pull 保持简洁。

在 Bitbucket 的文章中,我们可以大致了解一下各种 workflows 大概是怎么做的,他们的主要流程是什么。

从 git flow 说起

尽管 git flow 也不是一个银弹,也有很多的缺陷,但是依旧是一个在广泛使用的工作流,甚至还为其开发了 gitflow 这种命令行辅助工具。

我们来复习一下一个最简化版本的 git flow:

branch.png

这里我们用三种颜色来区分分支,总之,我们的日常是从 develop 分支切出 feat/* 分支进行开发,合并回 develop 后合并回 master 分支上线。这里的 feature A、B、C 表示三个不同的 feature,从图中我们可以看出,三条线是线性的,并且永远是单向合并的。也就是说,develop 永远是 feature 的子集,而 masterdevelop 的子集,如果不是,那么就代表你的 Git 分支管理出现了问题,可能会出现大量 conflict 的情况。

hotfixmaster 切出,并且合入 master,但是为了保证 developmaster 的一致性,我们需要在将同样的代码推入 develop

线性的理论很美好,但是实际上却会遇到很多复杂的业务场景,在下文的 Case 中我们会具体介绍,现在,我们先来理论性的了解一些基本原则:

feature 是什么

feature 代表一个功能块,他可能不是本次的一整个业务,比如实现整个活动页,更有可能的,是某一个功能块,是你被分到的一个任务。它应该尽可能是原子的,是一个最小单元。

从概念上来讲,已经是最小单元的 feature 应该只有一个 commit(因为 commit 也是原子的最小单元),但是实际开发中,我们虽然被分到的是一个任务,比如开发一个「用户注册」的功能,你可能会顺手写一些相对应的 utils,而这些 utils 在开发完成后应该单独的有一个 commit 去描述。(理由在下文的 Case 中会有介绍)

有实意的 commit

在开发过程中,我看到了大量的名叫 fix 或者 bug fix 的 MR,甚至是 review 中提出的意见新建了一个 commit 并提交,此时,commit 变成了离散的无语义的一个散点,对于团队合作杀伤力极强(理由在下文的 Case 中会有介绍)。

develop 与 master 分支

develop 和 master 对于整个 flow 来说是相对稳定的,为了避免出现问题,我们应该保证 master 永远是 develop 的子集,理论上,它们是可以保证 pull 期间没有任何 conflict 需要处理的,可以直接相互 merge 的分支。如果不是,代表 develop 和 master 已经是两个完全不同的分支了,只能想办法去解决这一类问题,带来的成本是极大的。

在这里,我们在 develop 和 master 设立两道防御,避免团队开发内部的冲突:

  1. develop 必须是一个线性(对开发)稳定版本,所有内容都需要从 develop 切出进行开发(除了 hotfix),最终都会归于 develop。
  2. master 也必须是一个线性(对部署)稳定版本,只有在 master 分支的内容可以上线。

按版本回滚

开发的生命中,难免会有这个版本出了问题,需要上下游一起去回滚延迟上线的情况,从概念上来说,就是「回滚到上一个版本」。如果不考虑依赖于发布系统提供的回滚功能,那么在每个发布之后应该打一个 tag

虽然……但是

上文我们说了一些利用分支管理流可以做到的事情以及一些约定,但是在实际实践中,我们可能会发现:诶这种 case 我要怎么满足才能达到「线性」治理。(就跟我们开发过程中强保证单向数据流一样)。

Case 1:可是我要提测

细心的你可能已经发现,整个 git flow 其实并没有考虑到「测试」、「提测」这个 case,那我们到底什么时候提测,要怎么提测呢。

一般的,我们会在 develop 往 master 合并的过程中引入一个新的类型:release/version(或者也可以叫 testing/version)。

因为上文我们说过,develop 是一个对开发稳定版本,因此它应该是一个不断滚动更新的内容,弱化「版本」的概念。从流程上,提测是在上线前,而在开发完成后,因此从语义的角度,同样的也应该在 develop -> master 过程中。

Case 2:我正在做某些不急着上线的东西

刚刚我们解释了怎么样提测,流向也就变成了 develop -> release -> master,但是如果我要做的东西不急着上线呢——按照流程,它就应该被冻结在 feature 分支等待合并。

Case 3:基于别人正在开发的内容开发

又发生了一件事情,某些不急着上线的东西被冻结在了 feature 中,那么如果我对此有依赖怎么办?

这里其实分为了两种 case:

  1. 通用方法依赖(比如 utils)

首先简单的 case 是业务依赖,既然是业务依赖,那就不会存在「我急着上线,而你不急着上线提测」的情况,那么只要基于对方(称为 A 同学)的 feature 分支进行开发就可以了,在最终的 Merge(Pull) Request 的过程中,Reviewer 只要先 Review A 同学开发的功能并合并,再 Review 你的功能就可以了。

通用方法的依赖就比较麻烦,不过我们可以回忆一下 feature 是什么一节,我们将 commit 内容变成了最小原子单元,也就是说,可以将对应的变更抽离出来,优先提交 Review 并合并到 develop,此时你就可以拉最新的 develop 并进行开发。

从上述内容中就可以看出为什么我们的 commit 必须要保证是有实意的,否则从别人的 MR 抽抽离内容会变成一个非常痛苦的过程。因此如果你还不会 git squash,请尽快学会。

Case 4:多人开发同一个业务

在团队规模增大之后,不可避免的会涉及一个迭代中的业务会有多人开发,这个时候处理 git flow 的复杂度就会上升,高速发展中的团队往往会死于多人开发的合作。

在这里我们回忆一下我们最初对 feature 分支的定义:「你的一个任务」,一种非常常见的错误用法是,在一个迭代中给自己切了一个属于自己的分支,然后疯狂在内部进行开发,而不是基于上述 flow 进行,很快就会陷入混乱之中。

因此我们在上文中已经定义了,feature 必须是原子的,他不是以人为单位,而是以功能为单位的,在 case 3 中的「基于别人正在开发的内容开发」,其实这个别人也可以是你自己。

这里以一个具体的前端栗子,比如这次迭代我要实现一个用户模块,产品提出的基本功能是「登录」、「注册」、「找回密码」、「修改密码」。

那么实际任务可能会变成:

  1. (业务)登录页面
  2. (业务)注册页面
  3. (业务)找回密码页面
  4. (业务)修改密码页面
  5. (通用)获取用户信息

在这里,如果是相互独立的,则直接从 develop 中切出挨个开发,当然,你会发现,仿佛「获取用户信息」,或者是隐藏的一个功能点「登录后跳转」是一个对于注册和登录通用的功能,那么可以先开发这一部分,然后以这个分支为根基进行进一步的开发。

当然,可能还会有更复杂的情况:中途又在这个业务中插了一个新需求,或者只是简单的在业务初期没有拆分好内容,出现了很多隐藏彩蛋,那么需要重新进行一次功能的划分,尤其是区分哪些是通用的部分,哪些是你负责的上层业务的部分。

Case 5:说好的要上线,结果又不上了

这种倒霉的情况可能出现在「提测前夕,由于本身优先级不高,导致测试资源不够用」和「都提测完了,突然因为某些其他问题,延期上限」;但是其他功能还要正常上线,这种时候,就是 revert 登场的时间了。

在上文中我们会发现,表面上是 git 的分支与 git flow 的实践,实际上更是 commit 的管理与任务的拆分,需要负责的同学对于任务划分有所规划,能够将功能块拆解到最小单位,只有这样,才能以最小的成本去治理版本。

git 分支管理(git flow)不仅是一个空洞的概念和模板,而需要根据团队和业务的迭代属性进行不断调整,才能找到属于自己的平衡点,与其说是一门理论学科,更像是一门艺术。

在 2021 年的现在,几乎每个工程师都宣称自己会使用 git,但是用好 git,甚至是利用 git 去管理和指导工程,却是很多工程师的痛点,因此本文整理了一些常见的 case 和解决方案,希望可以成为一些指导方案,当然,也非常欢迎提出更多的 case 一起探讨和解决。

小私货:为了保证分支的干净和统一,我喜欢在所有流程中使用 rebase,并且由本地自己去实现 commit 的管理(rename/pick/squash),包括文章开头所说的 git pull --rebase

如果您觉得文章不错,可以通过赞助支持我。

如果您不希望打赏,也可以通过关闭广告屏蔽插件的形式帮助网站运作。

标签: git


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK