git分支管理

主流的分支管理有以下几种:

Git Flow

简介

image.png

首先,项目存在两个长期分支。

主分支master
开发分支develop

前者用于存放对外发布的版本,任何时候在这个分支拿到的,都是稳定的分布版;后者用于日常开发,存放最新的开发版。

其次,项目存在三种短期分支。

功能分支(feature branch)
补丁分支(hotfix branch)
预发分支(release branch)

一旦完成开发,它们就会被合并进develop或master,然后被删除。

Git Flow 偏向于控制管理,使用了较多的分支,流程颇为复杂。大量的团队在实践过程中也遇到了颇多问题,其中大部分来自长期存在的分支。

问题

  • 合并冲突,合并冲突在使用 Git Flow 是非常常见的。原因很简单:如果你有多个并行功能分支,他们长时间存在,那么很可能代码库的相同部分在两个功能分支中被分别更改。合并冲突不仅对于需要手动解决的开发人员来说是令人沮丧的,也增加了在代码中破坏某些功能的风险,因为当你不得不决定使用哪个版本代码时,很容易犯错。

  • 功能分离,在合并到同一个分支之前,你不能测试两个功能的组合。当你在单独的分支中开发几天甚至几周的功能时,当合并回主分支后,可能也会发生两个功能的相互作用影响了你的代码。

  • 并没有做到持续交付,在 Git Flow 分支模型下,发布是非常有计划的,一个 feature 必须要经过一系列步骤才能到达生产环境,在时间上平均一个 feature 都要等待 两周时间才能长线,这样的等待并非是需求上的“按计划发布”,而是从技术上就造成了发布瓶颈,显然难以达到持续交付的要求。

  • 与持续集成相悖,你会发现,在坚持持续集成实践的情况下,feature 分支是一件非常矛盾的事情。持续集成鼓励更加频繁的代码集成和交互,让冲突越早解决越好。feature 分支的代码隔离策略却在尽可能推迟代码的集成。

GitHub Flow

简介

image.png

它只有一个长期分支,就是master,因此用起来非常简单。

官方推荐的流程如下:

  • 第一步:根据需求,从master拉出新分支,不区分功能分支或补丁分支。

  • 第二步:新分支开发完成后,或者需要讨论的时候,就向master发起一个pull request(简称PR)。

  • 第三步:Pull Request既是一个通知,让别人注意到你的请求,又是一种对话机制,大家一起评审和讨论你的代码。对话过程中,你还可以不断提交代码。

  • 第四步:你的Pull Request被接受,合并进master,重新部署后,原来你拉出来的那个分支就被删除。(先部署再合并也可。)

GitHub Flow是一个更轻量级的软件开发模型。它摒弃了 Git Flow 中繁杂的分支, 只保留一个主分支 master 。开发新功能时从 master 分支上拉取 feature 分支,开发完成后发起 Pull-Request ,小组内进行评审和反馈,此时也进行 Code Review 。测试通过后合并回主分支。

相比于 Git Flow,这种方式因为省去了一些分支而降低了复杂度,同时也更符合持续集成的思想,以一张故事卡为集成的最小单位,相对来说集成的周期短,反馈的速度也快,能够及早的遇到问题并及早解决。

GitLab Flow

简介

Gitlab flow 是 Git flow 与 Github flow 的综合。它吸取了两者的优点,既有适应不同开发环境的弹性,又有单一主分支的简单和便利。它是 Gitlab.com 推荐的做法。

上游优先

Gitlab flow 的最大原则叫做"上游优先"(upsteam first),即只存在一个主分支master,它是所有其他分支的"上游"。只有上游分支采纳的代码变化,才能应用到其他分支。

Chromium项目就是一个例子,它明确规定,上游分支依次为:

  1. Linus Torvalds的分支
  2. 子系统(比如netdev)的分支
  3. 设备厂商(比如三星)的分支

持续发布

Gitlab flow 分成两种情况,适应不同的开发流程。

image

对于"持续发布"的项目,它建议在master分支以外,再建立不同的环境分支。比如,"开发环境"的分支是master,"预发环境"的分支是pre-production,"生产环境"的分支是production

开发分支是预发分支的"上游",预发分支又是生产分支的"上游"。代码的变化,必须由"上游"向"下游"发展。比如,生产环境出现了bug,这时就要新建一个功能分支,先把它合并到master,确认没有问题,再cherry-pickpre-production,这一步也没有问题,才进入production

只有紧急情况,才允许跳过上游,直接合并到下游分支。

版本发布

image

对于"版本发布"的项目,建议的做法是每一个稳定版本,都要从master分支拉出一个分支,比如2-3-stable2-4-stable等等。

以后,只有修补bug,才允许将代码合并到这些分支,并且此时要更新小版本号。

从以上三种介绍可以看出复杂性从高到低:Git Flow > GitLab flow > GitHub Flow

Trunk Based Development

image.png

顺着持续集成的思想,如果我们把上一种分支模型做得再极致一点,我们不要 Feature 分支,或者把 Feature 分支只留在本地;不需要使用 Pull-Request 而是直接 Push 到远程 Master 分支,我们就做到了 Trunk based Development。

使用主干开发后,我们的代码库原则上就只能有一个 Master 分支了,所有新功能的提交也都提交到 Master 分支上,没有了分支的代码隔离,测试和解决冲突都变得简单,持续集成也变得稳定了许多,问题也接踵而至,主要有以下三个:

  • 如何避免发布的时候引入未完成的 Feature
  • 如何进行线上 Bug Fix
  • 如何重构

如何避免发布引入未完成 Feature

答案是: Feature Toggle

既然代码要随时保持可发布,而我们又需要只有一份代码来支持持续集成,在代码库里加一个特性开关来随时打开和关闭新特性是最容易想到的也是最容易被质疑的解决方案。

Feature Toggle 是有成本的,不管是在加 Toggle 的时候的代码设计,还是在移除 Toggle 时的人力成本和风险,都是需要和它带来的价值进行衡量的。事实上,在我们做一个前端的大特性变更的时候,我们确实没有因为没办法 Toggle 而采用了一个独立的 Feature 分支,我们认为即使为了这个分支单独做一套 Pipeline,也比在前端的各种样式间添加移除 Toggle 来得简单。但同时,团队商议决定在每次提交前都要先将 Master 分支 Merge 到 Feature 分支,以此避免分支隔离久以后合并时的痛苦。

如何进行线上 Bug Fix

在发布时打上 Release Tag,一旦发现这个版本有问题,如果这个时候Master分支上没有其他提交,可以直接在 Master 分支上 Hot Fix,如果 Master 分支已经有了提交就要做以下三件事:

  • 从 Release Tag 创建发布分支。
  • 在 Master 上做 Fix Bug 提交。
  • 将 Fix Bug 提交 Cherry Pick 到 Release 分支。
  • 在Release 分支再做一次发布。

线上 Fix 通常都比较紧急。看完这个略显繁琐 Bug Fix 流程,你可能会问为什么不在 Release 分支直接 Fix,再合并到 Master 分支?

这样做确实比较符合直觉,但事实是,如果在 Release 分支做 Fix,很可能会忘了 Merge 回 Master,试想深夜两点你做完 Bug Fix 眼看终于上线成功,这时的第一反应就是“终于可以下班了。什么,Merge 回 Master? 明天再来吧“ 等到第二天你早已把这个事忘得一干二净。而问题要等到下一次上线才会被暴露出来,一旦发现,而这个时候上一次 Release 的人又不在,无疑增加了很多工作量。

如何重构

这里指的是比较大规模的重构,无法在一次提交完成,TBD 要求每一次提交都是一个可上线的版本,所以这同时还意味着这个重构无法再一个上线周期内完成。

这种情况,需要在代码设计中增加一个抽象层,保证在重构过程中先不动原来的代码,也不破坏既有功能,类似于蓝绿部署中的负载均衡器的作用,这样的流程就是:

image
  • 在将要被重构的代码逻辑附近引入抽象层然后提交,对所有人可见。如果有需要可以是多个提交,这些提交都不能破坏 build,然后依次 push 到共享代码库。

  • 为将要被引入的代码写抽象层的第二次实现,然后提交。但在主干上由于关闭状态所以其他开发人员暂时不依赖于它。如果需要的话,这可能像上面那样需要多次提交。第一步的抽象层也可能偶然被调整,但必须遵循同样的原则:不能破坏build。

  • 切换使用重构后的代码,然后 Push。

  • 删除原有的旧实现(被重构代码)

  • 删除抽象层

以上过程也叫:抽象模拟分支

参考资料:
http://www.ruanyifeng.com/blog/2015/12/git-workflow.html
https://www.codercto.com/a/38021.html

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,295评论 6 512
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,928评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,682评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,209评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,237评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,965评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,586评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,487评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,016评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,136评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,271评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,948评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,619评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,139评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,252评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,598评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,267评论 2 358