一个成功的Git分支模型

本文翻译至:nvie.com/posts/a-suc…php

译者: TopJohngit

原文链接:www.xuanzhangjiong.top/2019/01/30/…github

版权归做者全部,商业使用请联系做者shell

一个成功的Git分支模型

在这篇文章中,我将介绍一下在一年前很是成功的不只是工做也包括私人项目的开发模型。我一直想写关于开发模型相关的内容,可是历来没有像如今这么强烈。在这里,我并不想将任何项目的细节,仅仅是想表达关于分支策略以及发布管理相关的内容。 bash

git-model

为何选择git?

有关Git与集中式源代码控制系统的优缺点讨论,请参阅网站。在代码的控制系统中,硝烟弥漫。做为一个开发者,在今天,相比于其余工具我更喜欢Git。Git真的改变了开发者对合并和分支的想法。从我来看经典的CVS/Subversion世界,合并/分支一般被认为是使人惧怕的(“当心合并冲突,它们会咬你!”),并且是每过一段时间都会作的事情。服务器

可是对于Git来讲,这些操做是极其廉价和简单的,它们真的被认为是您平常工做流程中的核心部分之一。例如,在CVS/Subversion书籍中,分支和合并在后续的章节中首次讨论(并且是对于高级用户),可是在Git书籍中,它们在第三章中就出现了(基础部分)。分布式

因为其简单和重复的性质,分支和合并变得再也不那么可怕。版本控制工具应该比其余任何东西更有助于分支/合并。svn

当咱们有了足够的了解,让咱们进入开发模型中去。我将在这里呈现的模型实质上只是一套每一个团队成员都应该遵循的软件开发模式。工具

分散但集中

咱们使用的仓库和分支模型配合得不错,是一个可信的中心化的仓库,这里指的是初始化的远程仓库。不过要注意,这是惟一的一个被认为是中央库的仓库(由于Git是一个分布式的版本管理系统,在技术层面上来说没有一个中心化的仓库)。咱们会把这个仓库称为origin(原始库),由于它的名字对全部用户来讲都比较熟悉。post

centr-decentr

每个开发者将代码拉取或者推送到origin(原始库)中。可是除了集中式的推拉关系以外,每一个开发者也能够从其余节点获取变动来造成子团队。举个例子,当两个或者更多的开发者一块儿开发一个新特性,这将变得很是有用,能够避免过早地将代码推送到原始库中。在上图中,Alice和Bob是一个子团队,Alice和David是一个子团队,Clair和David是一个子团队。

在技术上,这意味着Alice定义了一个远程分支,叫作bob,指向了Bob的仓库,反之亦然。

主分支

在核心部分,开发模式很大程度受到了传统模型的影响。中央库一直维护2个能够无限延伸的分支:

  • master 分支
  • develop 分支

main-branches

在原始库中,master分支应该被全部用户所熟知。和master分支并行的还有另外一个分支叫作develop分支。

咱们把origin/master分支做为主分支,这个分支代码的HEAD指针老是指向生产版本代码的一个准备状态。

咱们把origin/develop分支做为一个反映下一次须要交付的代码变动的分支。有人会叫develop分支为“集成分支”。这是全部夜间自动构建的出处。

当源代码在develop分支中到达一个稳定的状态以后,已经准备好发布了,那么全部的变动应该以某种方式被合并回master分支。同时打上版本号。这个操做会在后续进行详细讲解。

所以,每次当变动被合并到主分支的时候,将定义一个新的生产版本。咱们对此很是严格,所以从理论上来讲,咱们可使用Git hook脚本在每次对master分支进行提交代码的时候进行构建和在你的生产服务器上发布你的软件。

辅助分支

接下,来,除了master分支和develop分支你的开发模型上须要使用一系列的辅助分支来帮助团队的成员平行地开发,轻松地追踪一些特性,为生产发布作准备,并帮助快速修复生产版本代码的问题。不像主分支,这些分支的生命周期是有限的,由于它们最终将会被移除。

咱们使用不一样类型的分支:

  • Feature 分支
  • Release 分支
  • Hotfix 分支

这些分支每个都有特定的目的以及严格的规则,例如什么分支能够做为它们的原始分支,什么分支能够做为他们合并的目标。接下来咱们将展开讨论。

从技术角度来说,这些分支绝对不是“特殊的”。这些分支的类型取决于咱们如何去使用它们。它们一样是平凡的Git分支。

功能分支(feature branches)

功能分支可能从develop分支分离出来,可是必须合并到develop分支中去。

功能分支的命名规范:

除了master,develop,release-*,或者hotfix-*以外的名字均可以。

fb

功能分支(或者有时候叫作主题分支)是被用来开发即将发布或者将来版本的新功能的分支。在开发新功能的时候,目标的须要合并的发布版本可能在那个时候还不肯定。功能分支的本质是它存在于新功能开发的过程当中,最终将被合并到develop开发分支中去(为一个发布版本添加一个新特性)或者被丢弃(在实验状况使人失望的状况下)。

功能分支一般仅存在于开发人员的仓库中,而不是远程的原始库中。

建立一个功能分支

当要开发一个新功能的时候,通常都是从develop分支检出一个新分支。

$ git checkout -b myfeature develop
Switched to a new branch "myfeature"
复制代码

合并一个已经完成的分支到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标志-将致使建立一个新的commit标志,即便合并可使用fast-forward模式。这能够避免丢失功能分支的历史信息并将新特性和全部的提交合并到一块儿。比较:

merge-without-ff

在后一种状况,是不可能从Git历史中看到哪些提交记录实现了这个功能-你必须经过手动读取全部的log记录才能获取到相关信息。恢复整个功能(即一组提交),在后一种状况下是真的很头疼,可是若是使用了--no-ff标志就很容易完成。

虽然将多处几个(空的)提交记录,可是它的收益远大于成本。

发布分支(Release branches)

可能一个release分支是从develop分支切出来的,可是它必须被合并到develop或者master分支上去,分支的命名惯例通常是:release-*

Release分支用于支持新的生产版本的发布。它容许在最后作一些点缀或者小修改。此外,它们容许修复小错误而且准备发布的元数据(例如版本号,构建日期等)。经过在发布分支上完成全部这些工做,develop分支将更明确地准备下一个大版本的发布。

从develop分支建立release分支的关键时刻是develop分支达到了一个想要发布的理想状态。至少此次想要发布的特性必须被合并到develop分支在切出release分支以前。全部打算在将来发布的版本中特性须要在release分支切出来以后在合并进去。

在release分支开始的时候为即将发布的版本分配一个版本号--而不是在release分支以前。直到那一刻,develop分支反映的变化都是为了下一次发版,可是至于下一次发版是0.3仍是1.0是不清楚的,在release分支切出来以前。这个决定是在release分支开始的时候根据项目的规定定的,版本号也是根据项目的要求定的。

建立一个release分支

Release分支从develop分支建立。举个例子,假设1.1。5版本是当前的生产分支,咱们即将推出一个大版本。目前develop分支的状态是已经好为下一个release作好了准备,而且决定下一个版本将是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(-)
复制代码

在建立并切换到release分支以后,咱们设置了版本号。这里,bump-version.sh虚构了一个shell脚本,改变一些文件来指向一个新的版本。(这里固然能够手动修改一些文件-来代表某些文件变了。)而后,设置的版本号就被提交了。

这个新分支会存在一段时间,直到发布版本被正式推出。在这段时间,问题修复将在这个分支进行(而不是在develop分支)。在这里进行一些大的新特性的添加是不被容许的。它们必须被合并到develop分支,等待下一次大版本的发布。

完成release分支

当release分支的状态到达了一个真正的发布版本的时候,咱们须要进行一些操做,以便完成此次发布。首先,release分支须要被合并到master分支中(由于根据定义master上的每一次提交都是一次新的发布,记住)。接下来,在master上的这个提交必须被打上标记,以便未来参考此历史版本。最终,在release分支上的变动须要合并到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 标志来对标记进行签名。

在Git中,为了保持此次发布中的变动,咱们须要将这些变动合并到develop分支中去:

$ 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 branches)

热修复分支可能来源于master分支,可是必须被合并到develop和master分支,分支命名惯例:hotfix-*

hotfix-branches

Hotfix分支很是像release分支,它们都是为一个新的生产分支作准备的,尽管Hotfix是计划以外的。它们源于生产版本一些不被指望的状态。在生产版本出现了严重的错误须要马上被修复,一个热修复分支须要根据master分支上生产版本的标记进行切出。

本质是团队的其余成员能够继续在develop分支上开发,与此同时须要有一我的来在Hotfix分支上进行bugfix。

建立热修复分支(hotfix branch)

热修复分支从master分支上建立。举个例子,1.2版本是当前运行的生产版本,因为严重的错误致使了一些问题。可是如今develop分支是不稳定的。咱们须要切出一个hotfix分支开始修复问题:

$ 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(-)
复制代码

在建立完分支以后不要忘记更新版本号!

接下来,修复错误,提交一个或者多个记录。

$ git commit -m "Fixed severe production problem"
[hotfix-1.2.1 abbe5d6] Fixed severe production problem
5 files changed, 32 insertions(+), 17 deletions(-)
复制代码

完成热修复分支

当完成了,bugfix须要合并到master分支,可是为了保障下次发布版本可以包含bugfix,一样须要被合并到develop分支。 这和release分支的实现是相似的。

首先,更新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 标志来对标记进行签名。

接下来,将bugfix合并到开发分支,一样:

$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff hotfix-1.2.1
Merge made by recursive.
(Summary of changes)
复制代码

规则的一个例外是:当一个release分支已经存在的状况下,热修复分支的变更须要合并到release分支中,而不是develop分支。 在release分支发布完成的时候,若是将错误修复合并到了release分支一样也会反映到develop分支中最终。(若是develop分支马上须要这个问题修复并且等不及release分支修复,那么你能够安然地合并问题修复到develop分支中。)

最终,移除这个临时的hotfix分支:

$ git branch -d hotfix-1.2.1
Deleted branch hotfix-1.2.1 (was abbe5d6).
复制代码

总结

虽然这个分支模型没有什么使人震惊的地方,可是在文章开头的这张大图在你的项目中是异常有用的。这造成了一个优雅的思惟模型,并且是很是容易让人理解的,容许团队成员创建一个共同的分支和发布的模型。

此处提供一个高质量的PDF版本。把它挂墙上以便随时参考。

更新:若是有人须要的话:这里是文章中Git图片的源文件gitflow-model.src.key

我的公众号
相关文章
相关标签/搜索