Git 在团队中的最佳实践(二):如何正确使用 Git flow 工作流

前言

当在团队开发中使用版本控制系统时,商定一个统一的工作流程是至关重要的。Git 的确可以在各个方面做很多事情,然而,如果在你的团队中还没有能形成一个特定有效的工作流程,那么混乱就将是不可避免的。基本上你可以定义一个完全适合你自己项目的工作流程,或者使用一个别人定义好的。就像代码需要代码规范一样,代码管理同样需要一个清晰的流程和规范。

Git flow 工作流是经典模型,体现了工作流的经验和精髓。随着项目过程复杂化,会感受到这个工作流中深思熟虑和威力!Git flow 工作流没有用超出功能分支工作流的概念和命令,而是为不同的分支分配一个很明确的角色,并定义分支之间如何和什么时候进行交互。在这章节中我们将一起学习一个当前非常流行的工作流 Git flow。

Git flow 工作介绍

版本管理的挑战

虽然有这么优秀的版本管理工具,但是我们面对版本管理的时候,依然有非常大得挑战,我们都知道大家工作在同一个仓库上,那么彼此的代码协作必然带来很多问题和挑战,如下:

  • 如何开始一个 Feature 的开发,而不影响别的 Feature?
  • 由于很容易创建新分支,分支多了如何管理,时间久了,如何知道每个分支是干什么的?
  • 哪些分支已经合并回了主干?
  • 如何进行 Release 的管理?开始一个 Release 的时候如何冻结 Feature, 如何在 Prepare Release 的时候,开发人员可以继续开发新的功能?
  • 线上代码出 Bug 了,如何快速修复?而且修复的代码要包含到开发人员的分支以及下一个 Release?

大部分开发人员现在使用 Git 就只是用三个甚至两个分支,一个是 Master, 一个是 Develop, 还有一个是基于 Develop 打得各种分支。这个在小项目规模的时候还勉强可以支撑,因为很多人做项目就只有一个 Release, 但是人员一多,而且项目周期一长就会出现各种问题。

Git flow 流程

荷兰程序员 Vincent Driessen 曾发表了一篇博客 A Successful Git Branching Model,让一个分支策略广为人知。

下面是 Git flow 的流程图:

Git flow 的流程图

这一流程最大的亮点是考虑了紧急 Bug 的应对措施,整个流程显得过于复杂,所以在实施该方案前,需要对整个开发流程进行系统的学习。也需要借助 Git flow 等工具的辅助。

Git flow 安装以及初始化

工具 Git-flow 是按照 Vincent Driessen 的 branch 模型,实现的一个高层次(级别)的 git 仓库操作扩展集合。

Linux 安装 Git flow

Ubuntu 中使用 apt-get 安装 Git flow 的方法

1
$ sudo apt-get install git-flow

CentOS7 中使用 wget 安装 Git flow 的方法

1
$ wget --no-check-certificate -q  https://raw.githubusercontent.com/petervanderdoes/gitflow-avh/develop/contrib/gitflow-installer.sh && sudo bash gitflow-installer.sh install develop; rm gitflow-installer.sh

Mac 安装 Git flow

Mac 中使用 brew 安装 Git flow 的方法

1
$ brew install git-flow-avh

Windows 安装 Git flow

Windows 中使用 wget 安装 Git flow 的方法

1
$ wget -q -O - --no-check-certificate https://raw.github.com/petervanderdoes/gitflow-avh/develop/contrib/gitflow-installer.sh install stable | bash

Git flow 初始化

回答几个关于分支的命名约定的问题,建议使用默认值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ git flow init

No branches exist yet. Base branches must be created now.
Branch name for production releases: [master]
Branch name for "next release" development: [develop]

How to name your supporting branch prefixes?
Feature branches? [feature/]
Bugfix branches? [bugfix/]
Release branches? [release/]
Hotfix branches? [hotfix/]
Support branches? [support/]
Version tag prefix? [v]
Hooks and filters directory? [/home/ubuntu/study/.git/hooks]

Git flow 分支模型的介绍

Git flow 工作流仍然用中央仓库作为所有开发者的交互中心。和其它的工作流一样,开发者在本地工作并 push 分支到要中央仓库中。

  • Master 分支 - 生产分支
    最为稳定功能比较完整的随时可发布的代码,即代码开发完成,经过测试,没有明显的 bug,才能合并到 master 中。请注意永远不要在 master 分支上直接开发和提交代码,以确保 master 上的代码一直可用。
  • Develop 分支 - 开发分支
    用作平时开发的主分支,并一直存在,永远是功能最新最全的分支,包含所有要发布到下一个 release 的代码,主要用于合并其他分支,比如 feature 分支;如果修改代码,新建 feature 分支修改完再合并到 develop 分支。所有的 feature、release 分支都是从 develop 分支上拉的。
  • Feature 分支 - 功能分支
    这个分支主要是用来开发新的功能,一旦开发完成,通过测试没问题(这个测试,测试新功能没问题),我们合并回 develop 分支进入下一个 release。
  • Release 分支 - 发布分支
    用于发布准备的专门分支。当开发进行到一定程度,或者说快到了既定的发布日,可以发布时,建立一个 release 分支并指定版本号(可以在 finish 的时候添加)。开发人员可以对 release 分支上的代码进行集中测试和修改 bug。(这个测试,测试新功能与已有的功能是否有冲突,兼容性)全部完成经过测试没有问题后,将 release 分支上的代码合并到 master 分支和 develop 分支。
  • Hotfix 分支 - 热修复分支
    用于修复线上代码的 bug。从 master 分支上拉,完成 hotfix 后,打上 tag 我们合并回 master 和 develop 分支。

功能分支 - Feature 分支

功能分支 - Feature 分支

功能分支:通常为即将发布或者未来发布版开发新的功能,这通常只存在开发者的库中。当新功能开始研发,包含该功能的发布版本在这个还是无法确定发布时间的。功能版本的实质是只要这个功能处于开发状态它就会存在,但是最终会或合并到 develop 分支(确定将新功能添加到不久的发布版中)或取消(譬如一次令人失望的测试)。

分支命名规则:分支名称以 feature/* 开头

  1. 使用 Git 命令开发功能分支 - Feature 分支流程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 1. 开始一项功能的开发工作时, 基于'develop'创建分支
$ git checkout -b feature/some-feature develop

# 2. 推送到远程 -> 可选
$ git push -u origin feature/some-feature

# 3. 在'feature/some-feature'功能分支上开发完成后, 提交至仓库
$ git commit -a -m "some feature"

# 4. 切换到'develop'分支
$ git checkout develop

# 5. 从远程仓库拉去最新'develop'
$ git pull origin develop

# 6. 'develop'分支合并'feature'功能分支
$ git merge --no-ff feature/some-feature

# 7. 推送'develop'分支至远程仓库
$ git push origin develop

# 8. 删除'feature'功能分支
$ git branch -d feature/some-feature

# 9. 删除远程'feature'功能分支
$ git push origin --delete feature/some-feature

–no-ff 标志导致合并操作创建一个新 commit 对象,即使该合并操作可以 fast-forward。这避免了丢失这个功能分支存在的历史信息,将该功能的所有提交组合在一起。

Feature 分支 –no-ff 标志

  1. 使用 Git-flow 命令开发功能分支 - Feature 分支流程:
1
2
3
4
5
6
7
8
9
10
11
12
# 1. 增加新特性 P.S.[创建了一个基于'develop'的功能分支'some-feature', 并切换到这个分支之下]
$ git flow feature start some-feature

# 2. 完成新特性 P.S.[1. 合并'feature/some-feature'分支到'develop';2. 删除这个新特性分支; 3. 切换回'develop'分支]
Summary of actions:
- The feature branch 'feature/some-feature' was merged into 'develop'
- Feature branch 'feature/some-feature' has been locally deleted
- You are now on branch 'develop'
$ git flow feature finsh --no-ff some-feature

# 3. 推送'develop'分支至远程仓库
$ git push origin develop
1
2
3
4
5
6
7
8
# 1. 发布新特性 P.S.[发布新特性分支到远程服务器, 所以, 其它用户也可以使用这分支]
$ git flow feature publish some-feature

# 2. 取得一个发布的新特性分支 P.S.[取得其它用户发布的新特性分支, 并签出远程的变更]
$ git flow feature pull some-feature

# 3. 跟踪在 origin 上的特性分支]
$ git flow feature track some-feature

热修复分支 - Hotfix 分支

热修复分支 - Hotfix 分支

热修复分支:热修复分支与发布分支很相似,他们都为新的生成环境发布做准备,尽管这是未经计划的。他们来自生产环境的处于异常状态压力。当生成环境验证缺陷必须马上修复是,热修复分支可以基于 master 分支上对应与线上版本的 tag 创建。

分支命名规则:分支名称以 hotfix/* 开头

  1. 使用 Git 命令开发热修复分支 - Hotfix 分支流程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 1. 基于'master'创建热修复分支
$ git checkout -b hotfix/some-hotfix-0.1.1 master

# 2. 在'hotfix/some-hotfix-0.1.1'热修复分支上完成紧急修复, 提交至仓库
$ git commit -a -m "some hotfix"

# 3. 切换到'master'分支
$ git checkout master

# 4. 'master'分支合并'hotfix/some-hotfix-0.1.1'热修复分支
$ git merge --no-ff hotfix/some-hotfix-0.1.1

# 5. 推送'master'分支至远程仓库
$ git push origin master

# 6. 切换到'master'分支
$ git checkout develop

# 7. 'develop'分支合并'hotfix/some-hotfix-0.1.1'功能分支
$ git merge --no-ff hotfix/some-hotfix-0.1.1

# 7. 推送'develop'分支至远程仓库
$ git push origin develop

# 8. 删除'hotfix/some-hotfix-0.1.1'热修复分支
$ git branch -d hotfix/some-hotfix-0.1.1

# 9. 重新打标签
$ git tag -a v0.1.1 master

# 10. 提交所有 tag
$ git push --tags
  1. 使用 Git-flow 命令开发热修复分支 - Hotfix 分支流程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 1. 开始 git flow 紧急修复 P.S.[创建了一个基于'master'的热修复分支, 并切换到这个分支之下]
$ git flow hotfix start 0.1.1

# 2. 完成新特性 P.S.[1. 合并'hotfix/0.1.1'分支到'master';2. 给'master 打标签'v0.1.1';3. 合并'v0.1.1'分支到'develop';4. 删除本地'hotfix/v0.1.1'分支; 5. 切换回'develop'分支]
$ git flow hotfix finish --no-ff 0.1.1
Summary of actions:
- Hotfix branch 'hotfix/0.1.1' has been merged into 'master'
- The hotfix was tagged 'v0.1.1'
- Hotfix tag 'v0.1.1' has been back-merged into 'develop'
- Hotfix branch 'hotfix/0.1.1' has been locally deleted
- You are now on branch 'develop'

# 3. 切换到'master'分支
$ git checkout master

# 4. 推送'master'分支至远程仓库
$ git push origin master

# 5. 切换到'develop'分支
$ git checkout develop

# 6. 推送'develop'分支至远程仓库
$ git push origin develop

发布分支 - Release 分支

发布分支:Release 分支是为新产品的发布做准备的,它允许我们在最后时刻做一些细小的修改,它们允许小 bugs 的修改和准备发布元数据(版本号,开发时间等等)。Release 分支基于 develop 分支创建; 一旦创建了 release 分支,不能在从 develop 分支合并新的改动到 release 分支,可以基于 release 分支进行测试和 bug 修改,测试不用再另外创建用于测试的分支。

分支命名规则:分支名称以 release/* 开头

  1. 使用 Git 命令开发发布分支 - Release 分支流程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 1. 基于'develop'创建发布分支, 在此分支上小 bugs 的修改和准备发布元数据
$ git checkout -b release/some-release-0.1.1 develop

# 2. 切换到'master'分支
$ git checkout master

# 3. 'master'分支合并'release/some-release-0.1.1'热修复分支
$ git merge --no-ff release/some-release-0.1.1

# 4. 推送'master'发布分支至远程仓库
$ git push origin master

# 5. 切换到'master'分支
$ git checkout develop

# 6. 'develop'开发分支合并'release/some-release-0.1.1'功能分支
$ git merge --no-ff release/some-release-0.1.1

# 7. 推送'develop'开发分支至远程仓库
$ git push origin develop

# 8. 删除'release/some-release-0.1.1'发布分支
$ git branch -d release/some-release-0.1.1

# 9. 重新打标签
$ git tag -a v0.1.1 master

# 10. 提交所有 tag
$ git push --tags
  1. 使用 Git-flow 命令开发发布分支 - Release 分支流程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 1. 开始准备 release 版本 P.S.[创建了一个基于'develop'的热修复分支, 并切换到这个分支之下]
$ git flow release start 0.1.1

# 2. 完成 release 版本 P.S.[1. 合并'release/0.1.1'分支到'master';2. 给'master 打标签'v0.1.1';3. 合并'v0.1.1'分支到'develop';4. 删除本地'release/v0.1.1'分支; 5. 切换回'develop'分支]
$ git flow release finish 0.1.1
Summary of actions:
- Release branch 'release/0.1.1' has been merged into 'master'
- The release was tagged 'v0.1.1'
- Release tag 'v0.1.1' has been back-merged into 'develop'
- Release branch 'release/0.1.1' has been locally deleted
- You are now on branch 'develop'

# 3. 切换到'master'分支
$ git checkout master

# 4. 推送'master'分支至远程仓库
$ git push origin master

# 5. 切换到'develop'分支
$ git checkout develop

# 6. 推送'develop'分支至远程仓库
$ git push origin develop

Git 的分支工作流与 Pull Request

Pull request 是 github/bitbucket 给开发人员实现便利合作提供的一个 feature。他们提供一个用户友好的 web 界面在进代码之前来讨论这些变更。

简单说,Pull request 是一种为了开发人员通知 team member 他们已经完成了一个 feature 的机制。一旦他们的 feature branch ready 了,开发人员就通过他们的 github 帐号执行一个 pull request。这将使得每个相干人知晓这个事件,他们需要 review 这个 feature branch 的代码,并且需要决定是否 merge 到 master 分支上去。

但是 pull request 并不仅仅是一种 notification, 他也是一个专门用于讨论这些即将落地代码的细节的论坛。如果有任何问题或意见,同事们可以在 pull request 中提 comments,甚至直接在这个 Pull request 中修改要落地的代码。所有这些活动都由 pull request 来跟踪。

下面通过例子介绍:热修复分支 - Hotfix 分支 Git flow 工作流和 Pull Request

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 1. 'master'创建'hotfix'分支并发布'hotfix'分支到远程服务器
$ git flow hotfix start [hotfix version No.] [release version No.]
$ git flow hotfix publish [hotfix version No.]

# 2. 'developer'更新代码, 切换到'hotfix'分支
$ git pull
$ git checkout hotfix/[hotfix version No.]

# 3. 'developer'修复代码, 然后提交到远程仓库, 申请 pull request 从 hotfixbug-[hotfix version No.]/[bug name] 到 hotfix/[hotfix version No.]
$ git checkout –b hotfixbug-[hotfix version No.]/[bug name]
$ // todo fix bug
$ git push –u origin hotfixbug-[hotfix version No.]/[bug name]
$ // create pull request to hotfix/[hotfix version No.]

# 4. 'master'处理 merge 后, 测试人员跟进测试; 无误后, 申请 pull request 从 hotfix/[hotfix version No.] 到 master
$ // create pull request to master

# 5. 'master'merge to master. 针对项目维护者: git pull 和 git merge 是最常用的 merge Pull Requests 的方式, 在命令行下 merge 之后, PullRequest 也会相应地自动关闭; 或者在网站上点击同意合并
$ git flow hotfix finish --no-ff [hotfix version No.]

参考博文

[1]. 「译」浅谈 Gitflow
[2]. git-flow 备忘清单
[3]. 图解 Git


Git 在团队中的最佳实践系列


谢谢你长得那么好看,还打赏我!😘
0%