本作品原发布账号为【白鸽子中文网】,现转至当前账号【飞翔中文网】。
反思备录(2020/3/5)
这个模型构思于2010年,现已过去10余年,(2010年)那时正处于Git诞生后不久。在这10年间,git-flow(本文中提到的分支模型) 在许多软件队伍里特殊流行,以至于人们已经把它当成某种软件标准——但不幸的是它也被视为教条或灵丹妙药。
在这10年里,Git本身已经席卷了世界,而使用Git开发的最受接待的软件类型正在更多地转向网络应用步调,至少在我的过滤器泡沫(认知)中是这样。Web应用步调通常是连续交付的,而不是回滚的,而且您不必支持在非主体系中(?)运行的多个版本的软件。
这不是我10年前写博客时想的那种软件。如果您的团队正在持续交付软件,我建议您采用更简单的工作流(如GitHub流),而不是试图将git-flow塞进您的团队。
然而,如果您正在构建明确版本化的软件,或者如果您需要在非主体系中(?)支持多个版本的软件,那么git-flow大概仍旧像过去10年一样恰当您的团队。在这种情况下,请继续阅读。
总之,永远记住,灵丹妙药是不存在的。充分思量你自己的配景——不要讨厌自己决定。
正文
在这篇文章中,我介绍了大约一年前我为我的一些项目(包罗工作和私家项目)介绍的开发模式,效果证实它非常成功。我想写这篇文章已经有一段时间了,但直到现在,我还没有真正找到时间写得这么彻底。我不谈任何项目标细节,只谈分支计谋和发布管理。
为什么使用Git?
有关Git与会合式源代码控制系统的优缺点的详细讨论,请参阅web(http://git.or.cz/gitwiki/GitSvnComparsion)。那里正在进行大量的唇枪舌战。作为一名开发职员,我更喜欢Git,而不是现在的所有其它工具。Git确实改变了开发职员对合并和分支的见解。从我所处的经典CVS/Subversion体系来看,分离(分支)/合并(分支)不停被认为有点可骇(“小心合并冲突,它们会反噬你!”)而你只是偶尔做一次。
但是使用Git,这些操纵非常便宜和简单,它们被认为是日常工作流程的焦点部分之一。例如,在CVS/Subversion书籍中,分离和合并首先在背面的章节中讨论(对于高级用户),而在每一本Git书籍中,它已经在第3章(底子知识)中讨论过了。
由于其自身的简单性和重复性,分离和合并不再是令人害怕的事情。版本控制工具应该比其他任何工具更能资助分离/合并。
关于工具的内容已经充足了,让我们继续讨论开发模型。我将在这里介绍的模型根本上只不过是一系列的操纵,每个团队成员都必须遵照这些操纵才华进入托管软件开发过程。
去中心化又中心化
我们使用的存储仓库设置,它与这个分支模型很好地配合使用,是一个中心“真实”仓库。请注意,该仓库仅被(人为)视为中心仓库(由于Git是一个DVCS[Distributed Version Control System,分布式版本控制系统],因此在技能层面上不存在中心仓库)。我们将此仓库称为原始仓库origin,因为所有Git用户都熟悉这个名称。
每个开发职员都将其代码分离于且提交到原始仓库origin。但除了统一的“推送-拉取”关系之外,每个开发职员还可以从其他偕行那里获取更改,以组成子团队。例如,在过早地将正在进行的工作推到原始仓库origin之前,与两个或两个以上的开发职员互助开发一个大的新特性大概会很有用。在上图中,有爱丽丝(alice)和鲍勃(bob)、爱丽丝与大卫(david)、克莱尔(clair)和大卫的子组。
从技能上讲,这意味着Alice定义了一个名为bob的Git长途,指向bob的存储库,反之亦然(bob也定义了一个名为alice的长途仓库并指向)。
焦点分支
最焦点的是,开发模型受到了现有模型的极大开导。中心仓库持有两个寿命无穷(伴随软件开发的整个周期)的焦点分支:
master
develop
每个Git用户都应该熟悉原始仓库origin的主分支master。与主分支master并行的尚有另一个分支,称为开发分支develop。
我们认为origin/master是焦点分支,是因为其HEAD源代码总是反映生产就绪状态。
我们认为origin/develop是焦点分支,是因为其HEAD源代码总是反映下一个版本中最新交付的开发更改的状态。有人会称之为“集身分支”。这是构成任何主动夜间构建的底子。
当开发分支develop中的源代码到达稳定点并准备发布时,所有更改都应该以某种方式合并回主分支master,然后用发布号标记。这将在背面详细讨论。
因此,每次将更改合合并到主分支master时,这都是一个新的生产版本。我们倾向于对此非常严格,因此理论上,我们可以使用Git钩子脚本在每次主服务器上提交代码到主分支master时主动构建软件,并将其推出到我们的生产服务器。
支持分支
除了主分支master和开发分支develop之外,我们的开发模型还使用各种支持分支来资助团队成员之间的并行开发,简化功能跟踪,为生产发布做准备,并资助快速解决实时生产题目。与焦点分支差别,这些分支的寿命总是有限的,因为它们最终会被移除(不必伴随软件开发的整个周期)。
我们大概(“大概”->言外之意也可以自己定义)使用的差别类型的分支有:
Feature branches
Release branches
Hotfix branches
这些分支每个都有特定的目标,并受严格的规则约束,即哪些分支可以是其原始分支,哪些分支必须是其合并目标。我们将在一分钟内彻底相识它们。
从技能角度来看,这些分支绝非“特殊”。分支类型根据我们使用它们的方式进行分类。它们固然是普通的旧Git分支。
特性分支Feature branches
可以来自于(特定分支):
develop
必须合并到(特定分支):
develop
分支命名约定:
除了master,develop,release-*,或hotfix-*之外的所有命名均可。
特性分支Feature branches(或有时称为主题分支)用于为即将发布或将来发布的版本开发新功能。当开始开发一个特性时,这个特性将被纳入的目标版本在那个时候大概是未知的。特性分支的本质是,只要特性处于开发阶段,它就不停存在,但最终会被合并回开发分支develop(以明确地将新特性添加到即将发布的版本中)或被丢弃(以防出现令人失望的履历)。
特性分支Feature branches通常只存在于开发者存储库中,而不存在于原始仓库origin中。
创建功能分支Creating a feature branch
在开始新特性的工作时,从开发分支develop拉出分支。
- $ git checkout -b myfeature develop
- Switched to a new branch "myfeature"
复制代码 在开发过程中合并已完成的功能Incorporating a finished feature on develop
完成的功能可以合并到开发分支develop中,以明确地将它们添加到即将发布的版本中:
- $ git checkout develop
- Switched 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标记使合并始终创建一个新的提交对象,纵然(不使用的话)合并可以快速执行。这避免了丢失关于特性分支的历史存在的信息,并将一起添加特性的所有提交分组在一起。比较:
在后一种情况下,(合并以后)不大概从Git历史中看到哪些提交对象一起实现了一个特性,您必须手动读取所有日志消息。恢复整个特性(例如一组提交)是一个真正令人头痛的题目,而如果使用了--no ff标记,则很轻易完成。
是的,它将创建更多(空)提交对象,但收益远大于成本。
发布分支Release branches
可以来自于(特定分支):
develop
必须合并到(特定分支):
develop和master
分支命名约定:
release-*
发布分支为新的生产发布提供支持。它们答应在末了一刻打点和提交……(原文是:They allow for last-minute dotting of i’s and crossing t’s,此句不明?)。别的,它们还答应小的错误修复和为发布准备元数据(版本号、构建日期等)。通过在发布分支上完成所有这些工作,开发分支develop可以接收下一个大型发布的特性。
从开发分支develop拉出新发布分支的关键时候是开发分支(几乎)反映了新发布的期望状态。至少现在所有针对要构建的版本的特性都必须合并在开发分支develop中。所有面向未来版本的功能(大概都不是),它们必须等到发布分支被分离后。
正是从发布分付出现开始,即将发布的版本被分配了一个版本号——而不是更早的时候。直到那一刻(指发布分付出现),开发分支develop反映了“下一次发布”的变革,但在发布分支开始之前,尚不清楚“下一版本”最终会酿成0.3还是1.0。这个决定是在发布分支开始时做出的,并由项目关于版本号变动的规则执行。
创建发布分支Creating a release branch
发布分支是从开发分支develop创建的。例如,假设1.1.5版本是当前的生产版本,并且我们即将发布一个大版本。开发分支develop的状态已经为“下一个版本”做好了准备,我们已经决定这将成为1.2版(而不是1.1.6或2.0版)。以是我们拉出分支并给为其起一个反映新版本号的名称:
- $ git checkout -b release-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中,并且,等待下一个大型版本。
完成发布分支Finishing a release branch
当发布分支的状态准备成为真正的发布时,需要执行一些操纵。首先,发布分支被合并到主分支master中(因为主分支master上的每个提交根据定义都是一个新的发布,请记住这点)。接下来,必须标记在主分支master上的提交,以便于将来参考此历史版本。末了,需要将发布分支上所做的更改合并回开发分支develop中,以便将来的发布也包含这些错误修复。
在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).
复制代码 修补步调分支hotfix
可以来自于(特定分支):
master
必须合并到(特定分支):
develop和master
分支命名约定:
hotfix-*
修补步调分支与发布分支非常相似,因为它们也旨在为新的生产发布做准备,尽管是计划外的。它们产生于必须立即对现场制作版本的不期望状态接纳办法。当必须立即解决生产版本中的关键bug时,可以从标记生产版本的主分支上的相应标记分出一个修补步调分支。
本质是团队成员(在开发分支develop上)的工作可以继续,而另一个人正在准备快速的生产修复。
创建修补步调分支Creating the hotfix branch
修补步调分支是从主分支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并在一次或多次单独提交中提交修复。
- $ git commit -m "Fixed severe production problem"
- [hotfix-1.2.1 abbe5d6] Fixed severe production problem
- 5 files changed, 32 insertions(+), 17 deletions(-)
复制代码 完成修补步调分支Finishing a hotfix branch
完成后,bugfix(hotfix)需要合并回主分支master,但也需要合并回开发分支develop,以确保bugfix(hotfix)也包含在下一个版本中。这完全雷同于发布分支的完成方式。
首先,更新主分支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).
复制代码 总结
虽然这个分支模型并没有什么真正令人震惊的新东西,但这篇文章开头的“大图”体现出在我们的项目中非常有用。它形成了一个优雅的心理模型,易于明白,并答应团队成员对分支和发布过程形成共同的明白。
本文翻译自网络:https://nvie.com/posts/a-successful-git-branching-model
本文由飞翔中文网「feixiang.net」翻译
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |