共计 5495 个字符,预计需要花费 14 分钟才能阅读完成。
这个模型是在 2010 年构思进去的,而当初距今已有 10 多年的历史,而 Git 自身才诞生不久。在那 10 年中,git-flow(本文介绍的分支模型)在许多软件团队中十分风行,以至于人们开始将其视为某种规范,但可怜的是,它也被当作教条或灵丹妙药。
在那 10 年中,Git 自身就席卷了整个世界,并且与 Git 一起开发的最风行的软件类型正在越来越多地转向 Web 应用程序 - 至多在我的过滤泡中。Web 应用程序通常是间断交付的,不会回滚,并且您不用反对晚期运行的软件的多个版本。
这不是我十年前写博客时想到的那种软件。如果您的团队正在继续交付软件,我建议您采纳更简略的工作流程(例如 GitHub flow),而不是尝试将 git-flow 引入您的团队。
然而,如果您正在构建显式版本的软件,或者如果您须要在晚期支持软件的多个版本,那么 git-flow 依然可能像适宜您团队的人一样适宜您的团队最近 10 年。在这种状况下,请持续浏览。
总而言之,请始终记住万灵药不存在。思考您本人的状况。别厌恶 本人决定。
在这篇文章中,我介绍了大概一年前为我的一些我的项目(在工作中和在私人我的项目中)引入的开发模型,事实证明该模型十分胜利。我始终想写一阵子,然而直到现在,我还没有真正找到彻底这样做的工夫。我不会议论任何我的项目的细节,而只会议论分支策略和公布治理。
去中心化但中心化
咱们应用的并且与此分支模型配合良好的存储库设置是具备地方“实在”存储库的存储库设置。请留神,此 repo 仅 被视为 地方仓库(因为 Git 是 DVCS,因而在技术层面上没有地方仓库这样的货色)。咱们将此存储库称为 origin,因为所有 Git 用户都相熟此名称。
每个开发人员 pulls 和 pushes 到名为 origin 的存储库。但除了中心化的推拉关系,每个开发者也可能会从其余同行那里 fetch 变动,造成子团队。
次要分支
要害地是,开发模型受到现有模型的极大启发。地方仓库领有两个具备有限生命周期的次要分支:
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-
性能分支(或有时称为主题分支)用于为行将公布或边远的将来版本开发新性能。当开始开发性能时,此时可能不晓得将合并该性能的指标版本。性能分支的实质在于,只有该性能处于开发阶段,它就存在,但最终会被合并回 develop(明确将新性能增加到行将公布的版本中)或抛弃(如果试验令人悲观)。
性能分支通常只存在于开发者仓库中,而不存在于 origin.
创立 feature branches
当开始一个新个性的工作时,从这个 develop 分支创立一个新的分支。
Git 命令
$ git checkout -b myfeature develop
Switched to a new branch "myfeature"
将曾经开发的性能分支合并到 develop 分支中
能够将实现的 featuren 分支合并到 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 and master
分支命名规定
release-*
Release branches 反对筹备新的生产版本。它们容许在最初一刻打点 i 和穿插 t。此外,它们容许修复小谬误并为公布筹备元数据(版本号、构建日期等)。通过在公布分支上实现所有这些工作,该 develop 分支被革除以接管下一个大版本的性能。
创立进去自于 develop 新 Release branches, 至多所有针对待构建版本的性能都必须合并 到 develop。所有针对将来版本的性能可能都不是——它们必须等到 Release branches 分支创立后。
正是在 release 分支的开始,行将公布的版本被调配了一个版本号——而不是更早的版本。直到那一刻,develop 分支反映了“下一个版本”的变动,但不分明“下一个版本”最终会变成 0.3 还是 1.0,直到 elease 分支启动。该决定是在公布分支开始时做出的,并由我的项目对于版本号减少的规定执行。
创立 release 分支
release 分支是从 develop 分支创立的。例如,假如版本 1.1.5 是以后的生产版本,咱们行将公布一个大版本。此时,develop 分支已为 ” 下一版本 ” 做好筹备, 这次发版将成为 1.2 版(而不是 1.1.6 或 2.0)。因而, 创立一个 release 分支并给该分支命名一个反映新版本的名称
$ 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"
[release-1.2 74d9424] Bumped version number to 1.2
1 个文件已更改,1 个插入(+),1 个删除(-)
在创立一个新分支并切换到它之后,咱们减少了版本号。这 bump-version.sh 是一个虚构的 shell 脚本,它更改了工作正本中的一些文件以反映新版本。(这当然能够是手动更改——要害是某些文件产生了更改。)而后,提交了减少的版本号。
这个新分支可能会存在一段时间,直到正式公布。在此期间,可能会在此分支(而不是在 develop 分支上)谬误修复 Bug,然而, 禁止在此处增加大型新性能的代码。新的性能代码, 必须合并到中 develop 分支,而后,期待下一个重要版本的公布。
实现一个 release 分支
当 release 分支的状态筹备好,能够筹备公布时, 在筹备公布时,能够先执行一些操作。首先,将 release 分支合并到 master 分支 (因为依据定义,每次提交到 master 的代码都是一个新版本)。接下来, 必须将此次提交打上标记,以不便参考此历史版本。最初, 在 releasef 分支提交的如 bugfix 的代码必须合并回 develop 分支,这样做将来的 release 分支也能够蕴含这些 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
这个 release 分支工作曾经全副实现, 并且曾经打上 tag 以便未来查看。
为了保留在 release 分支提交的代码,咱们须要将 release 分支合并到 develop 分支
对应的 Git 的操作
$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff release-1.2
Merge made by recursive.
(Summary of changes)
这步操作可能会导致合并抵触。如果产生了,解决抵触而后从新提交。
当初咱们真地做完所有的事件, 此时,咱们不在须要 release 分支, 对应的 release 分支能够被删除掉了。
$ git branch -d release-1.2
Deleted branch release-1.2 (was ff452fe).
hotfix 分支
此分支从 master 分支 fork。此会合并回 develop 分支和 master 分支。
此分支命名的格局:hotfix-*
热修复分支与公布分支十分类似,因为它们也意味着为一个新的生产版本做筹备,只管是计划外的。当必须立刻解决生产版本中的要害 bug 时,可能会从标记生产版本的主分支上的相应标记中拆散出一个热修复分支。
团队能够借用这个个性,一个人在 develop 分支上工作, 另一个正在筹备一次生产的修复代码。
创立 hotfix 分支
从 master 分支创立 hotfix 分支。举例, 假如 1.2 版本是以后正在运行的产品版本,并因为一个重大的 bug 而引起麻烦。然而处于开发中 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(-)
别忘记在 hotfix 分支名前面加版本号. 而后在 hotfix 分支修复 bug。
$ git commit -m "Fixed severe production problem"
[hotfix-1.2.1 abbe5d6] Fixed severe production problem
5 files changed, 32 insertions(+), 17 deletions(-)
实现 hotfix 分支
当在 hotfix 修复工作实现后,bug 修复代码须要合并到 master 分支, 同时也须要合并到 develop 分支, 这样做的目标, 是为了确保下一个版本中也蕴含 bug 修复代码, 这跟 release 分支实现有些相似。
首先,将 hotfix 分支合并到 master 分支, 并打上 tag
$ 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
接下来, 将 hotfix 分支也合并到 develop 分支
$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff hotfix-1.2.1
Merge made by recursive.
(Summary of changes)
这里有一个例外是, 如果以后存在一个 release 分支时,须要将热修复代码合并到该 release 分支中,而不是开发。当 release 分支实现时,将 bug 修复程序反向合并 release 分支中最终将导致 bug 修复程序也合并到 develop 分支中。(如果在 debelop 的工作立刻须要修复这个 bug,而不能期待 release 分支实现,那么您也能够平安地将这个 bug 修复合并到当初的 develop 分支中。)
最终,移除这个长期的分支
$ git branch -d hotfix-1.2.1
Deleted branch hotfix-1.2.1 (was abbe5d6).
总结
尽管这一分支模型并没有什么陈腐的货色,但本文一开始提到的“大图”对咱们的我的项目十分有用。它造成了一个易于了解的优雅的心智模型,并容许团队成员开发对分支和公布过程的共享了解。