`

【zz】一个成功的Git分支模型

 
阅读更多

原文请见: http://www.juvenxu.com/2010/11/28/a-successful-git-branching-model/

 

本文中我会展示一种开发模型,一年前该模型就已经被我用在所有的项目中(包括工作中的项目和私有项目),结果是非常成功的。我早就想为此写点东西,可直到现在才有时间。本文不会讲述任何项目的细节,只会涉及到分支策略和发布管理。

本文使用Git 作为所有源码的版本控制工具。

为什么是Git?

要全面了解Git与其它集中式版本控制系统相比的优劣,可以参考这个页面 。 这方面的争论可谓是硝烟弥漫。作为一个开发者,所有这些工具中我最钟情于Git。Git的的确确改变了人们考虑合并及分支的方式。在我之前所处的经典 CVS/Subversion世界中,合并/分支总是被认为是有点可怕的事情(“小心合并冲突,丫会恶心到你”),因此你只应偶尔干这种事情。

但有了Git,这类事情就变得非常简单,分支及合并甚至被认为是你日常版本控制操作的核心之一。例如,在CVS/Subversion的 中,分支及合并往往在后面的章节才被介绍(针对高级用户),但在每一本Git的书 中,该内容已经在前3章中介绍(基础)。

简单及易重复性带来的好处就是,分支及合并变得不再可怕。版本控制工具本该帮助我们方便的进行和分支及合并操作。

简单介绍下工具后,让我们来看开发模型。我讲介绍的模型本质上只是一组步骤,每个团队成员都必须遵循这些步骤以形成一个可靠管理的软件开发过程。

去中心化但仍保持中心化

在这个分支模型中我们使用的,且被证实工作得很好的仓库配置,其核心是一个中心“真理”仓库。注意只有该仓库才被认为是中心库(由于Git是 DVCS [分布式版本控制系统],在技术层面没有中心库这一东西)。之后我们用origin指代该仓库,因为大多数Git用户都熟悉这个名称。

每个开发者都对origin做push和pull操作。不过除了这种中心化的push-pull关系外,每个开发者还可以从其他开发者或者小组处 pull变更。例如,可能两个或更多的开发者一起开发一个大的特性,在往origin永久性的push工作代码之前,他们之间可以执行一些去中心化的操 作。在上图中,分别有Alice和Bob、Alice和David、Clair和David这些小组。

从技术上来说,这仅仅是Alice定义一个Git remote,名字为bob,指向Bob的仓库,反过来也一样。

主要分支

此开发模型的核心主要受现有的模型启发。中心仓库包含了两个主要分支,这两个分支的寿命是无限的:

  • master
  • develop

每个Git用于都应该熟悉origin上的master分支。与master分支平行存在的,是另外一个名为develop的分支。

我们认为origin/develop分支上的HEAD源码反映了开发过程中最新的提交变更。有人会称之为“集成分支”。该分支是自动化每日构建的代码源。

当develop分支上的源码到达一个稳定的状态时,就可以发布版本。所有develop上的变更都应该以某种方式合并回master分支,并且使用发布版本号打上标签。稍后我们会讨论具体操作细节。

因此,每次有变化被合并到master分支时,根据定义这就是一次新的产品版本发布。我们趋向于严格遵守该规范,所以理论上来说,每次master有提交时,我们都可以使用一个Git钩子(hook)脚本来自动构建并部署软件至产品环境服务器。

支持性分支

紧接着主要分支master和develop,我们的开发模型使用多种支持性分支来帮助团队成员间实现并行开发、追踪产品特性、准备产品版本发布、以及快速修复产品问题。与主要分支不同的是,这些分支的寿命是有限的,它们最终都会被删除。

我们会用到的分支有这几类:

  • 特性分支(feature branch)
  • 发布分支(release branch)
  • 热补丁分支(hotfix branch)

上述每种分支都有特定的用途,它们各自关于源自什么分支、合并回什么分支,都有严格的规定。稍后我们逐个进行介绍。

从技术角度来说,这些分支一点都不“特殊”。分支按照我们对其的使用方式进行分类。技术角度它们都一样是平常的Git分支。

特性分支

可能的分支来源:develop
必须合并回:develop
分支命令约定:任何除master, develop, release-*, 或 hotfix-*以外的名称

特性分支(有时也被称作topic分支)是用来为下一发布版本开发新特性。当开始开发一个特性的时候,该特性会成为哪个发布版本的一部分,往往还不 知道。特性分支的重点是,只要特性还在开发,该分支就会一直存在,不过它最终会被合并回develop分支(将该特性加入到发布版本中),或者被丢弃(如 果试验的结果令人失望)。

特性分支往往只存在于开发者的仓库中,而不会出现在origin。

创建一个特性分支

开始开发新特性的时候,从develop分支创建特性分支。

$ git checkout -b myfeature develop
Switch to a new branch “myfeature”

合并完成的特性回develop

完成的特性应该被合并回develop分支以将特性加入到下一个发布版本中:

$ git checkout develop
Switch to branch ‘develop’
$ git merge –no-ff myfeature
Updating ea1b82a..05e9557
(Summary of changes)
$ git branch -d myfeature
Deleted branch myfeature (was 05e9557).
$ git push origin develop

上述代码中的–no-ff标记会使合并永远创建一个新的commit对象,即使该合并能以fast-forward的方式进行。这么做可以避免丢失特性分支存在的历史信息,同时也能清晰的展现一组commit一起构成一个特性。比较下面的图:

在第2张图中,已经无法一眼从Git历史中看到哪些commit对象构成了一个特性——你需要阅读日志以获得该信息。在这种情况下,回退(revert)整个特性(一组commit)就会比较麻烦,而如果使用了–no-diff就会简单很多。

是的,这么做会造成一些(空的)commit对象,但这么做是利大于弊的。

可惜的是,我没能找到方法让–no-diff成为默认的git merge行为参数,但其实应该这么做。

发布分支

可能的分支来源:develop
必须合并回:develop和master
分支命名约定:release-*

发布分支为准备新的产品版本发布做支持。它允许你在最后时刻检查所有的细节。此外,它还允许你修复小bug以及准备版本发布的元数据(例如版本号,构建日期等等)。在发布分支做这些事情之后,develop分支就会显得比较干净,也方便为下一大版本发布接受特性。

从develop分支创建发布分支的时间通常是develop分支(差不多)能反映新版本所期望状态的时候。至少说,这是时候版本发布所计划的特性 都已经合并回了develop分支。而未来其它版本发布计划的特性则不应该合并,它们必须等到当前的版本分支创建好之后才能合并。

正是在发布分支创建的时候,对应的版本发布才获得一个版本号——不能更早。在该时刻之前,develop分支反映的是“下一版本”的相关变更,但不知道这“下一版本”到底会成为0.3还是1.0,直到发布分支被创建。版本号是在发布分支创建时,基于项目版本号规则确定的。

创建一个发布分支

发布分支从develop分支创建。例如,假设1.1.5是当前的产品版本,同时我们即将发布下个版本。develop分支的状态已经是准备好“下 一版本”发布了,我们也决定下个版本是1.2(而不是1.1.6或者2.0)。因此我们创建发布分支,并且为其赋予一个能体现新版本号的名称:

$ git checkout -b releases-1.2 develop
Switched to a new branch “release-1.2”
$ ./bump-version.sh 1.2
Files modified successfully. version bumped to 1.2.
$ git commit -a -m “Bumped version number to 1.2”
[release-1.2 74d9424] Bumped version number to 1.2
1 files changed. 1 insertions(+). 1 deletions(-)

创建新分支并转到该分支之后,我们设定版本号。这里的bump-version.sh是一个虚构的shell脚本,它修改一些本地工作区的文件以体现新的版本号。(当然这也可以手动完成——这里只是说要有一些文件变更)接着,提交新版本号。

新的发布分支可能存在一段时间,直到该版本明确对外交付。这段时间内,该分支上可能会有一些bug的修复(而不是在develop分支上)。在该分支上添加新特性是严格禁止的。新特性必须合并到develop分支,然后等待下一个版本发布。

结束一个特性分支

当特性分支达到一个可以正式发布的状态时,我们就需要执行一些操作。首先,将发布分支合并至master(记住,我们之前定义master分支上的 每一个commit都对应一个新版本)。接着,master分支上的commit必须被打上标签(tag),以方便将来寻找历史版本。最后,发布分支上的 变更需要合并回develop,这样将来的版本也能包含相关的bug修复。

前两步在Git中的操作:

$ git checkout master
Switched to branch ‘master’
$ git merge –no-ff release-1.2
Merge made by recursive.
(Summary of changes)
$ git tag -a 1.2

现在版本发布完成了,而且为未来的查阅提供了标签。

提醒: 你可能同时也会想要用 -s 或者 -u <key> 来对标签进行签名。

为了能保留发布分支上的变更,我们还需要将分支合并回develop。在Git中:

$ git checkout develop
Switched to branch ‘develop’
$ git merge –no-ff release-1.2
Merge made by recursive.
(Summary of changes)

这一操作可能会导致合并冲突(可能性还很大,因为我们改变了版本号)。如果发现,则修复之并提交。

现在工作才算真正完成了,最后一步是删除发布分支,因为我们已不再需要它:

$ git branch -d release-1.2
Deleted branch release-1.2 (was ff452fe).

热补丁分支

可能的分支来源:master
必须合并回:develop和master
分支命名约定:hotfix-*

热补丁分支和发布分支十分类似,它的目的也是发布一个新的产品版本,尽管是不在计划中的版本发布。当产品版本发现未预期的问题的时候,就需要理解着 手处理,这个时候就要用到热补丁分支。当产品版本的重大bug需要立即解决的时候,我们从对应版本的标签创建出一个热补丁分支。

使用热补丁分支的主要作用是(develop分支上的)团队成员可以继续工作,而另外的人可以在热补丁分支上进行快速的产品bug修复。

创建一个热补丁分支

热补丁分支从master分支创建。例如,假设1.2是当前正在被使用的产品版本,由于一个严重的bug,产品引起了很多问题。同时,develop分支还处于不稳定状态,无法发布新的版本。这时我们可以创建一个热补丁分支,并在该分支上修复问题:

$ git checkout -b hotfix-1.2.1 master
Switched to a new branch “hotfix-1.2.1″
$ ./bump-version.sh 1.2.1
Files modified successfully, version bumped to 1.2.1.
$ git commit -a -m “Bumped version number to 1.2.1″
[hotfix-1.2.1 41e61bb] Bumped version number to 1.2.1
1 files changed, 1 insertions(+), 1 deletions(-)

不要忘了在创建热补丁分之后设定一个新的版本号!

然后,修复bug并使用一个或者多个单独的commit提交。

$ git commit -m “Fixed severe production problem”
[hotfix-1.2.1 abbe5d6] Fixed severe production problem
5 files changed, 32 insertions(+), 17 deletions(-)

结束一个热补丁分支

修复完成后,热补丁分支需要合并回master,但同时它还需要被合并回develop,这样相关的修复代码才会同时被包含在下个版本中。这与我们完成发布分支很类似。

首先,更新master分支并打上标签。

$ git checkout master
Switched to branch ‘master’
$ git merge –no-ff hotfix-1.2.1
Merge made by recursive.
(Summary of changes)
$ git tag -a 1.2.1

提醒: 你可能同时也会想要用 -s 或者 -u <key> 来对标签进行签名。

接着,将修复代码合并到develop:

$ git checkout develop
Switched to branch ‘develop’
$ git merge –no-ff hotfix-1.2.1
Merge made by recursive.
(Summary of changes)

这里还有个例外情况,如果这个时候有发布分支存在,热补丁分支的变更则应该合并至发布分支,而不是develop 。将热补丁合并到发布分支,也意味着当发布分支结束的时候,变更最终会被合并到develop。(如果develop上的开发工作急需热补丁并无法等待发布分支完成,这时你也已经可以安全地将热补丁合并到develop分支。)

最后,删除临时的热补丁分支:

$ git branch -d hotfix-1.2.1
Deleted branch hotfix-1.2.1 (was abbe5d6).

小结

虽然这个分支模型中没有什么特别新鲜的东西,但本文起始处的“全景图”事实上在我们的项目中起到了非常大的作用。它帮助建立了优雅的,易理解的概念模型,使得团队成员能够快速建立并理解一个公用的分支和发布过程。

我同时也提供了一个该图对应的高质量PDF版本 。你可以打印出来并挂在墙上,随时参考。

分享到:
评论

相关推荐

    base zz zz zz zz

    base zz zz zz zz zz base zz zz zz zz zz base zz zz zz zz zz base zz zz zz zz zz

    变形版SD ZZ高达 纸模型

    SD(Super Deformed)是日本动漫中的一个术语,意为超级变形,通常指的是角色被夸张地简化和可爱化,保留了主要特征,而ZZ高达则是该系列的主角机体之一。这款纸模型的独特之处在于其可变形的设计,让静态的纸模具有...

    在pp碰撞中测量ZZ生产截面和Z→分支分数

    对于具有两个相反符号的事件,测量了ZZ生产横截面σ(pp→ZZ)= 14.6−1.8 + 1.9(stat)−0.3 + 0.5(syst)±0.2(theo)±0.4(lumi)pb, 在质量区域60 &lt;m xss=removed&gt; 4 GeV,±0.1(lumi)×10−6 同味轻质...

    新安江模型程序核心源代码_新安江模型_XinanjiangMODEL_XinJiang_

    “新安江模型程序核心源代码.docx”这个文档可能包含了模型的详细算法描述、源代码结构解析、使用指南和示例应用等内容,对于学习和应用新安江模型的人来说是宝贵的参考资料。通过阅读和理解这个文档,可以更深入地...

    隐马尔可夫模型中的Viterbi算法zz

    Viterbi算法是概率模型,特别是隐马尔可夫模型(Hidden Markov Model, HMM)中的一个重要概念,用于寻找最有可能产生给定观测序列的状态序列。在这个算法中,我们假设观测序列是马尔可夫过程的结果,而状态序列是不...

    科学定价策略与模型zz.pptx

    《科学定价策略与模型zz.pptx》旨在为组织提供一个综合性的定价框架,帮助企业在不同的市场环境中制定出合理的价格策略。本文将根据给定的信息,详细阐述该文件中的核心概念及其应用。 #### 二、定价策略框架的目标...

    高仿微信,iOSAppTemplate代码重构 此版本TLChat基于TLKit、 ZZFLEX实现

    文件名称"TLChat-master"暗示这是一个Git仓库的主分支,可能包含了整个项目的源代码和资源文件。开发者可以下载这个压缩包,通过查看源码学习如何结合TLKit和ZZFLEX来重构一个类似微信的应用。这不仅可以深入理解这...

    git_windows(64位)

    在这个压缩包中,包含的是Git的64位安装程序——Git-2.12.0-64-bit.exe,这是一个用于在Windows 64位环境下安装Git的可执行文件。 Git的核心特性包括: 1. 分布式:每个开发者的本地工作目录都是一个完整的仓库,...

    勘误至:$$ \ hbox {pp} \ rightarrow \ hbox {ZZ} $$ pp→ZZ生产横截面和$$ \ hbox {Z} \ rightarrow 4 \ ell $$ Z→4ℓ分支分数的测量, $$ \ sqrt {s} = 13 \,\ hbox {TeV} $$ s = 13TeV时异常三重量规耦合的约束和约束

    由于提供的文件信息是关于一篇物理研究文章的勘误声明,文章讨论了在质子碰撞产生ZZ玻色子的生产截面以及Z玻色子衰变成四个轻子的分支分数测量,并在13 TeV的质心系能量下对异常三重量子耦合进行了约束。文章的勘误...

    git_windows(32位)

    Git-2.12.0是Git的一个特定版本,代表了该软件在2017年发布时的一个稳定分支。每个版本的Git都会带来一些新特性、改进和错误修复。2.12.0版本可能包含了如下特点: 1. **增强的性能**:Git团队持续优化Git的核心...

    zz809.com留言本

    总的来说,《zz809.com留言本》不仅是一个实际的网络应用,也是学习Web开发,尤其是PHP或相关技术的一个实例教程。对于初学者而言,这是一个宝贵的资源,可以帮助他们在实践中提高技能;对于有经验的开发者,它则...

    ZZ561401.CAB

    ZZ561401.CAB ZZ561401.CAB ZZ561401.CAB

    wincc AX NF ZZ

    wincc SIMATIC WinCC是第一个使用最新的32位技术的过程监视系统,具有良好的开放性和灵活性。 从面市伊始,用户就对SIMATIC WinCC印象深刻。

    ZZFLEX:一个完善的iOS敏捷开发框架,基于UIKit实现,包含常用控件的链式API拓展、一个数据驱动的列表框架、一个事件处理队列

    一个完善的iOS UI敏捷开发框架,基于UIKit/Foundation,包含常用控件的链式API拓展、一个命令式的列表控制器、一个事件处理队列,使用“模块化”的设计思路,致力于大大减小UI开发和维护的难度和工作量。 更新 1.1 1...

    MAX模型 火影佐助

    【标题】"MAX模型 火影佐助"所指的是使用3D建模软件3DS MAX创建的一个基于《火影忍者》角色宇智波佐助的三维模型。3DS MAX是一款广泛应用于游戏开发、影视特效、建筑可视化等领域的专业三维建模与动画软件。在3D建模...

    zz CAD快速计算长度插件

    在CAD中想要快速测量长度,在CAD工具栏找到加载应用程序,再点击加载 加载成功后在输入栏输入“zz”(不分大小写)在选择你需要测量的线段即可。

    Duncan-Chang模型第四章本构模型[参照].pdf

    【邓肯-张模型】是1970年由Duncan和Chang提出的非线性次弹性模型,属于变模量模型。该模型假设应力-应变关系为双曲线形状,因此也被称为双曲线模型。在该模型中,切线杨氏模量tE和泊松比tv不是常数,而是随应力水平...

    在带有Prophecy4f的“两希格斯双峰”模型中h→WW / ZZ→4个费米子的精确计算

    我们已经计算出了两种希格斯-双重峰模型(I型和I型)的轻度CP-偶数希格斯玻色子h的衰变过程h→WW / ZZ→4个费米子的次优阶电弱和QCD校正。 II,“轻子相关”和“翻转”模型)。 输入参数以四种不同的重归一化方案...

Global site tag (gtag.js) - Google Analytics