版本管理之gitlab实践教程:进阶篇(2)
2018-02-06 07:39
483 查看
github flow实践
git flow的问题
git flow是一个较早的版本管理模型,但是也有一些实际在使用上的问题。第一个常见的问题就是因为git flow的模型设计是围绕着release进行的,所以master成为了一个用于保存向生产环境发布代码的分支,而真正的主分支我们使用的是develop分支而不是master分支,但是无论是交流上还是一些工具的缺省设定,一般都会直接使用master,
这跟我们通常的说法不同,所以每次都需要解释:这种分支模型的develop分支就是经常意义上的master主分支。
而另外一个问题则是git flow模型还是较为复杂,对于缺乏版本管理知识的普通开发者来说,学习曲线和使用成本较高。
随着持续集成和持续部署在很多项目中的推动,项目越来越多进行持续的发布,而像传统的开发方式那样,同时多功能合并在一个大版本中一起发布的情形越来越少,
取而代之的则是小步快跑,持续集成结合继续部署,使得传统模式下复杂分支管理的需求变得越来越少,很多时候只需要一个master分支即可,而正是这种情况则是github flow提出的原因。
github flow产生的契机
正如Scott Chacon在他的文章中提到的那样:既然已经有git flow了,为什么github不是直接用git flow就好了呢?这个模型过于复杂,项目实际需要的似乎比其简单的多。于是在这个基础之上,在github,他们没有使用git flow,而是使用了一个更加简单的git工作流程,这个简化的模型就是github flow。
而且更为重要的原因,围绕着release设计的fit flow模型对github来说缺乏吸引力的重要原因是release对github来说从来都不是问题而也也没有成为问题过,每天github都可以release多次,
他们甚至可以通过hobot机器人自动做到这些,整个部署的流程对每个开发者来说都不是什么问题,持续集成的基础已经非常的好,所以在这个基础之上,会理所当然地认为更为简单的模型就能够解决这个问题。
git flow的主要特点
长期分支
github flow只有一条master长期分支用于管理随时可以进行发布的分支,在master分支上的一切都被认为是可以随时可以进行部署到生产环境的内容。临时分支
github flow不同于git flow存在release/hotfix/feature三类分支,github flow只有一种分支就是特性分支。无论是bug修正还是特性开发在github flow中都是特性分支。Pull Request
github的Pull Request分支提供了一种review和合并的机制,在gitflow中,这种机制也被使用地淋漓尽致。github flow使用Pull Request用于取得feedback以及合并。github flow使用方式
github flow在使用时主要遵循如下方式:第一:只有可以部署的内容才会放到master分支上,所以master分支上的任何内容都是可部署的。
第二:特性分支的创建需要以master为基础,同时特性分支的命名需要意义清晰,容易理解。
第三:特性分支需要经常更新到远程仓库中,远程仓库中的特性分支应与本地特性分支名称相同。
第四:当需要反馈或者帮助的时候,或者当分支已经可以进行合并的时候,随时可以开启一个pull request。
第五:仅当pull request通过review之后才进行合并。
第六:一旦合并之后并推送到master分支,则意味着此内容已经随时可以进行部署,根据持续集成的原则,可以也应当立即进行部署。
github flow的模拟使用
接下来我们使用gitlab10.4.2以及git1.8.3.1来模拟一下github flow开发的流程。创建一个项目
首先我们使用gitlab的restapi创建一个项目,当然也可以直接在gitlab上进行图形界面操作,具体命令如下,请根据自己的gitlab的URL和token进行修改, 另外jq命令如果没有可以不使用,对结果不产生影响,仅仅对结果的显示格式进行整形而已执行命令
curl –request POST –header “PRIVATE-TOKEN: sqiSUhn3tHYXe8nSGRDi” –data “name=githubflowmodel” “http://127.0.0.1:32001/api/v4/projects” |jq .执行log
[root@devops ~]# curl --request POST --header "PRIVATE-TOKEN: sqiSUhn3tHYXe8nSGRDi" --data "name=githubflowmodel" "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 1931 100 1911 100 20 1139 11 0:00:01 0:00:01 --:--:-- 1140 { "id": 3, "description": null, "name": "githubflowmodel", "name_with_namespace": "Administrator / githubflowmodel", "path": "githubflowmodel", "path_with_namespace": "root/githubflowmodel", "created_at": "2018-02-04T19:15:18.826Z", "default_branch": null, "tag_list": [], "ssh_url_to_repo": "git@3ff5a6afdc80:root/githubflowmodel.git", "http_url_to_repo": "http://3ff5a6afdc80/root/githubflowmodel.git", "web_url": "http://3ff5a6afdc80/root/githubflowmodel", "avatar_url": null, "star_count": 0, "forks_count": 0, "last_activity_at": "2018-02-04T19:15:18.826Z", "_links": { "self": "http://3ff5a6afdc80/api/v4/projects/3", "issues": "http://3ff5a6afdc80/api/v4/projects/3/issues", "merge_requests": "http://3ff5a6afdc80/api/v4/projects/3/merge_requests", "repo_branches": "http://3ff5a6afdc80/api/v4/projects/3/repository/branches", "labels": "http://3ff5a6afdc80/api/v4/projects/3/labels", "events": "http://3ff5a6afdc80/api/v4/projects/3/events", "members": "http://3ff5a6afdc80/api/v4/projects/3/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": "Bw4ms91w3U2U1TcsdHzM", "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 ~]#
这样我们就创建了一个名为githubflowmodel的gitlab项目了。
初期化项目
初期化master分支
git clone远程仓库内容,进行结果确认[root@devops ~]# git clone http://192.168.163.154:32001/root/githubflowmodel.git Cloning into 'githubflowmodel'... Username for 'http://192.168.163.154:32001': root Password for 'http://root@192.168.163.154:32001': warning: You appear to have cloned an empty repository. [root@devops ~]# cd githubflowmodel/ [root@devops githubflowmodel]# git branch [root@devops githubflowmodel]# git remote -v origin http://192.168.163.154:32001/root/githubflowmodel.git (fetch) origin http://192.168.163.154:32001/root/githubflowmodel.git (push) [root@devops githubflowmodel]# [root@devops githubflowmodel]#
对项目进行初期化,创建master分支,在master分支上添加一个文件C1,并将此文件推送到远端仓库。
[root@devops githubflowmodel]# touch C1; git add C1; git commit -m "add C1"; [master (root-commit) d432a66] add C1 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 C1 [root@devops githubflowmodel]# git push origin master Username for 'http://192.168.163.154:32001': root Password for 'http://root@192.168.163.154: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/githubflowmodel.git * [new branch] master -> master [root@devops githubflowmodel]#
以master为基础创建特性分支add-navigation
[root@devops githubflowmodel]# git checkout -b add-navigation master Switched to a new branch 'add-navigation' [root@devops githubflowmodel]#
向新分支内添加文件C2
[root@devops githubflowmodel]# touch C2; git add C2; git commit -m "add C2"; [add-navigation c910267] add C2 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 C2 [root@devops githubflowmodel]#
创建Merge Request
github的PR(Pull Request),在gitlab中称为MR(Merge Request),这里创建一个MR以便进行评审或者合并执行命令:curl –request POST –header “PRIVATE-TOKEN: sqiSUhn3tHYXe8nSGRDi” –data “id=3&source_branch=add-navigation&target_branch=master&title=MergeRequestOfNewBranch” “http://127.0.0.1:32001/api/v4/projects/3/merge_requests” |jq .
[root@devops githubflowmodel]# curl --request POST --header "PRIVATE-TOKEN: sqiSUhn3tHYXe8nSGRDi" --data "id=3&source_branch=add-navigation&target_branch=master&title=MergeRequestOfNewBranch" "http://127.0.0.1:32001/api/v4/projects/3/merge_requests" |jq . % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 1106 100 1022 100 84 2861 235 --:--:-- --:--:-- --:--:-- 2870 { "id": 1, "iid": 1, "project_id": 3, "title": "MergeRequestOfNewBranch", "description": null, "state": "opened", "created_at": "2018-02-04T19:26:14.543Z", "updated_at": "2018-02-04T19:26:14.543Z", "target_branch": "master", "source_branch": "add-navigation", "upvotes": 0, "downvotes": 0, "author": { "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" }, "assignee": null, "source_project_id": 3, "target_project_id": 3, "labels": [], "work_in_progress": false, "milestone": null, "merge_when_pipeline_succeeds": false, "merge_status": "unchecked", "sha": null, "merge_commit_sha": null, "user_notes_count": 0, "discussion_locked": null, "should_remove_source_branch": null, "force_remove_source_branch": null, "web_url": "http://3ff5a6afdc80/root/githubflowmodel/merge_requests/1", "time_stats": { "time_estimate": 0, "total_time_spent": 0, "human_time_estimate": null, "human_total_time_spent": null }, "subscribed": true, "changes_count": null } [root@devops githubflowmodel]#
#
[root@devops githubflowmodel]# git branch * add-navigation master [root@devops githubflowmodel]# git push origin add-navigation Username for 'http://192.168.163.154:32001': root Password for 'http://root@192.168.163.154: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: View merge request for add-navigation: remote: http://3ff5a6afdc80/root/githubflowmodel/merge_requests/1 remote: To http://192.168.163.154:32001/root/githubflowmodel.git * [new branch] add-navigation -> add-navigation [root@devops githubflowmodel]#
Accept MR
执行命令:curl –request PUT –header “PRIVATE-TOKEN: sqiSUhn3tHYXe8nSGRDi” –data “id=3&merge_request_iid=1” “http://127.0.0.1:32001/api/v4/projects/3/merge_requests/1/merge” |jq .执行日志
[root@devops githubflowmodel]# curl --request PUT --header "PRIVATE-TOKEN: sqiSUhn3tHYXe8nSGRDi" --data "id=3&merge_request_iid=1" "http://127.0.0.1:32001/api/v4/projects/3/merge_requests/1/merge" |jq . % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 1125 100 1101 100 24 2240 48 --:--:-- --:--:-- --:--:-- 2242 { "id": 1, "iid": 1, "project_id": 3, "title": "MergeRequestOfNewBranch", "description": null, "state": "merged", "created_at": "2018-02-04T19:26:14.543Z", "updated_at": "2018-02-04T19:37:41.705Z", "target_branch": "master", "source_branch": "add-navigation", "upvotes": 0, "downvotes": 0, "author": { "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" }, "assignee": null, "source_project_id": 3, "target_project_id": 3, "labels": [], "work_in_progress": false, "milestone": null, "merge_when_pipeline_succeeds": false, "merge_status": "can_be_merged", "sha": "c910267404bba74b86ad9b63ea79b350b559c71d", "merge_commit_sha": "069cdb85e6c5097f960c3f77e7e9791f3225c224", "user_notes_count": 0, "discussion_locked": null, "should_remove_source_branch": null, "force_remove_source_branch": null, "web_url": "http://3ff5a6afdc80/root/githubflowmodel/merge_requests/1", "time_stats": { "time_estimate": 0, "total_time_spent": 0, "human_time_estimate": null, "human_total_time_spent": null }, "subscribed": true, "changes_count": "1" } [root@devops githubflowmodel]#
结果确认
本地状态确认
[root@devops githubflowmodel]# git log --graph --pretty=oneline * c910267404bba74b86ad9b63ea79b350b559c71d add C2 * d432a6654faa78d46a67249ebfb59c230804e512 add C1 [root@devops githubflowmodel]# [root@devops githubflowmodel]# git checkout master Switched to branch 'master' [root@devops githubflowmodel]# git log --graph --pretty=oneline * d432a6654faa78d46a67249ebfb59c230804e512 add C1 [root@devops githubflowmodel]# git pull Username for 'http://192.168.163.154:32001': root Password for 'http://root@192.168.163.154:32001': remote: Counting objects: 1, done. remote: Total 1 (delta 0), reused 0 (delta 0) Unpacking objects: 100% (1/1), done. From http://192.168.163.154:32001/root/githubflowmodel d432a66..069cdb8 master -> origin/master Updating d432a66..069cdb8 Fast-forward C2 | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 C2 [root@devops githubflowmodel]# git log --graph --pretty=oneline * 069cdb85e6c5097f960c3f77e7e9791f3225c224 Merge branch 'add-navigation' into 'master' |\ | * c910267404bba74b86ad9b63ea79b350b559c71d add C2 |/ * d432a6654faa78d46a67249ebfb59c230804e512 add C1 [root@devops githubflowmodel]# [root@devops githubflowmodel]# ls C1 C2 [root@devops githubflowmodel]#
通过确认可以返现,merge操作是直接对远程仓库的操作本地库没有同步发生变化,取到远端仓库的最新信息之后,可以看到merge reqeust的对应从结果上来说与git merge –no-ff方式是基本一致,都会产生一个合并的节点,另外需要合并的新的分支的内容也已经合并进来了。
远程结果确认
确认所创建的名为githubflowmodel的project的merge信息,可以确认到标题为MergeRequestOfNewBranch的MR,此时已经是merged状态。总结
github flow相对于两条长期存在的主分支和三类临时性分支构成的git flow来说,算是一个非常简单的git的工作流程模型,此模型只有一个主分支为master为长期存在,而其他情形都可以使用临时分支来进行对应,通过活用PR或者MR进行沟通和评审以及合并,结合Webhook自动调用jenkins的job来实现持续集成和持续交付会有很好的效果。参考文章
http://scottchacon.com/2011/08/31/github-flow.html相关文章推荐
- 版本管理之gitlab实践教程:基础篇(12)
- 版本管理之gitlab实践教程:基础篇(5)
- 版本管理之gitlab实践教程:基础篇(4)
- 版本管理之gitlab实践教程:基础篇(2)
- 版本管理之gitlab实践教程:基础篇(9)
- 版本管理之gitlab实践教程:基础篇(8)
- 版本管理之gitlab实践教程:基础篇(13)
- 版本管理之gitlab实践教程:基础篇(11)
- 版本管理之gitlab实践教程:基础篇(1)
- 版本管理之gitlab实践教程:进阶篇(1)
- 版本管理之gitlab实践教程:基础篇(6)
- 版本管理之gitlab实践教程:基础篇(10)
- 版本管理之gitlab实践教程:基础篇(3)
- 版本管理之gitlab实践教程:基础篇(7)
- 使用GitLab版本管理工具教程
- 版本管理工具TortoiseSVN使用教程
- PHP 开发的 API 多版本管理实践
- GitLab版本管理
- PHP 开发的 API 多版本管理实践
- Android Studio之版本管理工具Git (图文教程)