Git Flow 是什么
Git Flow是构建在Git之上的一个组织软件开发活动的模型,是在Git之上构建的一项软件开发最佳实践。Git Flow是一套使用Git进行源代码管理时的一套行为规范和简化部分Git操作的工具。
2010年5月,在一篇名为“一种成功的Git分支模型”的博文中,@nvie介绍了一种在Git之上的软件开发模型。通过利用Git创建和管理分支的能力,为每个分支设定具有特定的含义名称,并将软件生命周期中的各类活动归并到不同的分支上。实现了软件开发过程不同操作的相互隔离。这种软件开发的活动模型被nwie称为“Git Flow”。
一般而言,软件开发模型有常见的瀑布模型、迭代开发模型、以及最近出现的敏捷开发模型等不同的模型。每种模型有各自应用场景。Git Flow重点解决的是由于源代码在开发过程中的各种冲突导致开发活动混乱的问题。因此,Git flow可以很好的于各种现有开发模型相结合使用。
在开始研究Git Flow的具体内容前,下面这张图可以看到模型的全貌(引自nvie的博文):
Git Flow中的分支
Git Flow模型中定义了主分支和辅助分支两类分支。其中主分支用于组织与软件开发、部署相关的活动;辅助分支组织为了解决特定的问题而进行的各种开发活动。
主分支
主分支是所有开发活动的核心分支。所有的开发活动产生的输出物最终都会反映到主分支的代码中。主分支分为master分支和development分支。
master分支
master分支上存放的应该是随时可供在生产环境中部署的代码(Production Ready state)。当开发活动告一段落,产生了一份新的可供部署的代码时,master分支上的代码会被更新。同时,每一次更新,最好添加对应的版本号标签(TAG)。
develop分支
develop分支是保存当前最新开发成果的分支。通常这个分支上的代码也是可进行每日夜间发布的代码(Nightly build)。因此这个分支有时也可以被称作“integration branch”。
当develop分支上的代码已实现了软件需求说明书中所有的功能,通过了所有的测试后,并且代码已经足够稳定时,就可以将所有的开发成果合并回master分支了。对于master分支上的新提交的代码建议都打上一个新的版本号标签(TAG),供后续代码跟踪使用。
因此,每次将develop分支上的代码合并回master分支时,我们都可以认为一个新的可供在生产环境中部署的版本就产生了。通常而言,“仅在发布新的可供部署的代码时才更新master分支上的代码”是推荐所有人都遵守的行为准则。基于此,理论上说,每当有代码提交到master分支时,我们可以使用Git Hook触发软件自动测试以及生产环境代码的自动更新工作。这些自动化操作将有利于减少新代码发布之后的一些事务性工作。
辅助分支
辅助分支是用于组织解决特定问题的各种软件开发活动的分支。辅助分支主要用于组织软件新功能的并行开发、简化新功能开发代码的跟踪、辅助完成版本发布工作以及对生产代码的缺陷进行紧急修复工作。这些分支与主分支不同,通常只会在有限的时间范围内存在。
辅助分支包括:
- 用于开发新功能时所使用的feature分支;
- 用于辅助版本发布的release分支;
- 用于修正生产代码中的缺陷的hotfix分支。
以上这些分支都有固定的使用目的和分支操作限制。从单纯技术的角度说,这些分支与Git其他分支并没有什么区别,但通过命名,我们定义了使用这些分支的方法。
feature分支
使用规范:
- 可以从develop分支发起feature分支
- 代码必须合并回develop分支
- feature分支的命名可以使用除
master
,develop
,release-*
,hotfix-*
之外的任何名称
feature分支(有时也可以被叫做“topic分支”)通常是在开发一项新的软件功能的时候使用,这个分支上的代码变更最终合并回develop分支或者干脆被抛弃掉(例如实验性且效果不好的代码变更)。
一般而言,feature分支代码可以保存在开发者自己的代码库中而不强制提交到主代码库里。
release分支
使用规范:
- 可以从develop分支派生
- 必须合并回develop分支和master分支
- 分支命名惯例:
release-*
release分支是为发布新的产品版本而设计的。在这个分支上的代码允许做小的缺陷修正、准备发布版本所需的各项说明信息(版本号、发布时间、编译时间等等)。通过在release分支上进行这些工作可以让develop分支空闲出来以接受新的feature分支上的代码提交,进入新的软件开发迭代周期。
当develop分支上的代码已经包含了所有即将发布的版本中所计划包含的软件功能,并且已通过所有测试时,我们就可以考虑准备创建release分支了。而所有在当前即将发布的版本之外的业务需求一定要确保不能混到release分支之内(避免由此引入一些不可控的系统缺陷)。
成功的派生了release分支,并被赋予版本号之后,develop分支就可以为“下一个版本”服务了。所谓的“下一个版本”是在当前即将发布的版本之后发布的版本。版本号的命名可以依据项目定义的版本号命名规则进行。
hotfix分支
使用规范:
- 可以从master分支派生
- 必须合并回master分支和develop分支
- 分支命名惯例:
hotfix-*
除了是计划外创建的以外,hotfix分支与release分支十分相似:都可以产生一个新的可供在生产环境部署的软件版本。
当生产环境中的软件遇到了异常情况或者发现了严重到必须立即修复的软件缺陷的时候,就需要从master分支上指定的TAG版本派生hotfix分支来组织代码的紧急修复工作。
这样做的显而易见的好处是不会打断正在进行的develop分支的开发工作,能够让团队中负责新功能开发的人与负责代码紧急修复的人并行的开展工作。
示例
下面的示例演示本工作流如何用于管理单个发布循环。假设你已经创建了一个中央仓库。
创建开发分支
第一步为master
分支配套一个develop
分支。简单来做可以本地创建一个空的develop
分支,push
到服务器上:
git branch develop
git push -u origin develop
以后这个分支将会包含了项目的全部历史,而master
分支将只包含了部分历史。其它开发者这时应该克隆中央仓库,建好develop
分支的跟踪分支:
git clone ssh://user@host/path/to/repo.git
git checkout -b develop origin/develop
现在每个开发都有了这些历史分支的本地拷贝。
小红和小明开始开发新功能
这个示例中,小红和小明开始各自的功能开发。他们需要为各自的功能创建相应的分支。新分支不是基于master
分支,而是应该基于develop
分支:
git checkout -b some-feature develop
他们用老套路添加提交到各自功能分支上:编辑、暂存、提交:
git status
git add
git commit
小红完成功能开发
添加了提交后,小红觉得她的功能OK了。如果团队使用Pull Requests
,这时候可以发起一个用于合并到develop
分支。否则她可以直接合并到她本地的develop
分支后push
到中央仓库:
git pull origin develop
git checkout develop
git merge some-feature
git push
git branch -d some-feature
第一条命令在合并功能前确保develop
分支是最新的。注意,功能决不应该直接合并到master
分支。冲突解决方法和集中式工作流一样。
小红开始准备发布
这个时候小明正在实现他的功能,小红开始准备她的第一个项目正式发布。像功能开发一样,她用一个新的分支来做发布准备。这一步也确定了发布的版本号:
git checkout -b release-0.1 develop
这个分支是清理发布、执行所有测试、更新文档和其它为下个发布做准备操作的地方,像是一个专门用于改善发布的功能分支。
只要小红创建这个分支并push
到中央仓库,这个发布就是功能冻结的。任何不在develop
分支中的新功能都推到下个发布循环中。
小红完成发布
一旦准备好了对外发布,小红合并修改到master
分支和develop
分支上,删除发布分支。合并回develop
分支很重要,因为在发布分支中已经提交的更新需要在后面的新功能中也要是可用的。另外,如果小红的团队要求Code Review
,这是一个发起Pull Request
的理想时机。
git checkout master
git merge release-0.1
git push
git checkout develop
git merge release-0.1
git push
git branch -d release-0.1
发布分支是作为功能开发(develop
分支)和对外发布(master
分支)间的缓冲。只要有合并到master
分支,就应该打好Tag
以方便跟踪。
git tag -a 0.1 -m "Initial public release" master
git push --tags
Git
有提供各种勾子(hook
),即仓库有事件发生时触发执行的脚本。可以配置一个勾子,在你push
中央仓库的master
分支时,自动构建好对外发布。
最终用户发现Bug
对外发布后,小红回去和小明一起做下个发布的新功能开发,直到有最终用户开了一个Ticket
抱怨当前版本的一个Bug
。为了处理Bug
,小红(或小明)从master
分支上拉出了一个维护分支,提交修改以解决问题,然后直接合并回master
分支:
“`
git checkout -b issue-#001 master
Fix the bug
git checkout master
git merge issue-#001
git push
“`
就像发布分支,维护分支中新加这些重要修改需要包含到develop
分支中,所以小红要执行一个合并操作。然后就可以安全地删除这个分支了:
git checkout develop
git merge issue-#001
git push
git branch -d issue-#001
下一站
到了这里,但愿你对集中式工作流、功能分支工作流和Gitflow
工作流已经感觉很舒适了。你应该也牢固的掌握了本地仓库的潜能,push
/pull
模式和Git
健壮的分支和合并模型。
记住,这里演示的工作流只是可能用法的例子,而不是在实际工作中使用Git
不可违逆的条例。所以不要畏惧按自己需要对工作流的用法做取舍。不变的目标就是让Git
为你所用。