Git Flow
什么是 Git
Git 是一个分布式版本控制系统,由大佬 Linux 之父 Linus 亲自编写的,默默流下了羡慕的泪水 😭。
版本控制系统 VCS
版本控制系统(Version Control System - VCS) 最基本的功能是版本控制。即在文件的修改历程中保留修改历史,让你可以方便地撤销之前对文件的修改操作:
- 中央式版本控制系统(Centralized VCS) - 都有一个单一的集中管理的服务器,保存所有文件的修订版本,而协同工作的人们都通过客户端连到这台服务器,取出最新的文件或者提交更新。缺点是中央服务器的单点故障可能导致无法提交更新,甚至可能丢失历史记录。
- 分布式版本控制系统(Distributed VCS) - 客户端并不只提取最新版本的文件快照,而是把代码仓库完整地镜像下来。这么一来,任何一处协同工作用的服务器发生故障,事后都可以用任何一个镜像出来的本地仓库恢复。因为每一次的克隆操作,实际上都是一次对代码仓库的完整备份。

Git vs SVN
SVN 作为 CVCS,Git 相比 SVN 的主要优点:
- 直接记录快照,而非差异比较 - Git 存储项目随时间改变的快照,效率更高;而 SVN 存储每个文件与初始版本的差异。
- 近乎所有操作都是本地执行 - Git 中的绝大多数操作都只需要访问本地文件和资源,所以速度更快,而且无需联网;而 SVN 处于断网状态时是无法提交更新的。
- 数据完整性 - Git 中所有数据在存储前都通过 SHA-1 散列计算校验和,然后以校验和来引用。实际上,Git 数据库中保存的信息都是以文件内容的哈希值来索引,而不是文件名,如 commit id。
- 更优的分支 - Git 中分支(branch)的创建实际上是创建了一个可以移动的新的指针,操作几乎能在瞬间完成,并且在不同分支之间的切换操作也是一样便捷;而 SVN 中的分支是一个完整的目录,且这个目录拥有完整的实际文件,占用空间大且低效。
Git Flow
Git 如此优秀的版本控制工具,给我们提供了极大的便利,但是在实际工作中,一个项目可能需要很多人维护,协同工作就成为了一个巨大的威胁。而且有可能我们只用到 Master 或者 Develop 少数的分支,并且提交历史混乱。基于上述情况,我们需要一个清晰的流程和规范,来更大程度上地享受 Git 带来的便利,这就是接下来要介绍的 Git Flow。
流程图
Git Flow 常用的分支:
| 分支 | 描述 |
|---|---|
| Production | 即 Master 分支,主要合并最近发布到生产环境的代码,并打上标签,此分支只能从其他分支合并,不能直接修改 |
| Develop | 主要开发分支,包含所有要发布到下一个 Release 的代码 |
| Feature | 主要是用来开发一个新功能,开发完成后合并到 Develop 分支,然后删除该特性分支 |
| Release | 当需要发布的时候,基于 Develop 分支创建一个 Release 分支,完成发布后将其合并到 Master 和 Develop 分支,然后删除该发布分支 |
| Hotfix | 当在 Master 分支发现新的 Bug 时候,需要创建一个 Hotfix 分支, 完成修复后将其合并回 Master 和 Develop 分支,所以 Hotfix 的改动会进入下一个 Release |

Git 中分支实际上是指向某个 commit 的指针。
Git 命令
流程我们知道了,那么如何去运用呢,一般情况下我们可以直接使用命令行,不妨来看看栗子:
# -------------------- feature ------------------------
# 创建 feature 分支并开发
gco -b smd-feature develop
# 完成 feature 分支,合并到 develop,并删除
gco develop && gl
grb develop smd-feature
gm smd-feature && gp # rebase 合并到 develop
gb -d smd-feature # 删除本地
# gp origin :smd-feature # 若推送过远端则删除远端分支
# -------------------- release ------------------------
# 创建 release 分支,准备发布
gco -b release-0.1.0 develop
# 完成 release,分别合并到 master 和 develop,然后删除打标签
gcm && gl
grb master release-0.1.0
gm release-0.1.0 && gp
gco develop && gl
grb develop release-0.1.0
gm release-0.1.0 && gp
gb -d release-0.1.0
git tag -a v0.1.0 master # 打标签
gp --tags
# -------------------- hotfix ------------------------
# 创建 hotfix 修复
gco -b hotfix-0.1.1 master
# 完成 hotfix 修复,分别合并到 master 和 develop,然后删除打标签
# 省略一万个字,同 release 操作
git tag -a v0.1.1 master
gp --tags
git flow 命令
我们可以看到,通过 Git 命令去实现工作流还是很繁琐的,很可能你会漏掉一些。因此我们可以借助一些工具,比如 Git flow script:
# 安装 git-flow
brew install git-flow
# 初始化
git flow init
# 开始 feature
git flow feature start smd-feature
# 发布 feature
git flow feature publish smd-feature
# 获取已发布的 feature
git flow feature pull origin smd-feature
# 完成 feature
git flow feature finish smd-feature
# 开始 release
git flow release start RELEASE [BASE]
# 发布 release
git flow release publish RELEASE
# 完成 release
git flow release finish RELEASE
# 开始 hotfix
git flow hotfix start VERSION [BASENAME]
# 发布 hotfix
git flow hotfix finish VERSION
上述发布(release)动作指的是 push 到远端
Sourcetree
我们还可以通过 GUI 来更便捷的去操作,可视化效果会更好,值得推荐的是 Sourcetree,我们来看看 gitflow 对应的操作图,我们只用点击对应的功能按键就可以实现上述一些功能:


.gitignore
通过 .gitignore 文件配置可忽略跟踪的文件,其格式规范如下:
- 所有空行或者以注释符号 # 开头的行都会被 Git 忽略。
- 可以使用标准的 glob模式 匹配。
- 匹配模式最后跟反斜杠 (/) 说明要忽略的是目录。
- 要忽略指定模式以外的文件或目录,可以在模式前加上惊叹号 (!) 取反。
glob模式 是指 shell 所使用的简化了的正则表达式,比如:
- 星号 (*) - 匹配零个或多个任意字符
- [abc] - 匹配任何一个列在方括号中的字符
- 问号 (?) - 只匹配一个任意字符
- [0-9] - 表示匹配所有 0 到 9 的数字
以下是 .gitignore 文件示例,各个语言环境下的标准可参考这里 👈👈👈
# 此为注释 – 将被 Git 忽略
# 忽略所有 .a 结尾的文件
*.a
# 但 lib.a 除外
!lib.a
# 仅仅忽略项目根目录下的 TODO 文件,不包括 subdir/TODO
/TODO
# 忽略 build/ 目录下的所有文件
build/
# 会忽略 doc/notes.txt 但不包括 doc/server/arch.txt
doc/*.txt
# 忽略 doc/ 目录下所有扩展名为 txt 的文件
doc/**/*.txt
如果某个文件可以放开,直接在 .gitignore 中去除对应配置并重新追踪即可;如果某个文件在忽略前已经被追踪,直接在 .gitignore 中添加是无效的。需要去除文件缓存或者物理删除再提交:
git rm -r --cached filename
.gitkeep
一般而言,git 不会去追踪空的文件目录,如果需要追踪的话,需要在里面创建一个文件,无论这个文件是什么,内容如何,名字是什么。因此社区约定了 .gitkeep 这个文件名,其实就是一个占位符,当然我们也可以取名 .nofile、.youcanseenothing 等等。
Git Hooks
Git 钩子(hooks)都被存储在 Git 目录下的 hooks 子目录中,即大部分项目中的 .git/hooks。在 Git 1.6 版本之后,这些样本名都是以.sample 结尾,因此必须重新命名。Git 提供两组钩子:客户端和服务端。
这里直接使用 husky,安装后,.git/hooks 目录里面的钩子都会被 husky 替换掉。在 package.json 里进行配置即可:
// 版本 0.14
"scripts": {
"postcommit": "echo hi snow",
"precommit": "echo hi tate"
}
// 版本 0.14 之后
// 可直接运行 ./node_modules/.bin/husky-upgrade 进行迁移
{
"husky": {
"hooks": {
"pre-commit": "echo hi tate",
"post-commit": "echo hi snow",
}
}
}
git commit -a -m 'add husky'
# husky > pre-commit (node v9.3.0)
# im tate
# husky > post-commit (node v9.3.0)
# im snow
# [master 8a1b6a3] add husky
参考链接
- Git
- Git 教程 By 廖雪峰
- A successful Git branching model By Vincent Driessen
- Git 在团队中的最佳实践–如何正确使用 Git Flow By wangdeshui