第一次翻译,轻喷,若有错误请在评论区指出,我会尽快修改。
如下是正文php
在这篇文章中,我将介绍一年前我为个人一些项目(包括工做项目和私人项目)引入的开发模型,这个模型很是成功。我想写这篇文章已经有一段时间了,可是一直没有足够的时间去认真地写这篇文章,如今有这个机会了。我不会谈论任何项目的细节,仅仅是谈论关于分支策略和发布管理。 git
有关Git与集中式源代码管理系统相比的利弊的深刻讨论,请参见这篇文章。这每每涉及不少争论。做为一名开发者,我爱Git赛过其余一切工具。我曾经使用古老的CVS/Subversion,合并/分支一直被认为有点可怕(“当心合并冲突,他们会咬人”),有些事情你只想经历一次。shell
可是使用Git,这些操做很是方便和简单,他们会成为你工做流程的核心部分之一。例如,在CVS/Subversion手册中,分支和合并第一次被讨论是在后面的章节(高级用法),而在每一个Git手册中,第3章(基础)就进行了介绍。安全
因为它的简单性和重复性,分支和合并再也不是什么可怕的东西。版本控制工具应该比任何其余工具更有助于进行分支/合并。服务器
关于工具的讨论就到此为止,让咱们进入开发模式吧。我在这里将要介绍的模型本质上不过是一组过程,每一个团队成员都必须遵循这些过程才能进入一个托管软件开发过程。svn
咱们使用的仓库设置和分支模型可以很好地工做,主要是由于有一个“真正”的中央仓库。请注意,这个仓库仅被视为中央仓库(因为Git是DVCS,所以在技术层面上没有中央仓库)。 咱们将此仓库称origin,由于全部Git用户都熟悉该名称。工具
每一个开发者都从这个origin仓库拉去和推送代码。可是,除了集中推拉关系以外,每一个开发者还能够从其余同行那里拉取修改,组成子团队。例如,与两个或多个开发者一块儿开发一个比较复杂的新特性,将正在进行的工做提早推进到origin仓库,这样会颇有用。上面图有Alice和Bob,Alice和David,Clair和David三个子团队。加密
从技术上讲,这不过是ALice定义了一个名为Bob的指向Bob的仓库的远程仓库,反之亦然。spa
在核心方面,开发模型受到现有模型的极大启发,中央仓库有两个无限生命周期的主分支。翻译
每一个Git用户都熟悉origin仓库的master分支。与master分支平行的另外一个分支被称为develop。
咱们把origin/master当作用于生产环境中的源代码的主分支。
origin/master中的源代码老是表明了下一个发布的版本。有些人将此称为“整合分支”。这是任何自动夜间构建的地方。
当开发分支中的源代码到达一个稳定点并准备发布时,全部的更改都应该以某种方式合并回主程序中,而后用一个发布号进行标记。如何进行详细处理将进一步讨论。
所以,每次更改被合并到master分支时,就定义了一个新的生产版本。在这一点上,咱们是很是严肃的,因此从理论上讲,咱们可使用Git钩子脚本,在每次提交maser分支时候,在产品服务器上自动构建和回滚咱们的软件。
接下来,咱们的开发模式使用各类辅助分支来帮助团队成员之间的并行开发,方便追踪新特性,准备生产发布,帮助快速修复现线上产品问题。与主分支不一样,这些分支老是具备有限的寿命时间,由于它们最终将被移除。
咱们可能使用的不一样分支有:
每一个分支都有特定的用途,而且必须遵照严格的规则,即哪些分支能够是它们的起始分支,哪些分支必须是它们的合并目标。咱们立刻来看看他们。
从技术角度看,这些分支毫不是“特殊”的。分支类型是根据咱们使用它们的方式来分类的。它们仍然是咱们熟悉的Git分支。
可能建立于:
develop
一定会合并到:
develop
分支命名约定:
除了master,develop,release-*,或 hotfix-*之外
特性分支(或有时称为主题分支)用于为即将发布或遥远的未来版本开发的新特性。 当开始开发特性时,此时可能不知道将合并该特性的目标版本。 特性分支的本质是只要特性在开发中就存在,可是最终会合并回到develop分支中(以确保将新功能添加到即将发布的版本中)或丢弃(若是实验使人失望)。
特性分支只存在与开发人员的仓库,不存在于origin仓库
$ git checkout -b myfeature develop // 建立并切换到“myfeature”分支
$ git checkout develop // 切换到“develop”分支 $ git merge --no-ff myfeature // 将新特性合并到“develop”分支 $ git branch -d myfeature // 删除特性分支 $ git push origin develop // 推送变动
--no-ff使合并始终建立一个新的提交对象,即便合并能够经过快进来执行。 这样能够避免丢失有关特性分支历史存在的信息,并将全部添加了特性的提交组织在一块儿。 比较:
在第二种状况下,没法从Git历史记录中看到哪些提交对象一块儿实现了特性,您将不得不手动读取全部日志消息。 在第二种状况下,还原整个功能(即一组提交)确实很头疼,而若是使用--no-ff则很轻松不少。
固然,这将会产生一些额外的(空)提交,可是收益比成本大得多。
可能产生于
develop
必需要合并到
develop 和 master
分支命名规范
release-*
release分支支持一个新的生产版本的发行。他们容许最后几分钟的修改。此外,他们容许较小的错误修复和准备版本的元数据(版本号、构建日期等)。经过在发布版本上执行这些操做,develop将作好发布下一个大版本的准备。
当开发版本已经可以反映新版本特性的时候,就是将release分支从develop分支中分离出来的好时机。在这个时候,至少最新的针对最新发型版本进行构建的新特性都必需要合并回develop分支。全部针对将来版本的特性则不须要合并——它们必须等到release分支被分离后才能合并。
在准备一个release分支的时候就能够为这个版本进行命名了,不须要太早。直到那一刻,develop分支仍反映“下一版本”的变化,但直到分离分支开始,尚不清楚该“下一版本”是否最终变成0.3或1.0。肯定版本号是在准备一个release分支时开始的,并根据项目在版本号上的规则来决定。
发布分支是从开发分支建立的。例如,假设1.1.5是当前的生产版本,咱们即将发布一个大版本。开发的状态已经为“下一个版本”作好了准备,咱们已经决定这将变成1.2版(而不是1.1.6或2.0)。所以,咱们退出发行版,并给发布分支一个反映新版本号的名称:
$ git checkout -b release-1.2 develop // 切换到一个新分支 release-1.2 $ ./bump-version.sh 1.2 // 文件修改为功,版本号 1.2 $ git commit -a -m "Bumped version number to 1.2"
在建立一个新的分支并切换到它以后,我会修改版本号。在这里bump-version.sh
是一个虚构的shell脚本,它能够更改工做副本中的一些文件,以反映新版本(固然也能够手动更改——关键是一些文件发生更改),而后Bump版本被提交。
该新分支可能会保留一段时间,直到版本被明确的发布后。在此期间,能够在该分支中(而不是develop分支)进行bug修复。在此期间,严格禁止添加较大的新功能。它们必需要合并到develop分支中,在下一个大版本中发布。
当release分支准备好发布的时候,须要执行一些操做。首先,release分支合并到master分支(由于master分支的的每一次提交都是一个新版本,必定要记住)。接下来,master分支上的下一次提交须要进行标记,以便往后回顾历史版本。最后,在release分支上所作的更改须要合并回develop分支,以便未来的版本也包含这些错误修复。
在Git中的前两步
$ git checkout master // 切换到master分支 $ git merge --no-ff release-1.2 // 进行合并 $ git tag -a 1.2 // 打标签
如今完成发布,并作好了标记。
建议:您最好使用`-s`或`-u <key>`对标记加密签名
为了保存在release分支中作的修改,咱们须要将它合并回develop分支,所以,在Git中:
$ git checkout develop // 切换到develop分支 $ git merge --no-ff release-1.2 // 合并分支
这一步骤可能会致使合并冲突(咱们甚至可能会所以更改版本号)。若是这样的话,修复后再次进行提交。
如今,咱们真的完成了release分支,而且能够移除掉它了,由于咱们不再须要它了。
$ git branch -d release-1.2 // 删除release-1.2分支
可能产生于
master
必须合并到
develop和master
分支命名规范
hotfix-*
hotfix分支很是相似于release分支,由于它也是为了生产版本作准备,尽管是hotfix分支在计划以外。它产生的缘由是生产版本存在问题,须要当即进行修复。当在生产版本中发现了一个严重bug时,能够将hotfix从master分支上被标记过的相应地方分离出来。
本质上讲,团队成员的工做(在develop分支)仍能够继续进行,由另外一我的来准备快速的修复版本。
hotfix分支从master分支上建立。例如,版本1.2是当前发布的生产版本,可是因为存在bug而不稳定。可是develop分支还在修改也不稳定。咱们须要分离出一个hotfix分支,并修复这个问题:
$ git checkout -b hotfix-1.2.1 master // 建立hotfix-1.2.1并切换到该分支 $ ./bump-version.sh 1.2.1 // 执行shell搅拌 文件修改为功 修改版本号 $ git commit -a -m "Bumped version number to 1.2.1" // 提交分支
不要忘记在分支结束后增长版本号!
而后在一个或多个提交中修复bug。
$ git commit -m "Fixed severe production problem"
完成后,须要将bug修复合回到master分支,可是咱们也须要合并到develop分支,以确保bug修复包含在下一个发行版本中。这和释放release分支作法相似。
$ git checkout master // 切换到master分支 $ git merge --no-ff hotfix-1.2.1 // 合并分支 $ git tag -a 1.2.1 // 打标签
建议:您最好使用`-s`或`-u <key>`对标记加密签名
接下来,将bug修复合并到develop分支
$ git checkout develop // 切换到develop分支 $ git merge --no-ff hotfix-1.2.1 // 合并分支
这里有一个例外,当release分支还存在,hotfix分支须要到release分支,而不是develop分支 。当release分支完成后,bug修复合并到release分支会让bug修复也包含到develop分支中(若是develop分钟须要当即修复这个bug,而且不能等待release分支完成,你也能够安全地将bug修复合并到develop中)。
最后移除掉这个临时的分支:
$ git branch -d hotfix-1.2.1 // 删除分支
虽然这个分支模式并无真正使人惊讶的新事物,但这个帖子开头的“大图片”在咱们的项目中是很是有用的。它造成了一个优雅的心理模型,易于团队成员理解分支和发布过程。
这里提供了一个高质量的PDF版本的数字.你能够随时把它挂在墙上,以供快速参考。