中心仓库具有两个永久的分支
master
develop
Git 用户应该对 origin
中 master
分支都很熟悉了。与 master
分支并行的另一个分支是 develop
分支。
origin/master
这一主要分支,其 HEAD
指向的源代码总是可用于生产环境
origin/develop
这一主要分支,其 HEAD
指向的源代码总是包含着最新已交付的功能,这些功能将会在下一次进行发布。这个分支通常会被用于每日自动构建的版本中。
当 develop
分支的代码足够稳定并已准备好发布出去的时候,所有的这些变更都应当以某种方式合并回 master
分支,然后打上一个已发布版本号。后面会讲到具体以什么方式来进行合并。
所以,根据之前的定义,每次将变更合并回 master
分支的时候,将产生一个新的生产环境版本。
除了 master
和 develop
两个分支外,这个开发模型使用一系列辅助分支来应对各种开发场景,例如,团队间并行开发,简化功能追溯,为生产环境版本作准备和帮助快速修复线上问题等等。不像主要分支那样,这些分支只有有限的使用周期,因为最后他们都会被删除掉。
我们可能会用到的各种分支类型有:
- 功能分支
- 预发布分支
- 热修复(hotfix)分支
这些分支都有其特定的作用,并且他们要从哪个分支迁出并最终又要回并回那个分支都有严格的规定。后面会一个个的来对这分支进行说明。
可能迁出的分支有:
develop
必须回并回的分支有:
develop
命名约定:
除了 master
,develop
,release-*
,hotfix-*
外都可以
功能分支被用于开发一个新的功能,这个功能将在不久之后(也可能要很久)会被发布出去。在开发该功能时,有可能还不知道要在什么版本发布。功能分支实质上只要这个功能还在开发中,那它就只会存在,但是最终他将会被合并回 develop
分支中(确定要将这个新功能添加到即将发布的版本中)或者被丢弃掉(由于这个功能很糟糕)。
功能分支通常只存在于开发者的本地仓库中,而不会同步到 origin
(远程仓库)上去。
当开始开发一个新功能的时候,从 develop
分支中迁出一个新的功能分支
# 切换到新的 myfeature 功能分支上
git checkout -b myfeature develop
将已完成的功能分支合并回 develop
分支以确保将他们添加到即将发布的版本中
# 切换到 develop 分支上
git checkout develop
# 将 myfeature 分支合并回 develop 分支
git merge --no-ff myfeature
# 删除 myfeature 分支
git branch -d myfeature
# 将新功能推送到远程仓库中
git push origin develop
这个 --no-ff
标志会让这一次合并自动生成一个 merge commit
,即使说这次合并能够已快进的形式执行。这种方式能够使这个功能分支保留历史记录中,也能够将这个功能的所有提交记录以整组形式呈现。下图是这两种合并模式示例。
上图右边的示例就没办法看出是哪些提交一起实现了某个功能——你必须人工的查看所有的日志信息。右边的那种情况下要回滚整个功能的话就会非常的头疼,但如果用 --no-ff
的话就很简单了。
虽然用 --no-ff
方式合并会产生一些空的提交,但总的来说还是利大于弊的。
可能迁出的分支有:
develop
必须回并回的分支有:
develop
master
命名约定:
release-*
(*
代表将要发布的版本号)
预发布分支用于辅助新的生产版本的准备工作。因而,它们允许在这上面修一修小 Bug 和为发布准备一些元数据(版本号,构建日期等等)。通过预发布分支上做这些事情,develop
分支就能清爽的集成下一个发布版本的功能了。
从 develop
分支中迁出预发布分支的时机是开发分支几乎已经达到可发布版本的要求了。这个时间点,至少是将要发布的版本中的所有功能都已经合并回 develop
分支中了。所有后面版本的功能还不能合并进来,要等到即将发布的这个版本从开发分支中迁出一个预发布分支后才行。
在迁出一个预发布分支后,要给这个发布版本分配一个版本号。直到这时候,develop
分支对应的变更才是下一个发布版本,但是下一个版本到底是变成 0.3 还是 1.0 这会儿还不知道。要在下一个预发布版本迁出来后,根据项目的版本增加规则来确定。
预发布分支要从 develop
衍生出来。例如,现在有一个 1.1.5 版本的生产环境版本,然后我们即将有一个大的版本即将发布。develop
已经准备好发布下一个版本,并且我们打算发布一个 1.2 版本(不是 1.1.6 或 2.0)。所以我们迁出一个发布分支并给这个分支其一个合适的名称来反应这个新的版本号。
# 新建并切换到新的 `release-1.2` 分支
git checkout -b release-1.2 develop
# 修改所有版本相关的文件(版本号等数据)
./bump-version.sh 1.2
# 提交修改后的文件
git commit -a -m "增加版本号到 1.2"
新建并切换到新分支后,我们升级到了新的版本号。bump-version.sh
是一个工具脚本,这个脚本用来修改一些文件来反应当前新的版本信息(也可以手动的去修改这些文件——主要就是文件修改)。然后,提交这些升级后的文件。
这个新的分支可能会存在一段时间,直到这个版本发布出去为止。在这段时间内,可能会在这个分支上修修新发现的 Bug (而不是在 develop
分支上)。严禁在这个分支上添加大的功能。新功能只能合并到 develop
上,要等到下一个发布版本。
当这个预发布分支已经准备好发布了,需要执行以下的操作。首先,将这个预发布分支合并到 master
分支(因为根据定义 master
上的每个提交都是一个新的发布)。下一步,那个 master
分支上的提交必须被打上一个标签以便于未来引用这个历史版本。最后,这些在预发布版本的所有变更都要合并回 develop
分支,以至于未来的发布版本中也能够包含这些 Bug 修复。
# 切换到 master 分支
git checkout master
# 合并 release-1.2
git merge --no-ff release-1.2
# 打上标签
git tag -a 1.2
这个发布就完成了,并且打了个标签以便于未来引用。
也可以通过使用
-s
或-u <key>
标志来加密你的 tag
我们还需要将这些变更合并回 develop
分支
# 切换到 develop 分支
git checkout develop
# 合并 release-1.2
git merge --no-ff release-1.2
这个步骤可能会导致一些代码冲突(很有可能,因为我们之前修改了版本号)。如果有的话,解决冲突并提交。
到目前为止这个预发布流程就算做完了,然后就可以把这个预发布分支删掉了,因为我们已经用不到他了。
git branch -d release-1.2
可能迁出的分支有:
master
必须回并回的分支有:
develop
master
命名约定:
hotfix-*
(*
代表已发布的版本号)
热修复分支与预发布分支很像,它们都是为一个新的生产环境版本做准备,尽管这是计划外的。这些热修复分支源于必须对线上版本的一些意外情况立即作出一些应对。例如,必须马上修复一个生产环境中的致命 Bug。一个热修复分支会从一个打有相应生产环境版本的主分支中迁出来。
这主要在于团队成员能够继续它们的工作(在 develop
分支上),而其他人能够着手快速的修复这个线上 Bug。
热修复分支从 master
分支衍生出来。例如,有一个 1.2 版本是当前的线上版本,由于一个严重的 Bug 导致了一个问题。但是在 develop
分支上还不够稳定。我们这时就是迁出一个热修复分支并开始修复这个问题。
# 切换到一个新的 hotfix-1.2.1 分支
git checkout -b hostfix-1.2.1 master
# 增加版本好为 1.2.1
./bump-version.sh 1.2.1
# 提交这个版本修改
git commit -a -m "增加版本号到 1.2.1"
迁出一个分支后别忘了马上增加版本号!
然后,修复这个 Bug 并提交这个修复(也可能有多个提交)
git commit -m "修复严重的线上问题"
做完以后,这个修复需要合并回 master
分支,同时也需要合并回 develop
分支,为了保证这个修复也包含在下一个发布中。这和预发布分支的做法一模一样。
首先,更新 master
分支并打上发布标签
# 切换到 master 分支
git checkout master
# 合并 hotfix-1.2.1
git merge --no-ff hotfix-1.2.1
# 打上标签
git tag -a v1.2.1
也可以通过使用
-s
或-u <key>
标志来加密你的 tag
下一步,让 develop
也包含这个修复
# 切换到 develop 分支
git checkout develoop
# 合并 hotfix-1.2.1 分支
git merge --no-ff hotfix-1.2.1
在这里有一个例外,如果现在存在一个预发布分支,那么这个修复需要合并到那个预发布分支中,而不是 develop
分支。当那个预发布分支结束的时候,合并回 develop
分支的同时这个修复也会跟着一起合并回去。如果 develop
分支当下就需要这个热修复而没办法等那个预发布分支结束,你也可以安全将这个热修复合并到 develop
分支中。
最后,移除这个临时分支
git branch -d hotfix-1.2.1
原文 A successful Git branching model (翻译时对内容做了部分调整)