0%

git-flow 练习笔记

在我们团队开发中,必不可免会使用到版本控制。同时还需要一个统一的工作流程,创建新的功能、打补丁、正式版发布打tag等等,git-flow工作流就这些繁琐的东西简化了,它封装了git命令,将命令组合了起来,我们只需要几行代码就能解决这些繁琐的工作。正好工作也有好一段时间了,想将这方面的知识梳理一下。

git flow 有好几个版本,这里笔者演示使用的是git-flow-avh的版本。

初始化

首先我们先开始初始化仓库的工作流,我们在命令行使用git flow init

1
2
3
4
5
6
7
8
9
10
11
$ git flow init
flags:ERROR short flag required for (showcommands) on this platform
flags:ERROR short flag required for (local) on this platform
flags:ERROR short flag required for (global) on this platform
flags:ERROR short flag required for (system) on this platform
flags:ERROR short flag required for (file) on this platform
/usr/local/bin/gitflow-common: line 81: [: -eq: unary operator expected
/usr/local/bin/gitflow-common: line 81: [: -eq: unary operator expected
/usr/local/bin/gitflow-common: line 81: [: -eq: unary operator expected
No branches exist yet. Base branches must be created now.

命令行出现了警告,告诉我们还没有基础的分支。这是因为测试是全新的仓库作测试,这个我们姑且先不管它,接着引导会向我们确定需要初始化分支的名字,我们都采用默认即可。
直到询问Version tag prefix时,我们采用v作版本前缀,这其实也是很常见的一种习惯。

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
Branch name for production releases: [master]
/usr/local/bin/gitflow-common: line 81: [: -eq: unary operator expected

Branch name for "next release" development: [develop]
/usr/local/bin/gitflow-common: line 81: [: -eq: unary operator expected
/usr/local/bin/gitflow-common: line 81: [: -eq: unary operator expected
/usr/local/bin/gitflow-common: line 81: [: -eq: unary operator expected
/usr/local/bin/gitflow-common: line 81: [: -eq: unary operator expected
/usr/local/bin/gitflow-common: line 81: [: -eq: unary operator expected

How to name your supporting branch prefixes?
Feature branches? [feature/]
/usr/local/bin/gitflow-common: line 81: [: -eq: unary operator expected
Bugfix branches? [bugfix/]
/usr/local/bin/gitflow-common: line 81: [: -eq: unary operator expected
Release branches? [release/]
/usr/local/bin/gitflow-common: line 81: [: -eq: unary operator expected
Hotfix branches? [hotfix/]
/usr/local/bin/gitflow-common: line 81: [: -eq: unary operator expected
Support branches? [support/]
/usr/local/bin/gitflow-common: line 81: [: -eq: unary operator expected

Version tag prefix? [] v
/usr/local/bin/gitflow-common: line 81: [: -eq: unary operator expected
Hooks and filters directory? [/Users/anran/MyProject/git-flow-test/.git/hooks]
/usr/local/bin/gitflow-common: line 81: [: -eq: unary operator expected

随后我们使用git branch查看一下当前分支,我们会发现,git flow 创建了两条分支————主分支(master)和开发分支(develop),并自动切换到了 develop 上。

一般来说,我们常将 master 作为部署的分支,这个版本的产品防止稳定的代码和功能,作为产品的一个正式版部署。
正常情况下,我们不能直接在 master 分支上进行工作,而该是在 develop 开发环境下进行工作。
除此之外,develop 还是一个基础的分支,当我们开发新的功能时,我们会另开一个分支,在新的分支上进行功能开发,等功能开发完毕后再合并进来 develop 分支。

嘿,我们先创建一个README.md,在里面添加一些文字进去,再提交上去。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
➜  git-flow-test git:(develop) git branch
* develop
master
➜ git-flow-test git:(develop) touch README.md
➜ git-flow-test git:(develop) ✗ vim README.md
➜ git-flow-test git:(develop) ✗ git add .
➜ git-flow-test git:(develop) ✗ git status
On branch develop
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)

new file: README.md

➜ git-flow-test git:(develop) ✗ git commit -m "First commit"
[develop 61ec91a] First commit
1 file changed, 1 insertion(+)
create mode 100644 README.md

如果这时直接用push的话,git会提示你没有设定上游分支————别忘了现在我们在使用全新的测试仓库。

bash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
➜  git-flow-test git:(develop) git push
fatal: The current branch develop has no upstream branch.
To push the current branch and set the remote as upstream, use

git push --set-upstream origin develop

➜ git-flow-test git:(develop) git push --set-upstream origin develop
Counting objects: 5, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (5/5), 385 bytes | 385.00 KiB/s, done.
Total 5 (delta 0), reused 0 (delta 0)
To github.com:anran758/git-flow-test.git
* [new branch] develop -> develop
Branch 'develop' set up to track remote branch 'develop' from 'origin'.
➜ git-flow-test git:(develop)

功能分支

umm..现在假设我们现在碰到了一个需求,需要加一些功能,这时我们就需要开一个功能分支了,这时工作中常用的分支。那为啥都切到开发环境了还要单独开一个分支呢?这是避免产品调皮的说,“刚才那个功能只是我突发奇想,咱们不要了吧(诶嘿.jpg”。嗯,这时宰一个产品祭天事小,污染了全局的开发环境才事大,回退都不好回退(可能团队中其他人也在写一些功能上去或者修复了一些bug上去,回退意味着其他人也会收到影响)。

而单独开一个分支则没那么多破事需要烦恼,再不济就删除这个分支即可,不需要耗费额外的成本。

我们先看一下给flow都有啥,使用命令git flow -h会提示如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
➜  git-flow-test git:(develop) git flow -h
flags:ERROR short flag required for (showcommands) on this platform
usage: git flow <subcommand>

Available subcommands are:
init Initialize a new git repo with support for the branching model.
feature Manage your feature branches.
bugfix Manage your bugfix branches.
release Manage your release branches.
hotfix Manage your hotfix branches.
support Manage your support branches.
version Shows version information.
config Manage your git-flow configuration.
log Show log deviating from base branch.

Try 'git flow <subcommand> help' for details.

因为我们现在是想做一个新功能,feature 就是我们想要的命令。我们进一步查看详情:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
➜  git-flow-test git:(develop) git flow feature help
flags:ERROR short flag required for (showcommands) on this platform
usage: git flow feature [list]
or: git flow feature start
or: git flow feature finish
or: git flow feature publish
or: git flow feature track
or: git flow feature diff
or: git flow feature rebase
or: git flow feature checkout
or: git flow feature pull
or: git flow feature delete

Manage your feature branches.

For more specific help type the command followed by --help

我们使用git flow feature start再加上一个名字,这个名字代表着这个功能分支是做什么的。

1
2
3
4
5
6
7
8
9
10
11
12
13
➜  git-flow-test git:(develop) git flow feature start home
flags:ERROR short flag required for (showcommands) on this platform
/usr/local/bin/gitflow-common: line 81: [: -eq: unary operator expected
/usr/local/bin/gitflow-common: line 81: [: -eq: unary operator expected
Switched to a new branch 'feature/home'

Summary of actions:
- A new branch 'feature/home' was created, based on 'develop'
- You are now on branch 'feature/home'

Now, start committing on your feature. When done, use:

git flow feature finish home

这时我们创建了一个名为feature/home的新分支,并且切换到了新分支上。feature的前缀就是前面使用默认的功能分支的名字。
这个 feature 可以当成一个放置功能的文件夹。

随后我创建一个 HTML 文件,并在上面写了少许代码假装(雾)完成了这个新功能的开发。
使用git flow feature finish <name>完成本回合的开发。

1
2
3
4
5
6
7
8
9
10
➜  git-flow-test git:(feature/home) ✗ git flow finish home
Switched to branch 'develop'
Your branch is up to date with 'origin/develop'.
Already up to date.
Deleted branch feature/home (was 61ec91a).

Summary of actions:
- The feature branch 'feature/home' was merged into 'develop'
- Feature branch 'feature/home' has been locally deleted
- You are now on branch 'develop'

git flow 将分支合并后,会将feature/home分支删除。这时分支会切换到develop注意,这时候的代码还没有提交到远端!

1
2
3
4
5
6
7
8
9
10
11
12
13
➜  git-flow-test git:(develop) ✗ git add .
➜ git-flow-test git:(develop) ✗ git commit -m "添加新的功能"
[develop 9ca31f9] 添加新的功能
1 file changed, 12 insertions(+)
create mode 100644 index.html
➜ git-flow-test git:(develop) ✗ git push
Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 482 bytes | 482.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To github.com:anran758/git-flow-test.git
61ec91a..9ca31f9 develop -> develop

正式发布

好啦,当我们开发的差不多了,bug都修完并且都测试过了,这时就可以考虑部署一版了。这时我们可以使用git flow release start <version number>进入发布的状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
➜  git-flow-test git:(develop) ✗ git flow release start 1.0.0
Switched to a new branch 'release/1.0.0'

Summary of actions:
- A new branch 'release/1.0.0' was created, based on 'develop'
- You are now on branch 'release/1.0.0'

Follow-up actions:
- Bump the version number now!
- Start committing last-minute fixes in preparing your release
- When done, run:

git flow release finish '1.0.0'

git flow 基于develop创建了一个新的分支,同时切换到新分支release/1.0.0上了。

这时我们可以进入最后的准备啦~比如我们一般发布都需要写版本信息,说明这版本都做了什么?新加了哪些功能?修了哪些bug等信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
➜  git-flow-test git:(release/1.0.0) ✗ touch changelog.md
➜ git-flow-test git:(release/1.0.0) ✗ vim changelog.md

----

# item name

## v1.0.0 2018/04/23

* 基础功能完善
* 完成巴拉巴拉功能
~
~
~
"changelog.md" 6L, 83C

----

➜ git-flow-test git:(release/1.0.0) ✗ git add changelog.md
➜ git-flow-test git:(release/1.0.0) ✗ git commit -m "增加版本号信息"
[release/1.0.0 f8464d6] 修改版本号信息
1 file changed, 6 insertions(+)
create mode 100644 changelog.md

这时暂时先不用push,不过这里值得注意的是,一般来说,我们只有两个长期分支,一个 develop,另一个是 master分支。例如release 、feature等分支一般不会出现在远程的分支中。这是以为当我们做完这些工作流后,这些分支都会合并删除了。

等完成这些工作后,我们把发布流程结束,在命令行输入: git flow release finish 1.0.0。git flow将会做以下几个步骤:

  • pull代码,以确保本地分支的代码都是最新的版本。

  • 然后,release 的内容会被合并到 “master” 和 “develop” 两个分支中去,这样不仅产品代码为最新的版本,而且新的功能分支也将基于最新代码。
    这时命令行会进入vim编辑器里的合并信息页,默认会以Merge branch 'release/1.0.0'作为 commit
    信息提交。我们也可以自己输入一些信息进行描述。(vim编辑器状态下,输入a则进入编辑状态,使用:q为不保存信息退出编辑器,:wq为保存信息并退出vim)。

1
2
3
4
5
6
7
8
9
10
11
12
Merge branch 'release/1.0.0'


# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.
~
~
~
"~/MyProject/git-flow-test/.git/MERGE_MSG" 7L, 256C
  • 保存后又会进入另一个信息,这次这个是确定版本号信息。我们将v1.0.0前面的#去掉,让其作为tag,v是一开头初始化所用的前缀,而1.0.0则是我们这次发布的名称(版本号)。
1
2
3
4
5
6
7
8
#
# Write a message for tag:
# v1.0.0
# Lines starting with '#' will be ignored.
~
~
~
"~/MyProject/git-flow-test/.git/TAG_EDITMSG" 5L, 84C
  • 为便于识别和做历史参考,release 提交会被标记上这个 release 的名字。
  • 清理操作,版本分支会被删除,并且回到 “develop”。

hotfix

上线后,在进行测试时会可能会发现之前没有留意到的小bug,比如展示的数据调错了字段,当bug修复后,这时就可以使用git flow 里的hotfix,用来表示bug的修复。值得注意的是,hotfix与之前两个分支有些不同,hotfix是基于master主分支的修复,而前面两者是基于develop分支。

1
2
3
4
5
6
7
8
9
10
11
12
13
➜  git-flow-test git:(master) git flow hotfix start v1.0.1hotfix
Switched to a new branch 'hotfix/v1.0.1hotfix'

Summary of actions:
- A new branch 'hotfix/v1.0.1hotfix' was created, based on 'master'
- You are now on branch 'hotfix/v1.0.1hotfix'

Follow-up actions:
- Start committing your hot fixes
- Bump the version number now!
- When done, run:

git flow hotfix finish 'fixShoppingCart'

然后你会看到git flow会提示你:

  • 开始修复你bug
  • 修复bug也是需要影响版本号的
  • 完成上述工作后就可以结束这个补丁啦~
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
➜  git-flow-test git:(hotfix/v1.0.1hotfix) vim index.html
➜ git-flow-test git:(hotfix/v1.0.1hotfix) ✗ vim changelog.md
➜ git-flow-test git:(hotfix/v1.0.1hotfix) ✗ git add .
➜ git-flow-test git:(hotfix/v1.0.1hotfix) ✗ git commit -m "fixed shopping cart bug"
[hotfix/v1.0.1hotfix 1506b7f] fixed shopping cart bug
2 files changed, 4 insertions(+), 2 deletions(-)
➜ git-flow-test git:(hotfix/v1.0.1hotfix) git flow hotfix finish v1.0.1hotfix
Switched to branch 'master'
Merge made by the 'recursive' strategy.
changelog.md | 2 ++
index.html | 4 ++--
2 files changed, 4 insertions(+), 2 deletions(-)
Switched to branch 'develop'
Your branch is up to date with 'origin/develop'.
Merge made by the 'recursive' strategy.
changelog.md | 8 ++++++++
index.html | 4 ++--
2 files changed, 10 insertions(+), 2 deletions(-)
create mode 100644 changelog.md
Deleted branch hotfix/v1.0.1hotfix (was 1506b7f).

Summary of actions:
- Hotfix branch 'hotfix/v1.0.1hotfix' has been merged into 'master'
- The hotfix was tagged 'vv1.0.1hotfix'
- Hotfix tag 'vv1.0.1hotfix' has been back-merged into 'develop'
- Hotfix branch 'hotfix/v1.0.1hotfix' has been locally deleted
- You are now on branch 'develop'

我们使用git flow hotfix finish v1.0.1hotfix结束工作流后,跟之前那样会出现合并的信息,如果需要的话,就添加相应秒速信息,再保存退出即可。

这时会将修复的部分同时合并到masterdevelop分支上,同时会为这次hotfix打上 tag。

其他

bugfix,它也是修复bug分支。看到这里就会有同学会疑问了:“啥?又改bug,这和之前那个又有啥区别?”。

原来它与hotbug不同的是,它是基于develop分支的。事实上这一个工作流在笔者的日常开发中用的比较少,似乎有些gif flow 的模型中都没有这个工作流,不过我也没有深入的去考证~因为目前没有遇到碰到这个的场景,了解的同学不妨留言讨论分享一下。

除此之外还有一个support的功能,是想用来支持以前的版本产品,这是一个实验性的功能,不太建议使用这个。

如果你偏爱于可视化的git的话,如同 Sourcetree 之类的 Git GUI 也内置有git flow。

总结

git flow实际上就一连串命令的组合,我们也可以单个单个的输入命令达到同样的效果。虽说git flow统一了工作流程,但并不是适用于全部的场景。项目中只有一个人时却反而会显得有点繁琐了。我们应该根据实际项目去选择符合项目的工作流。

「请笔者喝杯奶茶鼓励一下」

欢迎关注我的其它发布渠道