目录
分布式版本控制系统
访问模型
分支策略-Git flow
feature
分支策略-Github flow
分支策略-Gitlab flow
主干开发模式
总结
分布式版本控制系统
分布式相比于集中式的最大区别在于开发者可以提交到本地,每个开发者通过克隆(git clone),在本地机器上拷贝一个完整的Git仓库。
访问模型
分支策略-Git flow
关于Git分支策略最早的见于Vincent在2010年发表的一篇博文《A successful Git branching model》
在这种模式下,主要维护了两类分支:
主要分支 (The main branch)
master
develop
辅助分支 (Supporting branch)
feature branch (功能分支)
release branch (预发布分支)
hotfix branch (热修复分支)
master
首先,代码库应该有一个、且仅有一个主分支。master 分支的代码永远是稳定的,可以随时发布到生产环境。
develop
develop 分支用于日常开发,保存了开发过程中最新的代码。
当 develop 分支上的代码达到稳定,并且具备发版状态时,需要将 develop 的代码合并到 master,并且打一个带有发布版本号的 tag。
创建 develop 分支:
git checkout -b develop master
将 develop 合并到 master:
# 切换到 master 分支
git checkout master
# 对 develop 分支进行合并
git merge --no-ff develop
--no-ff
参数的作用是使当前的合并操作总是创建一个新的 commit 对象,即使该合并被执行为快进式(fast-forward)合并。
这样可以避免丢失掉该功能分支的历史信息,并且将针对该功能的所有提交都集中到一起。这样解释也并不是很易懂,通过下图来对比一下就比较明显了:
feature
- 分支来源:develop
- 合并到分支:develop
- 分支命名约定:feature-*
功能分支,在开发某一个新功能时,从 develop 分支分出来,开发完之后,再合并回 develop 分支。
功能分支通常只存在于开发者的本地仓库中,并不包含在远程库中。
创建一个功能分支:
git checkout -b feature-x develop
开发完成后,将功能分支合并到 develop 分支:
git checkout develop
git merge --no-ff feature-x
删除 feature 分支:
git branch -d feature-x
release
分支来源:develop
合并到分支:develop,master
分支命名约定:release-*
预发布分支,它是指发布正式版本之前,我们可能需要有一个预发布的版本测试,并且可以在上面做一些较小 bug 的修复。
预发布分支是从 develop 分支上分出来的,预发布结束以后,必须合并进 develop 和 master 分支。
创建一个预发布分支:
git checkout -b release-1.2 develop
确认没有问题后,合并到 master 分支:
git checkout master
git merge --no-ff release-1.2
# 对合并生成的新节点,做一个标签
git tag -a 1.2
最后,删除预发布分支:
git branch -d release-1.2
hotfix
分支来源:master
合并到分支:develop,master
分支命名约定:hotfix-*
最后一种是修复 bug 分支。软件正式发布以后,难免会出现 bug。这时就需要创建一个分支,进行 bug 修复。
修复 bug 分支是从 master 分支上分出来的。修复结束以后,再合并进 master 和 develop 分支。
创建一个修复 bug 分支
git checkout -b hotfix-0.1 master
修复结束后,合并到 master 分支:
git checkout master
git merge --no-ff hotfix-0.1
git tag -a 0.1.1
再合并到 develop 分支:
git checkout develop
git merge --no-ff hotfix-0.1
最后,删除修复 bug 分支:
git branch -d hotfix-0.1
小结
优点:各分支权责分明,清晰可控,是很多分支管理策略的启蒙模型。
缺点:
- 合并冲突:同时长期存在的分支可能会很多:master、develop、release、hotfix、若干并行的 feature 分支。两两之间都有可能发生冲突。频繁手动解决冲突不仅增加工作量,而且增大了出错的风险。
- 功能分离:功能并行开发时,合并分支前无法测试组合功能,而且合并后可能会出现互相影响。
- 无法持续交付:Git flow 更倾向于按计划发布,一个 feature 要经历很多步骤才能发布到正式环境,难以达到持续交付的要求。
- 无法持续集成:持续集成鼓励更加频繁的代码集成和交互,尽早解决冲突,而 Git flow 的分支策略隔离了代码,尽可能推迟代码集成。
分支策略-Github flow
Github flow 是一个轻量级的基于分支的工作流程。它由 GitHub 在 2011 年创建。分支是 Git 中的核心概念,并且 GitHub 工作流程中的一切都以此为基础。
它只有一个长期分支 master,其他分支都在其基础上创建。使用流程如下:
- 根据需求,从 master 拉出新分支,不用区分功能分支或修复分支,但需要给出描述性的名称。
- 本地的修改直接提交到该分支,并定期将其推送到远程库上的同一命名分支。
- 新分支开发完成后,或者需要讨论的时候,向 master 发起一个 Pull Request(简称 PR)。
- Pull Request 既是一个通知,让别人注意到你的请求,又是一种对话机制,大家一起评审和讨论你的代码。对话过程中,你还可以不断提交代码。
- 你的 Pull Request 被接受,合并进 master,重新部署后,原来你拉出来的那个分支就被删除了。
小结:
优点:
- 降低了分支管理复杂度,更适合小型团队,或者维护单个版本的项目开发。
- 工作流程简单,对持续交付和持续集成友好。
缺点:无法支持多版本代码部署。
分支策略- flow
它是 Git flow 与 Github flow 的综合。吸取了两者的优点,既有适应不同开发环境的弹性,又有单一主分支的简单和便利。
Gitlab flow 和 Github flow 之间的最大区别是 Gitlab flow 支持环境分支。
Gitlab flow 的最大原则叫做"上游优先"(upsteam first),即只存在一个主分支 master,它是所有其他分支的"上游"。只有上游分支采纳的代码变化,才能应用到其他分支。
Gitlab flow 分成两种情形来应付不同的开发流程:
- 持续发布
- 版本发布
持续发布
对于持续发布的项目,它建议在 master 分支以外,再建立不同的环境分支,每个环境都有对应的分支。比如,开发环境的分支是 master,预发环境的分支是 pre-production,生产环境的分支是 production。
开发分支 master 用于发布到测试环境,该分支为受保护的分支。
预发分支 pre-production 用于发布到预发环境,上游分支为 master。
正式分支 production 用于发布到正式环境,上游分支为 pre-production。
如果生产环境(production)发生错误,则要建一个新分支修改完后合并到最上游的开发分支(master)此时就是(Upstream first),且经过测试,再继续往 pre-production 合并,要经过测试没有问题了才能够再往下合并到生产环境。
版本发布
对于版本发布的项目,建议的做法是每一个稳定版本,都要从 master 分支拉出一个分支,比如 2-3-stable、2-4-stable 等。
在出现 bug 后,根据对应的 release branch 创建一个修复分支,修复工作完成后,一样要按照上游优选的原则,先合并到 master 分支,经过测试才能够合并到 release 分支,并且此时要更新小版本号。
小结
优点:
可以区分不同的环境部署。
对持续交付和持续集成友好。
缺点:
分支多,流程管理复杂。
主干开发模式
主干开发,是指开发人员直接向主干(习惯上主干分支通常为:trunk 或 master)提交/推送代码。通常,开发团队的成员1天至少1次地将代码提交到主干分支。在到达发布条件时,从主干拉出发布分支(通常为 release),用于发布。若发现缺陷,直接在主干上修复,并根据需要 cherry pick 到对应版本的发布分支。
优点:
-
分支模型简单高效,开发人员易于掌握不容易出现错误操作
-
避免了分支合并、冲突解决的困扰
-
随时拥有可发布的版本
-
有利于持续集成和持续交付
缺点:
-
基础架构要求高:合入到主干的代码若质量不过关将直接阻塞整个团队的开发工作,因此需要高效的持续集成平台进行把关;
-
自动化测试要求高:需有完备单元测试代码,确保在代码合入主干前能在获得快速和可靠的质量反馈;
-
最好有代码评审:若代码质量要求高,需要配套代码评审(CR)机制,在代码提交到主干时,触发CR,通过 Peer Review 后才能正式合入;
-
最好有特性开关:主干开发频发合入主干的情况下,特性拆分得很小,可能是半成品特性,需要配套特性开关(Feature Toggle),只有当特性整体开发完才通过灰度发布等手段逐步打开;
适用环境:
-
对迭代速度要求高,希望需求快速交付上线
-
基础架构强,持续集成工具高效;
-
团队成员习惯TDD(测试驱动开发),代码自动化测试覆盖率高(至少增量代码的自动化测试覆盖率高);
总结:
没有最好的的版本控制策略,只有适合自己的版本控政策略,不同的应用场景,以及开发的人员习惯都会影响我们的决策,我们需要考虑分支冲突、版本安全可控、管理复杂度等各方面。