结合git flow,使用gitlab作为远端仓库管理,在实际的项目中是一种可行的方式,而且这种方式对与复杂大型的项目有较好的适应方式。
git flow源于Vincent Driessen在2010年提出的一个分支模型:
git flow中有两个长期的分支,一直不会被删除,这两个分支是develop和master。
分支 | 生命期 | 作用说明 |
---|---|---|
master | 长期 | 用于保持和生产环境一致或者半步先于生产环境,主要目的用于保证生产环境的实时可用状态 |
develop | 长期 | 开发的集成分支,主要目的用于显示最新的开发状况 |
master 分支时常保持着软件可以正常运行的状态,一般不允许开发者直接对master 分支的代码进行修改和提交。结合gitlab的具体方式,可以将改分支设定为protect方式。
master分支专人管理,结合gitlab的权限管理,设定团队负责发布的人具有owner或者master的权限,其余人禁止直接对此分支进行操作。
master分支主要在以下场景中会用到:
当代码规模和团队规模到了一定程度之后,如果缺乏有效的管理,加之多团队的开发,尚未发布的功能,临时对应的bug,甚至还会有一些手动修改暂时未归入版本管理的文件,这些混杂在一起会变得非常的复杂。所以在问题发生时,想清楚的知道bug发生的生产化境所对应的源码基线都是一件困难的事情,此分支与上线功能息息相关,必须严格管理。
特性分支开发完毕,完成测试,确认此分支内容可以进行发布之后,便可与master分支合并,发布时一般会附加版本编号。
紧急bug修正之后,需要立即体现在master分支上,不然下次发布依然会有很多问题
建议在项目中添加自动化测试环节,使用gitlab的webhook设定,在merge时根据项目需要自动运行自动化测试验收,如果不通过及时报警,此自动化测试即使是很少的覆盖率,也能防范大部分人为因素导致的问题,比如不小心将一个编译都没有通过的版本推到了master上,即使专人负责,但是专人并不一定对所有的技术和项目功能以及实时状态都有全面的掌控,另外所有的问题都需要人去检查和确认,一张会无限增长的checklist从此产生,最终会形成一个几千行甚至更多的一个虽都不会去看的敷衍了事的检查环节,此环节在很多项目实践中已经得到证实:只在事后检讨的时候有用,检讨之后这张checklist会变得更长。
根据项目的模块进行拆分,不同的模块不同的团队负责,或者根据特性进行开发,不同的特性不同的团队负责,这些分支开发完毕时需要合并到develop分支上,以保证develop分支具有最新的功能。
紧急bug修正之后,需要立即体现在master分支上,但是同时需要在develop分支上进行反应,为何不直接在develop分支上进行管理,有很多因素需要考虑,比如新的功能虽然开发完毕了,但是由于其他制约的因素,发布的时期尚未确定,不能将这些已经完成开发和测试的内容发布到master分支上,简单来说此模型的出发点在于master分支用于和生产环境直接关联,之所以多一条分支就是为了管理各种复杂的难以掌控的项目实际需求的。紧急bug修正之后,master和develop分支都需要进行更新,前者保证下次发布不会将此紧急修正的内容覆盖,后者保证通过下次通过测试的内容合并到master上时不会覆盖此内容或者尽可能的减少merge操作。
develop分支是开发过程中代码中心分支,与master 分支一样,这个分支也是非常重要的分支,这个分支的合并操作可能每个人都会参与,如果做专人管理的话,基本上所有的开发者都需要参与。所以,合并之前需要建立基础的原则,比如java的项目最好做到如下内容才合并到本分支
本地编译通过
本地本次修改内容没有新的sonarqube高级别的defect对应
本地单体测试通过
手工或者自动化验收的测试通过
develop分支进行传统的每日构建甚至实时构建,结合不断完善的自动化测试,以可以接受的成本和代价保证开发的流水线不会断开。
设立时限原则:develop分支一旦发生构建或者关联的自动化测试出现问题,结合工具第一时间定位到对应的负责人进行回滚或者紧急修正,根据项目集成情况进行设立时限,比如平均每日由各个临时分支提交的功能为4次,则可设立时限最长不超过2小时,如果超过2小时无法对应,则意味着下次会有人在这个错误的版本上进行再一次的提交,错上加错是最需要避免的,发现问题在第一时间解决,超过时限,立即止损回滚。
相比于长期存在的分支,git flow的模型中还有三种临时性的分支
分支类型 | 说明 | 是否可为多条 |
---|---|---|
Feature分支 | 特性分支 | 可为多条 |
Hotfix分支 | bug对应分支 | 可为多条 |
Release分支 | release实施分支 | 可为多条 |
特性分支有时也被称为Topic分支,一般是用来开发新的特性,而其关联的发布可能近在眼前,也有可能需要很长一段时间,特性分支最终会被合并到develop分支或者最终会被丢弃。
丢弃特性分支开发的内容在敏捷开发中并不罕见,尤其是当项目需要不断地试验的阶段。
根据DevOps的调查显示,Trunc-based开发方式是主流推动的开发方式,但是由于项目的复杂性和实际推行时候各种制约因素的存在,
多条分支长时间的并行还是很难避免的,特性分支开发的时候在git flow模型中一般遵循如下步骤:
步骤 | 内容 | git 命令 |
---|---|---|
Step 1 | 以develop分支为基础创建特性分支 | git checkout -b 特性分支名称 develop |
Step 2 | 进行特性内容开发直至可以提交 | |
Step 3 | 特性分支开发完成后切换至develop分支 | git checkout develop |
Step 4 | 合并特性分支开发内容到develop分支 | git merge –no-ff 特性分支名称 |
Step 5 | 删除特性分支 | git branch -d 特性分支名称 |
Step 6 | push修改内容到远端仓库保存 | git push origin develop |
特性分支的使用注意事项如下:
注意事项 | 详细说明 |
---|---|
源分支 | 特性分支需要以develop分支为源分支 |
目标分支 | 特性分支的合并目标分支为develop分支,此模型中只能合并回develop分支 |
分支命名 | 除去master/develop/hotfix-/release-命名的所有分支 |
特性分支合并或者其他的分支合并,尽可能不使用fast forward的方式,以方便回滚和状态确认。
特性分支在git flow中仍然是临时性分支,使用之后请删除此分支,同时删除远程仓库上的该分支。另外,分支的增多以为着可能的沟通/合并/冲突等的增加,而这些正是精益开发中
所要规避的“waste”,不用即删,因为在实践中我们已经利用了git的非fast forward的方式,所以特性分支开发的信息已经完整地在develop分支保存,删除不会引起问题追踪上的问题。
Release分支基于develop分支为基础进行创建,主要用于版本的发布,主要用于保证最后一步的安全和顺畅,为发布所需要的各种准备以及手工操作,甚至小规模的bug对应都可以在此分支上完成。而当Release分支上的一切做完之后,标志着最新develop分支的功能已经发布到了master,同时为下一次发布的功能特性的接收已经开始。
特性分支或者其他分支合并到develop开发主分支的策略需要项目根据情况自行创建,最主要的原则之一在于尽量避免由于发布时期的不同导致频繁的分支合并/版本挑选等手工作业的发生。
比如发布计划明明是最后,但是在项目已开始的时候就合并进了主分支,这样会导致后续每次发布的时候都需要将此内容挑选出去,虽然使用gitlab的rebase+cherry pick等功能可以实现这种要求,
但是单纯在提交的规范上进行要求则可以避免这种无用的浪费的发生。
Release分支主要目的是用于大型项目中各个特性分支开发完毕之后,定义了一个准备就绪到工作完成的中间阶段,一般会和项目的管理工作结合进行,比如进行发布的申请和批准,结果确认和审核,
由于不同的开发流程不仅需要考虑到技术本身,还要考虑到各个公司实际的流程规范/audit等等,以保证release能够正常进行。虽然可以在此分支上进行小量的修改,但是大规模的功能修改请尽可能地规避。
Release分支在使用时候一般遵循如下步骤:
步骤 | 内容 | git 命令 |
---|---|---|
Step 1 | 以develop分支为基础创建release分支 | git checkout -b release-版本号 develop |
Step 2 | 做Release准备或者小的bug对应,然后进行提交 | git commit -a -m “release相关信息” |
Step 3 | 切换至master分支 | git checkout master |
Step 4 | 合并Release分支内容到master分支 | git merge –no-ff release-版本号 |
Step 5 | 设定tag | git tag -a 版本号 -m “release的tag信息” |
Step 6 | 切换至develop分支 | git checkout develop |
Step 7 | 合并Release分支内容到develop分支 | git merge –no-ff release-版本号 |
Step 8 | 删除release分支 | git branch -d release-版本号 |
Step 9 | 推送develop分支到远程仓库 | git push origin develop |
Step 10 | 切换至master分支并推送master分支到远程仓库 | git checkout master; git push origin master |
Step 11 | 推送tag信息到远程分支 | git push origin 版本号 |
Release分支的使用注意事项如下:
注意事项 | 详细说明 |
---|---|
源分支 | release分支需要以develop分支为源分支 |
目标分支 | 特性分支的合并目标分支为develop分支和master,在此分支上的诸如小的bug修正必须同时反映到develop分支和master分支,不然就会给下次发布留下隐患 |
分支命名 | release-* |
为了避免提交或者tag信息被恶意修改,可以在使用签名技术实现这一保障。签名使得操作具有了不可抵赖性和无法篡改性两种保证。而在git中只是需要加入-u或者-s选项即可简单实现。
hotfix分支与release分支非常相像,都牵扯到向生产环境ready的master进行版本的更新。但是不同的是hotfix往往是因为生产环境上出现了非常紧急的问题对应,需要立即对应,而项目的特性开发等又不想受到影响而中断,这时就可以依据master生成一个新的hotfix的分支,在此分支上进行bug的对应,既不影响develop主开发分支,又能保证到生产环境紧急问题的及时对应,而对应完毕之后同时向develop主开发分支进行同步跟新即可。
诸如hotfix和release上的对应需要向git flow的两条主线同时进行更新,如果一旦忘记其中一条,势必会引起不必要的后续问题,在流程规范或者工具的自动化里面建立增加对此操作执行的确认。
Hotfix分支在使用时候一般遵循如下步骤:
步骤 | 内容 | git 命令 |
---|---|---|
Step 1 | 以master分支为基础创建hotfix分支 | git checkout -b hotfix-版本号 master |
Step 2 | 进行bug对应,然后进行提交 | git commit -a -m “hotfix相关信息” |
Step 3 | 切换至master分支 | git checkout master |
Step 4 | 合并hotfix分支内容到master分支 | git merge –no-ff hotfix-版本号 |
Step 5 | 设定tag | git tag -a 版本号 -m “hotfix的tag信息” |
Step 6 | 切换至develop分支 | git checkout develop |
Step 7 | 合并hotfix分支内容到develop分支 | git merge –no-ff hotfix-版本号 |
Step 8 | 删除hotfix分支 | git branch -d hotfix-版本号 |
Step 9 | 推送develop分支到远程仓库 | git push origin develop |
Step 10 | 切换至master分支并推送master分支到远程仓库 | git checkout master; git push origin master |
Step 11 | 推送tag信息到远程分支 | git push origin 版本号 |
hotfix分支的使用注意事项如下:
注意事项 | 详细说明 |
---|---|
源分支 | hotfix分支需要以master分支为源分支 |
目标分支 | 特性分支的合并目标分支为develop分支和master,修正必须同时反映到develop分支和master分支,不然就会给下次发布留下隐患 |
分支命名 | hotfix-* |
接下来我们使用gitlab10.4.2以及git1.8.3.1来模拟一下git flow开发的流程。
首先我们使用gitlab的restapi创建一个项目,当然也可以直接在gitlab上进行图形界面操作,具体命令如下,请根据自己的gitlab的URL和token进行修改, 另外jq命令如果没有可以不使用,对结果不产生影响,仅仅对结果的显示格式进行整形而已
curl –request POST –header “PRIVATE-TOKEN: sqiSUhn3tHYXe8nSGRDi” –data “name=gitflowmodel” “http://127.0.0.1:32001/api/v4/projects” |jq .
[root@devops ~]# curl --request POST --header "PRIVATE-TOKEN: sqiSUhn3tHYXe8nSGRDi" --data "name=gitflowmodel" "http://127.0.0.1:32001/api/v4/projects" |jq .
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 1907 100 1890 100 17 1711 15 0:00:01 0:00:01 --:--:-- 1711
{
"id": 2,
"description": null,
"name": "gitflowmodel",
"name_with_namespace": "Administrator / gitflowmodel",
"path": "gitflowmodel",
"path_with_namespace": "root/gitflowmodel",
"created_at": "2018-02-04T14:11:10.055Z",
"default_branch": null,
"tag_list": [],
"ssh_url_to_repo": "git@3ff5a6afdc80:root/gitflowmodel.git",
"http_url_to_repo": "http://3ff5a6afdc80/root/gitflowmodel.git",
"web_url": "http://3ff5a6afdc80/root/gitflowmodel",
"avatar_url": null,
"star_count": 0,
"forks_count": 0,
"last_activity_at": "2018-02-04T14:11:10.055Z",
"_links": {
"self": "http://3ff5a6afdc80/api/v4/projects/2",
"issues": "http://3ff5a6afdc80/api/v4/projects/2/issues",
"merge_requests": "http://3ff5a6afdc80/api/v4/projects/2/merge_requests",
"repo_branches": "http://3ff5a6afdc80/api/v4/projects/2/repository/branches",
"labels": "http://3ff5a6afdc80/api/v4/projects/2/labels",
"events": "http://3ff5a6afdc80/api/v4/projects/2/events",
"members": "http://3ff5a6afdc80/api/v4/projects/2/members"
},
"archived": false,
"visibility": "private",
"owner": {
"id": 1,
"name": "Administrator",
"username": "root",
"state": "active",
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
"web_url": "http://3ff5a6afdc80/root"
},
"resolve_outdated_diff_discussions": false,
"container_registry_enabled": true,
"issues_enabled": true,
"merge_requests_enabled": true,
"wiki_enabled": true,
"jobs_enabled": true,
"snippets_enabled": true,
"shared_runners_enabled": true,
"lfs_enabled": true,
"creator_id": 1,
"namespace": {
"id": 1,
"name": "root",
"path": "root",
"kind": "user",
"full_path": "root",
"parent_id": null
},
"import_status": "none",
"import_error": null,
"open_issues_count": 0,
"runners_token": "iCwH41nomRPp-nwF4xoP",
"public_jobs": true,
"ci_config_path": null,
"shared_with_groups": [],
"only_allow_merge_if_pipeline_succeeds": false,
"request_access_enabled": false,
"only_allow_merge_if_all_discussions_are_resolved": false,
"printing_merge_request_link_enabled": true
}
[root@devops ~]#
这样我们就创建了一个名为gitflowmodel的gitlab项目了。
git clone远程仓库内容,进行结果确认
[root@devops ~]# git clone http://192.168.163.154:32001/root/gitflowmodel.git
Cloning into 'gitflowmodel'...
Username for 'http://192.168.163.154:32001': root
Password for 'http://[email protected]:32001':
warning: You appear to have cloned an empty repository.
[root@devops ~]# cd gitflowmodel/
[root@devops gitflowmodel]# git branch
[root@devops gitflowmodel]# git remote -v
origin http://192.168.163.154:32001/root/gitflowmodel.git (fetch)
origin http://192.168.163.154:32001/root/gitflowmodel.git (push)
[root@devops gitflowmodel]#
对项目进行初期化,创建master分支,在master分支上添加一个文件C1,并将此文件推送到远端仓库。
[root@devops gitflowmodel]# touch C1
[root@devops gitflowmodel]# git add C1; git commit -m"add C1"
[master (root-commit) 858d807] add C1
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 C1
[root@devops gitflowmodel]# git push origin master
Username for 'http://192.168.163.154:32001': root
Password for 'http://[email protected]:32001':
Counting objects: 3, done.
Writing objects: 100% (3/3), 199 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To http://192.168.163.154:32001/root/gitflowmodel.git
* [new branch] master -> master
[root@devops gitflowmodel]#
在目前master的状态下创建develop分支,添加一个文件C2,并将此文件推送到远端仓库。
[root@devops gitflowmodel]# git checkout -b develop master
Switched to a new branch 'develop'
[root@devops gitflowmodel]# ls
C1
[root@devops gitflowmodel]# touch C2; git add C2; git commit -m "add C2";
[develop e9aff8a] add C2
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 C2
[root@devops gitflowmodel]# git push origin develop
Username for 'http://192.168.163.154:32001': root
Password for 'http://[email protected]:32001':
Counting objects: 3, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (2/2), 225 bytes | 0 bytes/s, done.
Total 2 (delta 0), reused 0 (delta 0)
remote:
remote: To create a merge request for develop, visit:
remote: http://3ff5a6afdc80/root/gitflowmodel/merge_requests/new?merge_request%5Bsource_branch%5D=develop
remote:
To http://192.168.163.154:32001/root/gitflowmodel.git
* [new branch] develop -> develop
[root@devops gitflowmodel]#
这样两条长期分支master和develop已经就绪,接下来我们开始模拟实际上的分支开发/bug对应/release等临时分支操作。
步骤 | 内容 | git 命令 |
---|---|---|
Step 1 | 以develop分支为基础创建特性分支 | git checkout -b 特性分支名称 develop |
[root@devops gitflowmodel]# git branch
* develop
master
[root@devops gitflowmodel]#
[root@devops gitflowmodel]#
[root@devops gitflowmodel]# git checkout -b feature_F1001 develop
Switched to a new branch 'feature_F1001'
[root@devops gitflowmodel]#
步骤 | 内容 | git 命令 |
---|---|---|
Step 2 | 进行特性内容开发直至可以提交 |
[root@devops gitflowmodel]# touch C3; git add C3; git commit -m "add C3";
[feature_F1001 fa40dce] add C3
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 C3
[root@devops gitflowmodel]#
步骤 | 内容 | git 命令 |
---|---|---|
Step 3 | 特性分支开发完成后切换至develop分支 | git checkout develop |
[root@devops gitflowmodel]# git checkout develop
Switched to branch 'develop'
[root@devops gitflowmodel]# ls
C1 C2
[root@devops gitflowmodel]#
步骤 | 内容 | git 命令 |
---|---|---|
Step 4 | 合并特性分支开发内容到develop分支 | git merge –no-ff 特性分支名称 |
[root@devops gitflowmodel]# git merge --no-ff feature_F1001
Merge made by the 'recursive' strategy.
C3 | 0
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 C3
[root@devops gitflowmodel]#
步骤 | 内容 | git 命令 |
---|---|---|
Step 5 | 删除特性分支 | git branch -d 特性分支名称 |
[root@devops gitflowmodel]# git branch
* develop
feature_F1001
master
[root@devops gitflowmodel]#
[root@devops gitflowmodel]# git branch -d feature_F1001
Deleted branch feature_F1001 (was fa40dce).
[root@devops gitflowmodel]#
[root@devops gitflowmodel]# git branch
* develop
master
[root@devops gitflowmodel]#
步骤 | 内容 | git 命令 |
---|---|---|
Step 6 | push修改内容到远端仓库保存 | git push origin develop |
[root@devops gitflowmodel]# git branch
* develop
master
[root@devops gitflowmodel]# ls
C1 C2 C3
[root@devops gitflowmodel]# git push origin develop
Username for 'http://192.168.163.154:32001': root
Password for 'http://[email protected]:32001':
Counting objects: 4, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 331 bytes | 0 bytes/s, done.
Total 3 (delta 1), reused 0 (delta 0)
remote:
remote: To create a merge request for develop, visit:
remote: http://3ff5a6afdc80/root/gitflowmodel/merge_requests/new?merge_request%5Bsource_branch%5D=develop
remote:
To http://192.168.163.154:32001/root/gitflowmodel.git
e9aff8a..eb06c4a develop -> develop
[root@devops gitflowmodel]#
此时git仓库的状态
[root@devops gitflowmodel]# git log --graph --pretty=oneline
* eb06c4ad2a9bd1f70d1ec3135f7b8bdc8703f41f Merge branch 'feature_F1001' into develop
|\
| * fa40dce00a8878824641c281bd91e10749e8cc86 add C3
|/
* e9aff8adf4b6344c5d7f59155134ef2e579f1e32 add C2
* 858d8070c8176c42e35f453a3394e4ff1bdc7e94 add C1
[root@devops gitflowmodel]#
步骤 | 内容 | git 命令 |
---|---|---|
Step 1 | 以develop分支为基础创建release分支 | git checkout -b release-版本号 develop |
root@devops gitflowmodel]# git branch
* develop
master
[root@devops gitflowmodel]# ls
C1 C2 C3
[root@devops gitflowmodel]# git checkout -b release-0.1 develop
Switched to a new branch 'release-0.1'
[root@devops gitflowmodel]#
步骤 | 内容 | git 命令 |
---|---|---|
Step 2 | 做Release准备或者小的bug对应,然后进行提交 | git commit -a -m “release相关信息” |
[root@devops gitflowmodel]# touch C4; git add C4; git commit -m "add C4";
[release-0.1 fcca679] add C4
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 C4
[root@devops gitflowmodel]#
步骤 | 内容 | git 命令 |
---|---|---|
Step 3 | 切换至master分支 | git checkout master |
[root@devops gitflowmodel]# git checkout master
Switched to branch 'master'
[root@devops gitflowmodel]#
步骤 | 内容 | git 命令 |
---|---|---|
Step 4 | 合并Release分支内容到master分支 | git merge –no-ff release-版本号 |
[root@devops gitflowmodel]# git merge --no-ff release-0.1
Merge made by the 'recursive' strategy.
C2 | 0
C3 | 0
C4 | 0
3 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 C2
create mode 100644 C3
create mode 100644 C4
[root@devops gitflowmodel]# ls
C1 C2 C3 C4
[root@devops gitflowmodel]#
步骤 | 内容 | git 命令 |
---|---|---|
Step 5 | 设定tag | git tag -a 版本号 -m “release的tag信息” |
[root@devops gitflowmodel]# git tag -a 0.1
[root@devops gitflowmodel]#
步骤 | 内容 | git 命令 |
---|---|---|
Step 6 | 切换至develop分支 | git checkout develop |
[root@devops gitflowmodel]# git checkout develop
Switched to branch 'develop'
[root@devops gitflowmodel]#
步骤 | 内容 | git 命令 |
---|---|---|
Step 7 | 合并Release分支内容到develop分支 | git merge –no-ff release-版本号 |
[root@devops gitflowmodel]# git merge --no-ff release-0.1
Merge made by the 'recursive' strategy.
C4 | 0
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 C4
[root@devops gitflowmodel]#
步骤 | 内容 | git 命令 |
---|---|---|
Step 8 | 删除release分支 | git branch -d release-版本号 |
[root@devops gitflowmodel]# git branch -d release-0.1
Deleted branch release-0.1 (was fcca679).
[root@devops gitflowmodel]#
步骤 | 内容 | git 命令 |
---|---|---|
Step 9 | 推送develop分支到远程仓库 | git push origin develop |
[root@devops gitflowmodel]# git branch
* develop
master
[root@devops gitflowmodel]# git push origin develop
Username for 'http://192.168.163.154:32001': root
Password for 'http://[email protected]:32001':
Counting objects: 4, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 339 bytes | 0 bytes/s, done.
Total 3 (delta 2), reused 0 (delta 0)
remote:
remote: To create a merge request for develop, visit:
remote: http://3ff5a6afdc80/root/gitflowmodel/merge_requests/new?merge_request%5Bsource_branch%5D=develop
remote:
To http://192.168.163.154:32001/root/gitflowmodel.git
eb06c4a..ff52200 develop -> develop
[root@devops gitflowmodel]#
步骤 | 内容 | git 命令 |
---|---|---|
Step 10 | 切换至master分支并推送master分支到远程仓库 | git checkout master; git push origin master |
[root@devops gitflowmodel]# git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 5 commits.
(use "git push" to publish your local commits)
[root@devops gitflowmodel]# git push origin master
Username for 'http://192.168.163.154:32001': root
Password for 'http://[email protected]:32001':
fatal: Authentication failed for 'http://192.168.163.154:32001/root/gitflowmodel.git/'
[root@devops gitflowmodel]#
[root@devops gitflowmodel]# git push origin master
Username for 'http://192.168.163.154:32001': root
Password for 'http://[email protected]:32001':
Counting objects: 1, done.
Writing objects: 100% (1/1), 223 bytes | 0 bytes/s, done.
Total 1 (delta 0), reused 0 (delta 0)
To http://192.168.163.154:32001/root/gitflowmodel.git
858d807..1ad3d55 master -> master
[root@devops gitflowmodel]#
步骤 | 内容 | git 命令 |
---|---|---|
Step 11 | 推送tag信息到远程分支 | git push origin 版本号 |
[root@devops gitflowmodel]# git push origin 0.1
Username for 'http://192.168.163.154:32001': root
Password for 'http://[email protected]:32001':
Counting objects: 1, done.
Writing objects: 100% (1/1), 152 bytes | 0 bytes/s, done.
Total 1 (delta 0), reused 0 (delta 0)
To http://192.168.163.154:32001/root/gitflowmodel.git
* [new tag] 0.1 -> 0.1
[root@devops gitflowmodel]#
确认分支状态
[root@devops gitflowmodel]# git log --graph --pretty=oneline
* 1ad3d55b2b35220d30f00be7da0c82d385aeb48d Merge branch 'release-0.1'
|\
| * fcca679ee89ad9e2ed90e7b319ba78d10cd22dac add C4
| * eb06c4ad2a9bd1f70d1ec3135f7b8bdc8703f41f Merge branch 'feature_F1001' into develop
| |\
| | * fa40dce00a8878824641c281bd91e10749e8cc86 add C3
| |/
| * e9aff8adf4b6344c5d7f59155134ef2e579f1e32 add C2
|/
* 858d8070c8176c42e35f453a3394e4ff1bdc7e94 add C1
[root@devops gitflowmodel]#
[root@devops gitflowmodel]# git branch
develop
* master
[root@devops gitflowmodel]#
[root@devops gitflowmodel]# git checkout develop
Switched to branch 'develop'
[root@devops gitflowmodel]# git log --graph --pretty=oneline
* ff52200742dc3515c85d41e206b4b7c5208881c2 Merge branch 'release-0.1' into develop
|\
| * fcca679ee89ad9e2ed90e7b319ba78d10cd22dac add C4
|/
* eb06c4ad2a9bd1f70d1ec3135f7b8bdc8703f41f Merge branch 'feature_F1001' into develop
|\
| * fa40dce00a8878824641c281bd91e10749e8cc86 add C3
|/
* e9aff8adf4b6344c5d7f59155134ef2e579f1e32 add C2
* 858d8070c8176c42e35f453a3394e4ff1bdc7e94 add C1
[root@devops gitflowmodel]#
步骤 | 内容 | git 命令 |
---|---|---|
Step 1 | 以master分支为基础创建hotfix分支 | git checkout -b hotfix-版本号 master |
[root@devops gitflowmodel]# git checkout -b hotfix-0.1.1 master
Switched to a new branch 'hotfix-0.1.1'
[root@devops gitflowmodel]#
[root@devops gitflowmodel]# git branch
develop
* hotfix-0.1.1
master
[root@devops gitflowmodel]#
步骤 | 内容 | git 命令 |
---|---|---|
Step 2 | 进行bug对应,然后进行提交 | git commit -a -m “hotfix相关信息” |
[root@devops gitflowmodel]# touch C5; git add C5; git commit -m "add C5";
[hotfix-0.1.1 7190442] add C5
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 C5
[root@devops gitflowmodel]#
步骤 | 内容 | git 命令 |
---|---|---|
Step 3 | 切换至master分支 | git checkout master |
[root@devops gitflowmodel]# git checkout master
Switched to branch 'master'
[root@devops gitflowmodel]#
步骤 | 内容 | git 命令 |
---|---|---|
Step 4 | 合并hotfix分支内容到master分支 | git merge –no-ff hotfix-版本号 |
[root@devops gitflowmodel]# git merge --no-ff hotfix-0.1.1
Merge made by the 'recursive' strategy.
C5 | 0
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 C5
[root@devops gitflowmodel]#
步骤 | 内容 | git 命令 |
---|---|---|
Step 5 | 设定tag | git tag -a 版本号 -m “hotfix的tag信息” |
[root@devops gitflowmodel]# git tag -a 0.1.1 -m "hotfix for 0.1.1"
[root@devops gitflowmodel]#
步骤 | 内容 | git 命令 |
---|---|---|
Step 6 | 切换至develop分支 | git checkout develop |
root@devops gitflowmodel]# git checkout develop
Switched to branch 'develop'
[root@devops gitflowmodel]#
[root@devops gitflowmodel]# git branch
* develop
hotfix-0.1.1
master
[root@devops gitflowmodel]#
步骤 | 内容 | git 命令 |
---|---|---|
Step 7 | 合并hotfix分支内容到develop分支 | git merge –no-ff hotfix-版本号 |
[root@devops gitflowmodel]# git merge --no-ff hotfix-0.1.1
Merge made by the 'recursive' strategy.
C5 | 0
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 C5
[root@devops gitflowmodel]#
步骤 | 内容 | git 命令 |
---|---|---|
Step 8 | 删除hotfix分支 | git branch -d hotfix-版本号 |
[root@devops gitflowmodel]# git branch -d hotfix-0.1.1
Deleted branch hotfix-0.1.1 (was 7190442).
[root@devops gitflowmodel]#
步骤 | 内容 | git 命令 |
---|---|---|
Step 9 | 推送develop分支到远程仓库 | git push origin develop |
[root@devops gitflowmodel]# git push origin develop
Username for 'http://192.168.163.154:32001': root
Password for 'http://[email protected]:32001':
Counting objects: 4, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 382 bytes | 0 bytes/s, done.
Total 3 (delta 2), reused 0 (delta 0)
remote:
remote: To create a merge request for develop, visit:
remote: http://3ff5a6afdc80/root/gitflowmodel/merge_requests/new?merge_request%5Bsource_branch%5D=develop
remote:
To http://192.168.163.154:32001/root/gitflowmodel.git
ff52200..e4b3be8 develop -> develop
[root@devops gitflowmodel]#
步骤 | 内容 | git 命令 |
---|---|---|
Step 10 | 切换至master分支并推送master分支到远程仓库 | git checkout master; git push origin master |
[root@devops gitflowmodel]# git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 2 commits.
(use "git push" to publish your local commits)
[root@devops gitflowmodel]# git push origin master
Username for 'http://192.168.163.154:32001': root
Password for 'http://[email protected]:32001':
Counting objects: 1, done.
Writing objects: 100% (1/1), 223 bytes | 0 bytes/s, done.
Total 1 (delta 0), reused 0 (delta 0)
To http://192.168.163.154:32001/root/gitflowmodel.git
1ad3d55..b843ef1 master -> master
[root@devops gitflowmodel]#
步骤 | 内容 | git 命令 |
---|---|---|
Step 11 | 推送tag信息到远程分支 | git push origin 版本号 |
[root@devops gitflowmodel]# git tag
0.1
0.1.1
[root@devops gitflowmodel]#
[root@devops gitflowmodel]# git push origin 0.1.1
Username for 'http://192.168.163.154:32001': root
Password for 'http://[email protected]:32001':
Counting objects: 1, done.
Writing objects: 100% (1/1), 160 bytes | 0 bytes/s, done.
Total 1 (delta 0), reused 0 (delta 0)
To http://192.168.163.154:32001/root/gitflowmodel.git
* [new tag] 0.1.1 -> 0.1.1
[root@devops gitflowmodel]#
确认分支状态
[root@devops gitflowmodel]# git branch
develop
* master
[root@devops gitflowmodel]# git log --graph --pretty=oneline
* b843ef1d58bca6afdf8d3ecd9b363e4725c6ce24 Merge branch 'hotfix-0.1.1'
|\
| * 7190442a53e054bc0a4715f135f5f3fae347e839 add C5
|/
* 1ad3d55b2b35220d30f00be7da0c82d385aeb48d Merge branch 'release-0.1'
|\
| * fcca679ee89ad9e2ed90e7b319ba78d10cd22dac add C4
| * eb06c4ad2a9bd1f70d1ec3135f7b8bdc8703f41f Merge branch 'feature_F1001' into develop
| |\
| | * fa40dce00a8878824641c281bd91e10749e8cc86 add C3
| |/
| * e9aff8adf4b6344c5d7f59155134ef2e579f1e32 add C2
|/
* 858d8070c8176c42e35f453a3394e4ff1bdc7e94 add C1
[root@devops gitflowmodel]#
[root@devops gitflowmodel]# git checkout develop
Switched to branch 'develop'
[root@devops gitflowmodel]# git log --graph --pretty=oneline
* e4b3be8a572f3d3efcbaf94c12211dd622b66779 Merge branch 'hotfix-0.1.1' into develop
|\
| * 7190442a53e054bc0a4715f135f5f3fae347e839 add C5
| * 1ad3d55b2b35220d30f00be7da0c82d385aeb48d Merge branch 'release-0.1'
| |\
* | \ ff52200742dc3515c85d41e206b4b7c5208881c2 Merge branch 'release-0.1' into develop
|\ \ \
| | |/
| |/|
| * | fcca679ee89ad9e2ed90e7b319ba78d10cd22dac add C4
|/ /
* | eb06c4ad2a9bd1f70d1ec3135f7b8bdc8703f41f Merge branch 'feature_F1001' into develop
|\ \
| * | fa40dce00a8878824641c281bd91e10749e8cc86 add C3
|/ /
* | e9aff8adf4b6344c5d7f59155134ef2e579f1e32 add C2
|/
* 858d8070c8176c42e35f453a3394e4ff1bdc7e94 add C1
[root@devops gitflowmodel]#
除了git的基础命令,还有其他的一些工具可以辅助进行git flow的使用使之更加简单,有命令行的操作也有图形化的工具,由于git命令本身已经较为简单,就不再对其他的方式进行进一步的介绍了。
除了git flow之外还有github flow以及gitlab flow,我们会在后续的文章中进一步的展开,相较于git flow,后面两种模型更为简单,推行起来更加方便,
但是大型复杂项目下的对应,尤其是从传统方式过度的项目,在朝着trunk-based的构成前进的途中,中间状态的对应使用git flow还是有很明显的效果的。
git flow的主要思路是两条长期存在的主分支,一条对应主开发分支,一条对应主生产分支,根据项目的复杂程度可以进行调节已达到适合当前项目的结构,甚至使用的不是git这种版本管理工具,
这种思路的延伸和扩展还是值得讨论的,比如在实际的更为复杂的项目中,使用传统的RCS这种古老的分支管理技术,使用过3条长期存在的主分支在一个超大型的项目中稳定地的管理了整个软件的生命周期。
master:用于保存和生产环境一模一样的分支
premaster:用于保存通过内部部署流程及奖发布到生产环境的分支
develop:开发分支的主分支
可以看出,这种方式下使用premaster分支作为两条主分支之间的过渡分支,一旦出现各种意外情况,可以保证无论任何时候都能知道生产环境的最新状况而不必通过一些版本工具的额外操作来实现,
一旦生产环境软硬件出现问题,可以以最快速度进行重构,以保证服务的可用性。
其实对照git flow进行思考会发现,其实这是git flow的一种变种,如果将release分支长期化,从临时性的分支变成一条长期存在的分支,即为此实践的方式。所以git flow的精华之处在于此版本管理模型的抽出,其实远在git产生之前,实际类型的实践已经在很多大型的项目中有过实践只是没有上升到共用的版本模型的高度而已。
http://nvie.com/posts/a-successful-git-branching-model/