从 0 到 1 工程实践 (4)

叁叁肆2018-11-13 11:35

欢迎访问网易云社区,了解更多网易技术产品运营经验。


2.1.5 代码版本管理


设想这样的场景,你对代码做了一些变更,上线后发现代码有问题无法正常运行怎么 办?你肯定会想赶紧回滚到原来的代码,如果没有代码版本控制的工具,就很麻烦。


代码版本管理系统是一种可以帮助开发团队管理代码变更的工具,它会跟踪团队成 员对代码的每一次修改。如果发现变更的代码有问题,开发者可以回滚代码,并且可以与 之前的代码对比,找出问题所在,尽量减小对整个团队成员的影响。对于开发团队来说, 代码是最重要的资产,代码版本管理工具可以避免人为或其他原因导致的代码丢失或文件 损坏。


1. 代码管理工具


代码版本管理工具经过这么多年的发展,目前主要有两种不同的模式:集中式版本控 制( Centralized Version Control Systems,简称 CVCS)及分布式版本控制(Distributed Version Control System,简称 DVCS)。


集中式版本控制 

Subversion(简称 SVN)是集中式版本控制工具的典型代表。集中式版本控制工具有一个单一的集中管理服务器,保存所有文件的修订版本,而协同工作的人们都通过客户端 连到这台服务器,取出最新的文件或者提交更新。这种做法带来了许多好处,每个人都可 以在一定程度上看到项目中的其他人正在做些什么,管理员也可以轻松掌控每个开发者的 权限。


事分两面,有好有坏。这么做最显而易见的缺点是中央服务器的单点故障。如果宕机 一小时,那么在这一小时内,谁都无法提交更新,也就无法协同工作。如果中央服务器的 磁盘发生故障,碰巧没做备份,或者备份不够及时,就会有丢失数据的风险。最坏的情况 是彻底丢失整个项目的所有历史更改记录,而被客户端偶然提取出来保存在本地的某些快 照数据就成了恢复数据的希望。但这样依然是个问题,你不能保证所有的数据都事先完整 提取出来。


分布式版本控制 

因为集中式版本控制的单点问题,分布式版本控制系统面世了,Git 是其代表。在分布 式版本控制中,客户端并不只提取最新版本的文件快照,而是把代码仓库完整地镜像下来。 这么一来,任何一处协同工作用的服务器发生故障,事后都可以用任何一个镜像出来的本 地仓库恢复。因为每一次的提取操作,实际上都是对代码仓库的完整备份。


许多这类系统都可以指定和若干不同的远端代码仓库进行交互,你可以在同一个项目 中,分别和不同工作小组的人相互协作。


2. Git VS. SVN


这两种代码管理工具的基本使用方式在此不做详细介绍,读者可以分别参考 Pro Git Book 及 SVN 教程。


不管是 Git 还是 SVN,一般的使用流程都是检出(checkout)、添加或者更新文件(add)、 提交变更(commit)的过程,只是内在的一些概念有一些区别。


在 SVN 中,只有一个远程中央仓库,所有的操作都针对这个远程仓库。而在 Git 中, 既有远程仓库,又有本地仓库的概念,本地仓库可以同步远程仓库的更新,但本地仓库独 立于开发者,每个开发者都可以独立操作自己的本地仓库而不影响其他开发者。Git 中有很 多操作都是针对本地仓库,确定没问题时再同步到远程仓库。


SVN 的 commit 直接提交代码到远程仓库,如果发现提交的代码有问题,就再提交一次;而 Git 的 commit 只提交到本地仓库,需要通过 push 才能将提交推送到远程仓库,如 果在 push 前发现本地提交有问题,还可以通过 revert、rebase 等操作去变更提交记录。


在 SVN 中,分支(branch)是一个完整的目录,包含完整的实际文件,新建一个分支 就等于把所有文件复制一份,所以在 SVN 中,创建分支是一件相对来说有代价的事(耗时 复制,新的复制占用空间)。而且这个分支是大家共享的,你新开一个分支,其他成员就可 以看到(所以 SVN 有目录级权限控制,以控制开发人员对不同目录的访问权限)。


在 Git 中,创建分支不需要复制文件,它基于提交创建分支,所以 Git 创建分支非常快。 Git 首先是在本地仓库中创建分支的,只有自己能够看到,只有在确定这个分支需要共享给 其他人时,才会把分支推送到远程仓库。这些差异,也是 Git 分支的优势,Git 鼓励多分开 支,通过分支来组织不同的功能开发。


3. 分支模型


当我们多人协作开发的时候,往往会产生多个分支,因此一个好的分支管理策略就显 得比较重要,而一个混乱的分支管理,可能会导致提交历史看上去一团糟。下面以 Git 为 例,介绍两种分支模型,并结合笔者的实际开发体验说明差异。


master/develop 多分支模型 

如果读者在网上搜索 Git 的分支模型,会看到来自如下地址的一篇文章 http://nvie.com/ posts/a-successful-git-branching-model/,在这篇文章中,作者 Vincent Driessen 提出了自己使 用的一个 Git 分支模型,并且非常成功。


如图 2-1 所示,这个分支模型中使用两个长期分支 master 和 develop,然后使用多个辅 助分支。当进行新功能开发的时候,需要首先从 develop 分支中开新的特性分支进行开发, 当一个新的特性开发完成后,然后合并回 develop 分支;当开发稳定后,可以发布一个新 版本的时候,从 develop 分支开一个 release 分支,再在 release 分支上面进行一些提交,待 稳定后,合并到 master 分支发布,同时相关的 release 分支上的修改还要合并回 develop 分 支;当线上出现问题后,直接从 master 上面开 hotfix 分支,待完成修复后,再合并到 master 分支,最后相关的修复还要合并到 develop 分支。该分支模型的最大特点就是使用显式的 合并来跟踪新特性的合入、新版本的发布,以及线上的 hotfix。当发现某个新特性的合入导 致问题时,可以仅仅恢复那个合并的提交,即可将所有与该特性相关的提交进行恢复。

              


单 master 分支模型


这种方式仅仅使用一个长期的 master 分支,并且不使用合并,所有的提交都直接 rebase 到 master 分支上面,如图 2-2 所示。 

图 2-2 单 master 分支模型(图片来自 Vincent Driessen 博客)
功能开发时,直接在 master 上面开特性分支,开发完成后,再 rebase 回 master 分支。 如果需要 bugfix,也同样直接在 master 上进行修复,完成后再直接 rebase 到 master 分支。


根据具体的需求,当完成一部分需求开发,测试正常通过后,代码基本稳定,就直接从 master 分支开出一个 release 分支,打上线的 tag,并上线。


当上线后,在 release 分支发现 bug 后,直接在 release 分支进行 hotfix 修复,并打新的 tag,然后将修复 cherry-pick 回 master 分支。
上线后,如果在 master 分支上面发现了会影响目前上线的 release 分支上的 bug,直接 在master分支上进行修复,再将这个修复cherry-pick到对应的release分支上,并打新的tag, 然后上线修复。


再经过一段时间的开发,又到了一个可以发布的节点时,此时开新的 release 分支。当 发布完成后,上一个 release 分支废弃掉,使用新的 release 分支。如果发布的时候出现问题, 可以直接回退到上一个 release 分支。


这种模型中,master 是长期远程分支,每一个 release 都只会在其处于活跃期的时候, 在远程仓库存在一段时间,一旦废弃,就不再维护。其他所有分支都是本地分支,包括开 发新功能的特性分支,修复 bug 所开的 bugfix 分支,都是开发者在本地进行。由于其所有 分支都是从 master 分支出来,并且不进行合并,就像一个仙人掌一样,有很多分叉,因此 该模型又被形象地称为“仙人掌”模型。


两种模型的总结


使用前一种模型,对于一个开发团队来说,特别是有团队成员对版本控制的使用不太 熟练的时候,容易造成分支膨胀,当你查看分支记录时,会看到一团糟,提交线混乱。而 且由于涉及分支很多,又有来回合并的操作,整个团队能否正确实施是一个挑战。一旦出 现 bug,想进行二分查找 bug 的引入也比较麻烦。对于一个成熟的团队,能够正确实施该 模型,也是一个不错的选择。


使用后一种模型,master 分支的提交历史是一条直线,所有有价值的提交都一定要应 用到 master 分支上。比起第一种方式来回 merge,这种方式比较简单直接。由于限制使用 merge 操作,分支比较清晰。对于查看历史,二分查找 bug 等都比较方便,团队实施起来 也比较简单。


不过这种方式丢失了 merge 信息,由于没有 merge,你不能直观地看到某个功能在哪 里进入到 master 中,不过可以通过强制在提交日志中说明其实现的功能来弥补。


4. 第三方托管工具


如果你不想自己来维护一套代码管理或者镜像管理的系统,可以使用第三方托管平台。 一般只需要注册一个帐号,就可以创建私有或者公开的仓库,方便快速地进行代码或者镜 像管理。


GitHub(https://github.com/) 

GitHub 是一个面向开源及私有软件项目的托管平台,因为只支持 Git 作为唯一的版本 库格式进行托管,故名 GitHub。


GitHub 于 2008 年 4 月 10 日正式上线,除了 Git 代码仓库托管及基本的 Web 管理界面 以外,还提供了订阅、讨论组、文本渲染、在线文件编辑器、协作图谱(报表)、代码片段 分享(Gist)等功能。目前,其注册用户已经超过百万,托管版本数量也非常多。


GitHub 同时提供付费账户和免费账户。这两种账户都可以创建公开的代码仓库,但是 付费账户也可以创建私有的代码仓库。除了允许个人、组织创建和访问代码库以外,它也 提供了一些方便社会化软件开发的功能,包括允许用户追踪其他用户、组织、软件库的动 态,对软件代码的改动和 bug 提出评论等。GitHub 也提供了图表功能,用于显示开发者们 怎样在代码库上工作及软件的开发活跃程度。


GitLab(https://gitlab.com/) 

GitLab 是一个利用 Ruby on Rails 开发的开源应用程序,实现一个自托管的 Git 项目仓 库,可通过 Web 界面进行访问的公开或者私人项目。


它拥有与 GitHub 类似的功能,能够浏览源代码、管理缺陷和注释。可以管理团队对仓 库的访问,易于浏览已提交的版本并提供一个文件历史库。它还提供一个代码片段收集功 能,轻松实现代码复用,便于日后有需要的时候进行查找。
相比 GitHub,GitLab 上可以免费创建自己的私有项目。


码云(http://git.oschina.net/) 

码云是开源中国社区于 2013 年推出的基于 Git 的完全免费的代码托管服务,这个服务 是基于 GitLab 开源软件所开发的,在 GitLab 的基础上做了大量的改进和定制开发,目前 已经成为国内最大的代码托管系统,致力于为国内开发者提供优质稳定的托管服务。 码云除了提供最基础的 Git 代码托管之外,还提供代码在线查看、历史版本查看、Fork、 Pull Request、打包下载任意版本、Issue、Wiki、保护分支、代码质量检测和 PaaS 项目演示 等方便管理、开发、协作、共享的功能。


文章节选自《云原生应用架构实践》 网易云基础服务架构团队 著 


网易云计算基础服务深度整合了 IaaSPaaS 及容器技术,提供弹性计算、DevOps 工具链及微服务基础设施等服务,帮助企业解决 IT、架构及运维等问题,使企业更聚焦于业务,是新一代的云计算平台。点击可免费试用