Git工作流指南 分布式版本控制系统

观看笔记:https://www.bilibili.com/video/BV1dW411U7ER?p=1
老师笔记: http://www.funtl.com/zh/git/

Git简介

  • 什么是版本控制系统
  • 什么是Git
  • 如何安装Git

什么是版本控制系统

为什么需要版本控制

在软件开发过程中,每天都会产生新的代码,代码合并的过程中可能会出现如下问题

  • 代码覆盖或丢失
  • 代码写的不理想,希望还原之前的版本
  • 希望知道与之前版本的差别
  • 修改了代码以及为什么修改;
  • 发版时希望分成不同的版本(测试版本、发行版本等);

因此,希望有一种机制,能够帮助我们:

  • 可以随时回滚到之前的版本
  • 协同开发时,不会覆盖别人的代码;
  • 留下修改记录,以便随时查看;
  • 发版时可以方便的管理不同的版本

什么是版本控制系统

一个标准的版本控制系统 Version Control System(VCS),通常需要有以下功能:

  • 能够创建Repository仓库),用来保存代码
  • 协同开发时,方便将代码分发给团队成员;
  • 记录每次修改代码的内容、时间、原因等信息
  • 能够创建Branch(分支),可以根据不同的场景进行开发
  • 能够创建Tag(标签)建立项目里程碑

版本控制系统的发展史

版本控制系统发展至今有几种不同的模式

Local VCS

本地使用 复制/粘贴 的方式进行管理,缺点无法协同开发

Gentralized VCS(Lock,悲观锁)

中央集中式版本控制系统团队共用仓库,当某人需要编辑文件时,进行锁定,以免其他人同时编辑时造成冲突,但不是很方便,其他人需要排队才能编辑文件,如果有人编辑了很久或是忘记解锁会造成其他人长时间等待的情况;

如何理解悲观锁:总有刁民想害朕。
我要是面试这么答,会怎么样?

Gentralized VCS(Merge,乐观锁)

中央集中式版本控制系统团队共用仓库,不采用悲观锁方式来避免冲突,而是时候发现如果别人也修改相同文件(冲突),再进行手动修改解决

有很多VCS属于这种类型,如:CVS、Subversion、Perforce等;

中央集中式版本控制系统的共同问题是,做任何操作都需要和服务器同步,如果服务器宕机则会造成无法继续工作的窘迫

如何理解乐观锁:天网恢恢疏而不漏。
我想给自己两锤子;

Distributed VCS

分布式版本控制系统本地拥有完整的代码仓库,就不会出现上述集中式管理的问题,即使没有网络,依然可以commit和看log,也无需担心服务器同步问题;

如:Git、Mercurial、Bazaar等就属于分布式版本控制系统缺点功能比较复杂,上手需要一定的学习时间;

分布式版本控制系统都有一个本地化的这样一个概念;区块链系统也能称之为一个分布式系统

Git工作流

Git工作流代码管理工作流程、方式

  • Git工作流简介
  • 集中式工作流
  • 功能分支工作流
  • GitFlow工作流
  • Forking工作流
  • Pull Requests

Git工作流简介

工作流有各式各样的用法,但也正因此使得在实际工作中如何上手使用增加了难度。

这篇指南通过总览公司团队中最常用的集中Git工作流让大家可以上手使用;

在阅读的过程中请记住,本文中的集中工作流是作为方案指导而不是条例规定,在展示了各种工作流可能的用法后,可以从不同的工作流中挑选或揉合出一个满足自己需求的工作流;

集中式工作流

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-k1NsOAXt-1616635519570)(http://r.photo.store.qq.com/psc?/V13IdniL4CDhqM/TCfiP1YaPeRT4Jil9RANXyIW2ezMoDhUXO*s5pTGue2N753CPNKcE42sPIP6l3d0rpu2DZjcGmC.Kga3cDUruqQwuWnPoetw.KevCfGSm5U!/r)]

如果开发团队成员已经很熟Subversion集中式工作流让你无需去适应一个全新流程就可以体验Git带来的收益。

这个工作流也可以作为向更Git风格工作流迁移的友好过渡。

(个人、三五个人的小团队)

功能分支工作流

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BrSN9Sdk-1616635519576)(http://r.photo.store.qq.com/psc?/V13IdniL4CDhqM/TCfiP1YaPeRT4Jil9RANX.QLkS1nyIjv6HHWnbV4dX7srariw7MEQpLi1gOAxL3ou18PqhQZr1mrBrEaIbVs5JuQWzjNbAd8lfxuJK8OGPM!/r)]

功能分支工作流集中式工作流基础,不同的是为各个新功能分配一个专门的分支来开发。

这样可以在把新功能继承到正式项目前,用Pull Requests的方式讨论变更

(达到约12个人的团队)

Git Flow工作流

Git Flow工作流通过为功能开发发布准备维护分配独立的分支,让发布迭代过程更顺畅

严格的分支模型也为大型项目提供了一些非常必要的结构。

(整个公司,这么一个团队的规模)

Forking工作流

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wrD9j7eh-1616635519578)(http://r.photo.store.qq.com/psc?/V13IdniL4CDhqM/TCfiP1YaPeRT4Jil9RANX7NQkdqkFQWuuELLHKCcql5ABKaPDZFUejww*HH9qtsi8qr7IlATkqBkQ9PV1LJ9rT6faqWzcfgS3pJZnzLSzVg!/r)]

Forking工作流是分布式工作流,充分利用了Git在分支和克隆上的优势。

可以安全可靠地管理大团队的开发者(developer),并能接受不信任贡献者(contributor)的提交。

(跨国合作。跨国团队的使用,一般用于Forking工作流)

Pull Requests

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZSxprR1w-1616635519584)(http://r.photo.store.qq.com/psc?/V13IdniL4CDhqM/TCfiP1YaPeRT4Jil9RANXzYbgZ.02.6Smac50apszMyWGwg89uQEVJSVU01e69u2Dts1al5lueZ4HgBrr.WyV.0GtO*ZTdT3LpQtilbX2Vk!/r)]

功能分支工作流GitFlow工作流Forking工作流都会穿插一个Pull Requests的一个东西。

Pull Requests通常称为请求合并Merge Pull Requests);

Pull Requests让开发者更方便地进行协作的功能,提供了友好的Web界面可以在提议的修改合并到正式项目之前对修改进行讨论。

(相当于一个评论系统);

集中式工作流

转到分布式版本控制系统看起来像个令人生畏的任务,但不改变已用的工作流你也可以用上Git带来的收益。

团队可以用和Subversion完全不变的方式来开发项目。

但使用Git加强开发的工作流,Git比SVN有几个优势

(1) 首先,每个开发者可以有属于自己的整个工程的本地拷贝。隔离的环境让各个开发者的工作和项目的其他部分(修改)独立开来-------即自由地提交到自己的本地仓库,先完全忽略上游的开发,直到方便的时候再把修改反馈上去。

(2) 其次,Git提供了强壮的分支和合并模型。不像SVN,Git的分支设计成可以作为一种用来在仓库之间集成代码和分享修改的 【失败安全】机制

工作方式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-an3dYRAQ-1616635519586)(http://r.photo.store.qq.com/psc?/V13IdniL4CDhqM/TCfiP1YaPeRT4Jil9RANX58rubGqwbukXS4rvP.hcw8vVDFpcMEKyanOzFC60vYY7EfnKsFaNa8DYFcGkpbCkTOCu8b0QXObUxn8ABvZn4U!/r)]

Subversion一样,集中式工作流中央仓库作为项目所有修改的单点实体

相比SVN缺省的开发分支trunk,Git叫做master,所有修改提交到这个分支上。

该工作流只用到master这一个分支。

开发者开始先克隆中央仓库。

在自己的项目拷贝中,像SVN一样的编辑文件和提交修改;

但修改是存在本地的,和中央仓库完全隔离的;

开发者可以把和上游的同步延后到一个方便时间点;

要发布修改到正式项目中,开发者要把本地master分支的修改【推(push)】到中央仓库中。

这相当于svn commit操作,但push操作会把所有还不在中央仓库的本地提交都推上去。

解决冲突

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h8FExR6K-1616635519589)(http://r.photo.store.qq.com/psc?/V13IdniL4CDhqM/TCfiP1YaPeRT4Jil9RANX7NAq94egRJ5nBPO8Co87th*P0cTdtAGYXp43mklxBxvhd73.i5d8Lm58WdsFYNrarV7XZaiqfrmkd3gUFAFW0o!/r)]

中央仓库代表了正式项目,所以提交历史应该被尊重且是稳定不变的。

如果开发者本地的提交历史和中央仓库有分歧,Git会拒绝push提交否则会覆盖已经在中央库的正式提交。

在开发者提交自己功能修改到中央库前,需要先fetch在中央库的新增提交,rebase自己提交到中央库提交历史之上。

这样做的意思是在说,【我要把自己的修改加到别人已经完成的修改上。】最终的结果是一个完美的线性历史,就像以前的SVN的工作流中一样;

如果本地修改和上游提交有冲突,Git会暂停rebase过程,给你手动解决冲突的机会。

Git解决合并冲突,用和生成提交一样的git status和git add命令,很一致方便。

还有一点,如果解决冲突时遇到麻烦,Git可以很简单中止整个rebase操作,重来一次(或者让别人来帮助解决)。

示例

一起逐步分解来看看一个常见的小团队如何用这个工作流来协作的。

有两个开发者小明和小红,看他们是如何开发自己的功能并提交到中央仓库上的。

有人先初始化好中央仓库

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sLevQsYY-1616635519590)(http://r.photo.store.qq.com/psc?/V13IdniL4CDhqM/TCfiP1YaPeRT4Jil9RANX9UbT3uXKi44e*o.QOIDNJOk403REJAlPsZkIyST70GEweXbAbks3cFR7TqiVMFHAtTg9MXSvYT6HSyIH1eLii4!/r)]

第一步,有人在服务器上创建好中央仓库。

如果是新项目,可以初始化一个空仓库;否则要导入已有的Git或SVN仓库。

中央仓库应该是个裸仓库(bare repository),即没有工作目录(working directory)的仓库。

所有人克隆中央仓库

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cLbLOsmq-1616635519591)(http://r.photo.store.qq.com/psc?/V13IdniL4CDhqM/TCfiP1YaPeRT4Jil9RANX8lXRlkamDFhSxpL42PuUsH4aIULseTwL66K.p5pWkVzGzBh8Nih.I7qaVf43t7zoP8GGUp44vHNSNRccIY!/r)]

下一步,各个开发者创建整个项目的本地拷贝。

通过git clone命令完成。

git clone  https://github.com/path/to/repo.git

基于后续会持续和克隆的仓库做交互的假设,克隆仓库时Git会自动添加远程别名origin指回【父】仓库。

github即git的中央仓库;版本控制系统有一个版本仓库。

github上public即开源,公开的意思,代码开源。

如果是私有private则需要进行CreditCard 信用卡支付相应的金额;收费;

小明开发功能

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PcT5d9Kx-1616635519593)(http://r.photo.store.qq.com/psc?/V13IdniL4CDhqM/TCfiP1YaPeRT4Jil9RANX3cSXX6681Ge8WeUymk3FFjspNtDVB3t7XeHuVufMD05ZhJzX9OyWJDCYAlloD65QJLNRkDaLpYfFLKjESAA0SM!/r)]

在小明的本地仓库中,他使用标准的Git过程开发功能:编辑、暂存(Stage)和提交。

如果你不熟悉暂存区(Stageing Area),这里说明一下:暂存区的用来准备一个提交,但可以不用把工作目录中所有的修改内容都包含进来。

这样可以创建一个高度聚焦的提交,尽管本地修改很多内容。

git status # 查看本地仓库的修改状态
git add # 暂存文件
git commit # 提交文件

请记住,因为这些命令生成的是本地提交,小明可以按自己需求反复操作多次,而不用担心中央仓库有了什么操作。

对需要多个更简单更原子分块的大功能,这个做法是很有用的;

小红开发功能

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wCcPqTco-1616635519594)(http://r.photo.store.qq.com/psc?/V13IdniL4CDhqM/TCfiP1YaPeRT4Jil9RANX3AhXN0wKh7FwIloQiq3PMOUwpanqXsBqPo.yaxL1hWnR.kZm*XseG5RhBNtuoS8.PVSKuKSdHEw1x7MixOxA!/r)]

与此同时,小红在自己的本地仓库中用相同的编辑、暂存和提交过程开发功能。

和小明一样,她也不关心中央仓库有没有新提交;当然更不关心小明在他的本地仓库中的操作,因为所有本地仓库都是私有的。

小明发布功能

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W5gJW6V0-1616635519596)(http://r.photo.store.qq.com/psc?/V13IdniL4CDhqM/TCfiP1YaPeRT4Jil9RANX2DDMKOOXZiA6a0j82260kNXKGqba7MbMMt5OmvuzTfK3A*Lxszb8CTdFEjjZXvIDOZez3cKxhQHt2dZMB.G9S4!/r)]

一旦小明完成了他的功能开发,会发布他的本地提交到中央仓库中,这样其他团队成员可以看到他的修改。

他可以用下面的git push 命令:

git push origin master

注意,origin是小明克隆仓库时Git创建的远程中央仓库别名。

master参数告诉Git推送的分支。

由于中央仓库自从小明克隆以来还没有被更新过,所以push操作不会有冲突,成功完成。

小红试着发布功能

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7Zv4WmVi-1616635519597)(http://r.photo.store.qq.com/psc?/V13IdniL4CDhqM/TCfiP1YaPeRT4Jil9RANX49Hssuuk2yHbmsbkSdUuOtLRbTxRlP3xEORKm5txDWaExKbZyYnyzyBD0oDqcjETeUWkabVFxZpo*3gs9yQWHs!/r)]

一起来看看在小明发布修改后,小红push修改会怎么样?

她使用完全一样的push命令:

git push origin master

但她的本地历史已经和中央仓库有分歧了,Git拒绝操作并给出下面很长的出错消息:

error: failed to push some refs to '/path/to/repo.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Merge the remote changes(e.g. 'git pull')
hint: before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
....

这避免了小红覆写正式的提交。

她要先pull小明的更新到她本地仓库合并上她的本地修改后,再重试。

小红在小明的提交之上rebase

小红用git pull 合并上游的修改到自己的仓库中。

这条命令类似svn update -------拉取所有上游提交命令到小红的本地仓库,并尝试和她本地修改合并。

git pull --rebase origin master

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QPkAt2Da-1616635519598)(http://r.photo.store.qq.com/psc?/V13IdniL4CDhqM/TCfiP1YaPeRT4Jil9RANXyi6Y8l5sb1aRwQRlb0CiRDNdgM9NZtfk5D41PvfJEccriZP3FT6WnQ4PWKvEqz*e7LpBOfcXui.l9nUXAPUgd4!/r)]

–rebase 选项告诉Git把小红的提交移到同步了中央仓库修改后的master分支的顶部;

如果忘了加这个选项,pull操作仍然可以完成,但每次pull操作要同步中央仓库别人修改时,提交历史会以一个多余的【合并提交】结尾。

对于集中式工作流,最好是使用rebase而不是生成一个合并提交。

小红解决合并冲突

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wuKSXeda-1616635519599)(http://r.photo.store.qq.com/psc?/V13IdniL4CDhqM/TCfiP1YaPeRT4Jil9RANX7FxPBYYYsKKPOWXqC*0rCPhZKJRqU86pJwCJIVi3g31ZcpHEH2b76upvPK6lrEAQ9UWa9VqeFjlEC4dX2PAHTw!/r)]

rebase操作过程是把本地提交一次一个地迁移到更新了的中央仓库master分支之上,这意味着可能要解决在迁移某个提交时出现的合并冲突,而不是解决包含了所有提交的大型合并时所出现的冲突。

这样的方式让你尽可能保持每个提交的聚焦和项目历史的整洁。

反过来,简化了哪里引入Bug的分析,如果有必要,回滚修改也可以做到对项目影响最小。

如果小红和小明的功能是相关的,不大可能在rebase过程中有冲突。

如果有,Git在合并有冲突的提交出暂停rebase过程,输出下面的信息并带上相关的指令:

CONFLICT (content): Merge conflict in

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SpwGF9iS-1616635519600)(http://r.photo.store.qq.com/psc?/V13IdniL4CDhqM/TCfiP1YaPeRT4Jil9RANX5fiCqpawh2bvFoyuusAOSGHKu5sc59EGgvKP1aVmHVmey3BEhEwMSvuvtOXh1oSZU1zNvf5QV2G*SN2a1sgwiA!/r)]

Git 很赞的一点是,任何人可以解决他自己的冲突。

在这个例子中,小红可以简单的运行 git status 命令来查看哪里有问题。

冲突文件列在 Unmerged paths(未合并路径)一节中:

# Unmerged paths:
#(use "git reset HEAD <some-file>..." to unstage)
#(use "git add/rm <some-file>..." as appropriate to mark resolution)
#
# both modified:<some-file>

接着小红编辑这些文件。

修改完成后,用老套路暂存这些文件,并让git rebase 完成剩下的事情:

git add
git rebase --continue

要做的就这些了。

Git会继续一个一个的合并后面的提交,如其他的提交有冲突就重复这个过程。

如果你碰到了冲突,但是发现搞不定,不要惊慌。

只要执行下面这条命令,就可以回到你执行git pull --rebase命令前的样子:

git rebase --abort
小红成功发布功能

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yjdw6ood-1616635519601)(http://r.photo.store.qq.com/psc?/V13IdniL4CDhqM/TCfiP1YaPeRT4Jil9RANX0kBnWeNL8ejRYU6ro4.2u6jfdf4WmDKrAtmoAnmJ9TQ4sDBTQl0i3xlqRsJMoYZns72c0lo3zm5ObKWH4CoUG0!/r)]

小红完成和中央仓库的同步之后,就能成功发布她的修改了。

git push origin master
总结

如你所见,仅仅使用几个Git命令,就可以模拟出传统Subversion开发环境。

对于要从SVN迁移过来的团队来说这太好了,但是没有发挥出Git分布式本质的优势。

如果你的团队适应了集中式工作流,但想要更流畅的协作效果,绝对值得探索一下功能分支工作流的收益。

通过为一个功能分配一个专门的分支,能够做到一个新增功能集成到正式项目之前对新功能进行深入讨论。

功能分支工作流

一旦玩转了集中式工作流,在开发过程中可以很简单地加上功能分支,用来鼓励开发者之间协作和简化交流。

功能分支工作流背后的核心思路是所有的功能开发应该在一个专门的分支,而不是在master分支上。

这个隔离可以方便多个开发者在各自的功能上开发而不会弄乱主干代码。

另外,也保证了master分支的代码一定不会是有问题的,极大有利于集成环境。

功能开发隔离也让pull requests工作流成为可能, pull requests工作流能为每一个分支发起一个讨论,在分支合入正式项目之前,给其它开发者有表示赞同的机会。

另外,如果你在功能开发中有问题卡出了,可以开一个pull Requests来向同学们征求建议。

这些做法的重点就是,pull Requests让团队成员之间互相评论工作变成非常方便!

工作方式

功能分支工作流仍然用中央仓库,并且master分支还是代表了正式项目的历史。

但不是直接提交本地历史到各自的本地master分支,开发者每次在开始新功能前先创建一个新分支。

功能分支应该有个描述性的名字,比如 animated-menu-items 或者 issue-#1061,这样可以让分支有个清楚且高聚焦的用途。

在master分支和功能分支之间,Git是没有技术上的区别,所以开发者可以用和集中式工作流完全一样的方式编辑、暂存和提交修改到功能分支上。

另外,功能分支也可以(且应该)push到中央仓库中。

这样不修改正是代码就可以和其他开发者分享提交的功能。

由于master仅有的一个【特殊】分支,在中央仓库上存在多个功能分支不会有任何问题。

当然这样做也可以很方便地备份各自的本地提交。

Pull Requests

功能分支除了可以隔离功能的开发,也使得通过 Pull Requests讨论变更称为可能。

一旦某个开发完成一个功能,不是立即合并到master,而是push到中央仓库的功能分支上并发起一个Pull Requests的请求去合并并修改到master。

在修改成为主干代码之前,这让其他的开发者有机会先去Review变更。

Code Review是Pull Requests的一个重要的收益。

但是pull Requests目的是讨论代码一个通用方式。

你可以把Pull Requests作为专门给某个分支的讨论。

这意味着可以在更早的开发过程中就可以进行Code Review。

比如,一个开发者开发功能需要帮助时,要做的就是发起一个Pull Requests,相关的人就会自动收到通知,在相关的提交旁边能看到需要帮助解决的问题。

一旦Pull Requests被接受了,发布功能要做的就和集中式工作流就很像了。

(1)首先,确定本地的master分支和上游的master分支是同步的。

(2)然后合并功能分支到本地master分支,并push已经更新的本地master分支到中央仓库。

示例

下面的示例演示了如何把Pull Requests作为Code Review的方式,但注意Pull Requests可以用于很多其他的目的。

小红开始开发一个新功能

在开始开发功能之前,小红需要一个独立的分支。

使用下面的命令新建一个分支。

git checkout -b marys-feature master

这个命令检出一个基于master名为marys-feature的分支,Git的-b选项表示如果分支还不存在则新建分支。

这个新分支上,小红按照老套路编辑、暂存和提交修改,按需要提交以实现功能:

git  status
git add
git commit
小红要去吃个午饭

(两个人、多个人同时开发,称之为协同开发)

仓库:github、码云、码市、gitlab

review 代码审核;

早上小红为新功能添加了一些提交。

去吃午饭前,push功能分支到中央仓库是很好的做法,这样可以方便地备份,如果和其他开发协作,也让他们可以看到小红的提交。

git push -u origin marys-feature

这条命令 push marys-feature 分支到中央仓库(origin),-u选项设置本地分支去跟踪远程对应的分支。

设置好跟踪的分支后,小红就可以使用git push 命令省去指定推送分支的参数。

小红完成功能开发

小红吃完午饭回来,完成整个功能的开发。

在合并到master之前,她发起一个Pull Requests让团队的其他人知道功能已经完成。

但是首先,她要确认中央仓库中已经有她最近的提交。

git push

然后,在她的Git GUI客户端中发起Pull Request,请求合并marys-feature到master,团队成员会自动收到通知。

Pull Request很酷的是可以在相关的提交旁边显示评注,所以你可以很对某个变更集提问。

小黑收到Pull Request

小黑收到Pull Request后会查看marys-feature的修改。

决定在合并到正式项目前是否要做些修改,且通过Pull Request和小红来回的讨论。

小红再做修改

要在做修改,小红用和功能第一个迭代完全一样的过程。

编辑、暂存、提交并push更新到中央仓库。

小红这些活动都会显示在Pull Request上,小黑可以断续做评注。

如果小黑有需要,也可以把marys-feature分支拉到本地,自己来修改,他加的提交也会一样显示在Pull Request上。

小红发布她的功能

一旦小黑可以接受Pull Request,就可以合并功能到稳定项目代码中(可以由小黑或者是小红来做这个操作):

git checkout master
git pull
git pull origin marys-feature
git push

无论谁来做合并,首先要检出master分支并确认它是最新的。

然后执行 git pull origin marys-feature 合并 marys-feature 分支到已经和远程一直的本地 master分支。

你可以使用简单 git merge marys-feature命令,但是前面的命令可以保证总是最新的新功能分支。

最后更新的master分支要重新push回到origin。

这个过程常常会生成一个和并提交。

有些开发者喜欢有合并提交。

因为它像一个新功能和原来代码基线的连通符。

但如果你偏爱线性的提交历史,可以在执行合并rebase新功能到master分支的顶部,这样生成一个快进(fast-forward)的合并。

一些GUI客户端只要点一下【接受】按钮执行好上面的命令来自动化Pull Request接受过程。

如果你的不能这样,至少在功能合并到master分子后自动关闭Pull Request。

与此同时,小明在做和小红一样的事情

当小红和小黑在marys-feature上工作并讨论她的Pull Request的时候,小明在自己的功能分支上做完全一样的事情。

通过隔离功能能到独立的分支上,每个人都可以自主的工作,当然必要的时候在开发者之间分享变更还是比较繁琐的。

总结

到了这里,但愿你发现了功能分支可以很直接地在集中式工作流的仅有的master分支上完成多功能的开发。

另外,功能分支还使用了Pull Request,使得可以在你的版本控制GUI客户端中讨论某个提交。

功能分支工作流是开发项目异常灵活的方式。

问题是,有时候太灵活了。

对于大型团队,常常需要给不同分支分配一个更具体的角色。

GitFlow工作流是管理功能开发、发布准备和维护的常用模式。

GitFlow工作流

在实际开发当中,可能通常使用GitFlow工作流。

GitFlow工作流定义了一个围绕项目发布的严格分支模型。

虽然比功能分支工作流复杂几分,但是提供了一个用于健壮的用于管理大型项目的框架。

GitFlow工作流没有用超出功能分支工作流的概念和命令。

而是为不同的分支分配了一个很明确的角色,并定义分支之间如何交互和什么时候进行交互。

除了使用功能分支,在做准备、维护和记录发布也是用各自的分支。

当然你可以用上功能分支工作流所有的好处:Pull Request、隔离实验性开发和更高效的工作。

工作方式

GitFlow工作流仍然用中央仓库作为所有开发者的交互中心。

和其他工作流一样,开发者在本地工作并push分子到中央分支去。

历史分支

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O5Mpak5b-1616635519603)(http://r.photo.store.qq.com/psc?/V13IdniL4CDhqM/TCfiP1YaPeRT4Jil9RANX0DucqArpSZN8V1mN.Djx7WchltIFUxePFkxo0wF6tL9hJ92GPpyK1meBHYC6jQnh92Uk6*6zENCWbjq21uqLsI!/r)]

相对使用仅有的一个master分支,GitFlow工作流使用两个分支来记录项目的历史。

master分支存储了正式发布的历史,而develop分支作为功能的集成分支,这样也方便master分支上的所有提交分配一个版本号。

剩下要说明的问题就是围绕这两个分支的区别展开。

功能分支

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cRvWlSyV-1616635519604)(http://r.photo.store.qq.com/psc?/V13IdniL4CDhqM/TCfiP1YaPeRT4Jil9RANX4suzD8O2OoWbYPwQ150IFWgQS3qSKoLWdglLxIjfri4eWAHC*W6m9OYJM0vFH4CxIhXiOdTBQYoWLsUJ3d8M.k!/r)]

每个新功能位于一个自己的分支,这样可以push到中央仓库以备份和协作。

但是功能分支不是从master分支上拉出新分支,而是使用develop分支作为父分支。

当新功能完成时,合并会develop分支。

新功能提交应该从不直接与master分支交互。

开源软件基本上是使用GitFlow来做代码版本管理的控制。

注意,从各种含义和目的上来看,功能分支加上develop分支就是功能分支工作流的用法。

但是GitFlow工作流没有在这里止步。

发布分支

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3Fta4bq2-1616635519605)(http://r.photo.store.qq.com/psc?/V13IdniL4CDhqM/TCfiP1YaPeRT4Jil9RANX1K5y5ivKrSrhk3l.NtQVVaNHmKMdlqKelqYaRENh701X*IrEmFCJIhfs5U7wXELfZbYI1tihPDOGBwBPqt6E!/r)]

一旦develop分支上有了做一次发布(或者说快到了既定的发布日)的足够功能,就从develop分支上fork一个发布分支。

新建的分支用于开始发布循环,所以从这个时间点开始之后新的功能不能再加到这个分支上-------这个分支只应该叫Bug修复、文档生成或其他面向发布任务。

一旦对外发布的工作都完成了,发布分支合并到master分支并飞配一个版本号打好Tag。

另外,这些新建发部分之以来做的修改要合并回develop分支。

使用一个用于发布准备的专门分支,使得一个团队可以在完善当前的发布版本的同时,另一个团队可以继续开发下个版本的功能。

这也打造定义良好的开发阶段(比如,可以很轻松的说,【这周我们要做准备发布版本4.0】,并且在仓库的目录结构中可以实际看到)

常用的分支约定:

  • 用于新建发布分支的分支:develop
  • 用于合并的分支:master
  • 分支命名:release- 或 release/
维护分支

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I6ukL0Bu-1616635519606)(http://r.photo.store.qq.com/psc?/V13IdniL4CDhqM/TCfiP1YaPeRT4Jil9RANX8qfvx9q8UhYcwpU4tSoxZoCzp2TGnchoEgJnBAd**ejGrSWx7H1n1RbZFVAdVlD7v3kEO6EHjpPFNMCD9pabTQ!/r)]

维护分支或者说是热修复(hotfix)分支用于生成快速给产品发布版本(production release)打补丁,这是唯一可以从master分支fork出来的分支。

修复完成,修改应该马上合并回master分支和develop分支(当前的发部分支),master分支应该用新的版本号打好Tag。

为了Bug修复使用专门分支,让团队可以处理问题而不用打断其他工作或者是等待下一个发布循环。

你可以把维护分支想成是一个直接在master分支上处理的临时发布。

即hotfix,维护的是v1.0.0—>v1.0.1这种;
第三位数修改的是Bug(hotfix维护版本第三位数);第二位数修改的是功能(功能分支维护的是版本的第二位数);第一位为大架构改变的时候进行修改(维护版本的第一位数);

GitFlow从这点上就可以与语义化规范牵扯上联系;

示例

下面的示例演示本工作流如何用于管理单个发布循环。

假设你已经创建了一个中央仓库。

创建开发分支

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aIlwBfww-1616635519607)(http://r.photo.store.qq.com/psc?/V13IdniL4CDhqM/TCfiP1YaPeRT4Jil9RANX4Xsg92Awirp0bThQ4nYW8UWB.U5XFBFsn5hkNOcst0hBz.q1uwuu*KDADM.W9naZBQq8eKQyo4iLkzk28e1g!/r)]

第一步为master分支配套一个develop分支。

简单来做可以本地创建一个空的develop分支,push到服务器上:

git branch develop
git push -u origin master

以后这个分支将会包含了项目的全部历史。

而master分支将只包含部分历史。

其他开发者这时应该克隆中央仓库,建好develop分支的跟踪分支:

git clone ssh://user@host/path/to/repo.git
git checkout -b develop origin/develop

现在每个开发都有了这些历史分支的本地拷贝。

小红和小明开始开发新功能

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7pbc8SPO-1616635519608)(http://r.photo.store.qq.com/psc?/V13IdniL4CDhqM/TCfiP1YaPeRT4Jil9RANX2X16EiSaoizI9a2HRgo6HRlddb*dD0yGRzorFtrKInoqDMveDkX4.ujU1ZgrgxXoZf1vY83YLzd6Dl2YO5SDUc!/r)]

这个示例中,小红和小明开始各自的功能开发。

他们需要为各自的功能创建相应的分支。

新分支不是基于master分支,而是应该基于develop分支:

git checkout -b some-feature develop

他们用老套路添加提交到各自功能分支上:编辑、暂存、提交;

git status
git add
git commit
小红完成功能开发

添加了提交后,小红觉得她的功能OK了。

如果团队使用Pull Requests,这时候可以发起一个用于合并到develop分支。

否则她可以直接合并到她本地的develop分之后push到中央仓库:

git pull origin develop
git checkout develop
git merge some-feature
git push
git branch -d some-feature

第一条命令在合并功能前确保develop分支是最新的。

注意,功能绝不应该直接合并到master分支。

冲突解决方法和集中式工作流一样。

小红开始准备发布

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kmzMP4BF-1616635519609)(http://r.photo.store.qq.com/psc?/V13IdniL4CDhqM/TCfiP1YaPeRT4Jil9RANXxm6aYd1gMGOxylETc6cDcj7kTwBnGuyoyzYDL7pNxxvtXeoD5bCxnVfWEk.cQe8O4lhgkHo2zR.IIDII1kmA!/r)]

这个时候小明正在实现他的功能。

小红开始准备她的第一个项目正式发布(发布分支也叫预发布分支,预发布分支基于develop,只有预发布版本分支才能够去合并到master分支,而预发布版本是经过测试人员测试之后的没有问题的一个版本;master分支代码必须可以执行,没有被污染)。

像功能开发一样,她用一个新的分支来做发布准备。

这一步也确定了发布的版本号:

git checkout -b release-0.1 develop

这个分支是清理分支、执行所有测试、更新文档和其他为下个发布做准备操作的地方,像是一个专门用于改善发布的功能分支。

只要小红创建的这个分支push到中央仓库,这个发布就是功能冻结的。

任何不在develop分支中的新功能都推到下一个发布循环中。

小红完成发布

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P0CPQvO6-1616635519610)(http://r.photo.store.qq.com/psc?/V13IdniL4CDhqM/TCfiP1YaPeRT4Jil9RANXx2fdZ*.CxsTwPMg235DDXkchbPbk7hNVec6.FIcmcf72k0vjzhdQvVlYt8u8ao*65n3gyQAyN5GOxndJKhwiNk!/r)]

一旦准备好了对外发布,小红合并修改到master分支和develop分支上,删除发布分支。

合并回develop分支很重要,因为在发布分支中已经提交的更新需要在后面的新功能中也要是可用的。

另外,如果小红的团队要求Code Review,这是一个发起Pull Request的理想时机。

git checkout master
git merge release-0.1
git push
git checkout develop
git merge release-0.1
git push
git branch -d release-0.1

发布分支是作为功能开发(develop分支)和对外发布(master分支)间的缓冲。

只要有合并到master分支,就应该打好Tag以方便跟踪。

git tag -a 0.1 -m "Initial public release" master
git push --tags

Git有提供各种钩子(hook),即仓库有时间发生时触发执行的脚本。

可以配置一个钩子,在你push中央仓库的master分支时,自动构建好对外发布。

最终用户发现Bug

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PYuFAa1A-1616635519611)(http://r.photo.store.qq.com/psc?/V13IdniL4CDhqM/TCfiP1YaPeRT4Jil9RANXzsQH1hJotlrx1khR6EZ0dUlyxkaf9L1Yi66Fs6sohYE0UTifJNygNHaokiIgZc5dg2qSXBWVyQGtiyMr0yo8!/r)]

对外发布后,小红回去和小明一起做下个发布的新功能开发,直到有最终用户开了一个Ticket抱怨当前版本的一个Bug。

为了处理Bug,小红(或者小明)从master分支上来去了一个维护分支(hotfix),提交修改以解决问题,然后直接合并回master分支:

git checkout -b issue-#001 master
# Fix the bug
git checkout master
git merge issue-#001
git push

就像发布分支,维护分支中新加这些重要修改需要包含到develop分支中,所以小红要执行一个合并操作,然后就可以安全地删除这个分支了:

git checkout develop
git merge issue-#001
git push
git branch -d issue-#001

总结

到了这里,但愿你对集中式工作流、功能分支工作流和GitFlow工作流已经感觉很舒适了。

你应该也牢固的掌握了本地仓库的潜能,push/pull模式和Git健壮的分支和合并模型。

记住,这里演示的工作流只是可能用法的例子,而不是在实际工作中使用Git不可违逆的条例。

所以不要畏惧按自己需要对工作流的用法做取舍,不变的目标就是让Git为你所用。

(在整个GitFlow工作流当中,只会去进行省略功能分支Feature,Master、HotFix、Release、Develop是必不可少的分支,以便控制每一次版本的迭代)

Forking工作流

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5SXKrFpc-1616635519612)(http://r.photo.store.qq.com/psc?/V13IdniL4CDhqM/TCfiP1YaPeRT4Jil9RANX2qjPC0eDN.Xf29HcBYoAsTtpBFvJhu8qPVkh5cv575QWLsHx3q8JbFYK3X5cts.Zn43gkCjc7OzyBcDFaNdl.g!/r)]

Forking工作流和前面讨论的几种工作流有根本的不同。

这种工作流不是适用单个服务器端仓库作为【中央】代码基线,而让各个开发者都有一个服务端仓库。

这意味着各个代码贡献者有2个Git仓库而不是1个:一个本地私有的,另一个服务端公开的。

Forking工作流的一个主要优势是,贡献的代码可以被集成,而不需要所有人都能push代码到仅有的中央仓库中。

开发者push到自己的服务端仓库,而只有项目维护者才能push到正式仓库。

这样项目维护者可以接受任何开发者的提交,但无需给他正式代码库的写权限。

效果就是一个分布式的工作流,能为大型、自发性的团队(包括了不受信的第三方)提供灵活的方式来安全的写作。

也让这个工作流称为开源项目的理想工作流。

工作方式

和其他的Git工作流一样,Forking工作流要先有一个公开的正式仓库存储在服务器上,但一个新的开发者想要在项目上工作时,不是直接从正式仓库克隆,而是fork正式项目在服务器上创建一个拷贝。

这个仓库拷贝作为他人公开仓库-----其他开发者不允许push到这个仓库,但可以pull到修改(后面很快就会看到这点很重要)。

在创建了自己服务端拷贝之后,和之前的工作流一样,开发者执行git clone命令克隆仓库到本地机器上,作为私有的开发环境。

要提交本地修改时,push提交到自己公开仓库中-------而不是正式仓库中。

然后,给正式仓库发起一个pull request,让项目维护者知道有更新已经准备好可以集成了。

对于贡献的代码,pull request也可以很方便地作为一个讨论的地方。

为了集成功能到正式代码库,维护者pull贡献者的变更到自己的本地仓库中,检查变更以确保不会让项目出错,合并变更到自己本地的master分支,然后push master分支到服务器的正式仓库中。

到此,贡献的提交成为了项目的一部分,其他的开发者应该执行pull操作与正式仓库同步自己本地仓库。

正式仓库

在Forking工作流中,【官方】仓库的叫法只是一个约定,理解这点很重要。

从技术上来看,各个开发者仓库和正式仓库在Git卡那里没有任何区别。

事实上,让正式仓库之所以正式的唯一原因是他是项目维护者的公开仓库。

Forking工作流的分支使用方式

所有的个人公开仓库实际商只是为了方便和其他的开发者共享分支。

各个开发者应该用分支隔离各个功能,就像功能分支工作流和GitFlow工作流一样。

唯一的区别是这些分支被共享了。

在Forking工作流中这些分支会被pull到另一个开发者的本地仓库中,而在功能分支工作流和GitFlow工作流中是直接被push到正式仓库当中。

示例

项目维护者初始化正式仓库

和任何使用Git项目一样,第一步还是创建在服务器上一个正式仓库,让所有团队成员都可以访问到。

通常这个仓库也会作为项目维护者的公开仓库。

公开仓库应该是裸仓库,不管是不是正式代码库。

所以项目维护者会运行像下面的命令来搭建正式仓库:

ssh user@host
git init --bare /path/to/repo.git

Bitbucket和Stash提供了一个方便的GUI客户端已完成上面命令行做的事。

这个搭建中央仓库的过程和前面提到的工作流完全一样。

如果有现存的代码库,维护者也要push到这个仓库中。

开发者fork正式仓库

其他所有的开发需要fork正式仓库。

可以用git clone命令用SSH协议连通到服务器,拷贝仓库到服务器另一个位置-----是的,fork操作基本上就只是一个服务端的克隆。

Bitbucket和Stash上可以点一下按钮就让开发者完成仓库的fork操作。

这一步完成后,每个开发都在服务端有一个自己的仓库。

和正式仓库一样,这些仓库应该是裸仓库。

开发者克隆自己fork出来的仓库

下一步,各个开发者要克隆自己的公开仓库,用熟悉的git clone命令。

在这个示例中,假定用Bitbucket托管了仓库。

记住,如果这样的话各个开发者需要有各自的Bitbucket账号,使用下面命令克隆服务端自己的仓库。

git clone https://user@bitbucket.org/user/repo.git

相比前面介绍的工作流只用了一个origin远程别名指向中央仓库,Forking工作流需要2个远程别名-------一个指向正式仓库,另一个指向开发者自己的服务端仓库。

别名的名字可以任意命名,常见的约定是使用origin作为远程克隆的仓库的别名(这个别名会在运行git clone自动创建),upstream(上游)作为正式仓库的别名。

git remote add upstream https://bitbucket.org/maintainer/repo

需要自己用上面的命令创建upstream别名。

这样可以简单地保持本地仓库和正式仓库的同步更新。

注意,如果上游仓库需要认证(比如不是开源的),你需要提供用户:

git remote add upstream https://user@bitbucket.org/maintainer/repo

这时在克隆和pull正式仓库时,需要提供用户的密码。

开发者开发自己的功能

在刚克隆的本地仓库中,开发者可以向其他工作流一样的编辑代码、提交修改和新建分支:

git checkout -b some-feature
// Edit some code
git commit -a -m "Add first draft of some feature"

所有的修改都是私有的直到push到自己公开仓库中。

如果正式项目已经向前走了,可以用git pull命令获得新的提交:

git pull upstream master

由于开发者应该都在专门的功能分支上工作,pull操作结果会都是快进合并。

开发者发布自己的功能

一旦开发者准备好了分享新功能,需要做两件事。

(1)首先,通过push他的贡献代码到自己的公开仓库中,让其他的开发者都可以访问到。他的origin远程别名应该已经有了,所有要做的就是:

git push origin  feature-branch

这里和之前的工作流的差异是,origin远程别名指向开发者自己的服务端仓库,而不是正式仓库。

(2)第二件事,开发者要通知项目维护者,想要合并他的新功能到正式库中。Bitbucket和Stash提供了Pull Request按钮,弹出个表单让你指定哪个分支要合并到正式仓库。一般你会想集成你的功能分支到上游远程仓库的master分支中。

项目维护者集成开发者的功能

当项目维护者收到pull request时,他要做的是决定是否集成它到正式代码库中。

有两种方式来做:

  • 直接在pull request中查看代码
  • pull代码到他自己的本地仓库,再手动合并

第一种做法更简单,维护者可以在GUI中查看变更的差异,做评注和执行合并。

但如果出现了合并冲突,需要第二种做法来解决。

这种情况下,维护者需要从开发者的服务端仓库中fetch功能分支,合并到他本地的master分支,解决冲突:

git fetch https://bitbucket.org/user/repo feature-branch
//查看变更
git checkout master
git merge FETCH_HEAD

变更集成到本地的master分支后,维护者要push变更到服务器上的正式仓库,这样其他的开发者都能访问到:

git push origin master

注意,维护者的origin是指向他自己公开仓库的,即是项目的正式代码库。

到此,开发者的贡献完全集成到了项目中。

开发者和正式仓库做同步

由于正式代码库往前走了,其他的开发需要和正式仓库做同步:

git pull upstream master

总结

如果你之前是使用SVN,Forking工作流可能看起来像是一个激进的范式切换(paradigm shift)。

但是不要害怕,这个工作流实际上就是在功能分支工作流之上引入了另一个抽象层。

不是直接通过单个中央仓库来分享分支,而是把贡献代码发布到开发者自己的服务端仓库中。

示例中解释了,一个贡献如何从一个开发者流到正式的master分支中,但是同样的方法可以把贡献集中到任意一个仓库中。

比如,如果团队的几个人协作实现一个功能,可以在开发之间用相同的方法分享变更,完全不涉及正式仓库。

这使得Forking工作流对于松散组织的团队来说是个非常强大的工具。

任一开发者可以方便地和另一开发者分享变更,任何分支都能有效地合并到正式代码库中。

Pull Requests

Pull Requests 是Bitbucket上方便开发者之间协作的功能。

提供了一个用户友好的Web界面,在集成提交的变更到正式向目前可以对变更进行讨论。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S7VXTVqn-1616635519613)(http://r.photo.store.qq.com/psc?/V13IdniL4CDhqM/TCfiP1YaPeRT4Jil9RANX1zLLMp65VmnavK5XDJUKS6zYUJDvvIJNLt1FNUoIJG0DkTCKRNuOGToGtjWmjIrVLufSpHVogAtzO4DgCm80!/r)]

开发者向团队成员通知功能开发已经完成,pull Requests是最简单的用法。

开发者完成功能开发后,通过Bitbucket账号发起一个pull Request。这样让涉及这个功能的所有人知道,要去做Code Review和合并到master分支。

但是,Pull Request远不止一个简单的通知,而是为讨论提交的功能的一个专门论坛。

如果变更有任何问题,团队成员反馈在Pull Request中,甚至pull新的提交微调功能。

所有的这些活动都直接跟踪在Pull Request中。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jrkhUmxB-1616635519614)(http://r.photo.store.qq.com/psc?/V13IdniL4CDhqM/TCfiP1YaPeRT4Jil9RANX7SLIJSUYxrmcZpwuXYsQB1Ya2zpcBawWJ7atpdZcoSsGWSrxt3XnkjpSfeaAffmHrs3SyEpgZCaBKHAdN3ReSA!/r)]

相比其他的协作模型,这种分享提交的形式有助于打造一个更流畅的工作流。

SVN和Git都能通过一个简单的脚本收到通知邮件;

但是,讨论变更时,开发者通常只能去回复邮件。

这样做会变得杂乱,尤其还要涉及后面的几个提交时。

Pull Requests吧所有相关功能整合到一个和Bitbucket仓库界面集成的用户友好Web界面中。

解析Pull Request

当腰发起一个pull Request,你所要做的就是请求(Request)另一个开发者(比如项目的维护者),来pull你仓库中一个分支到他的仓库中。

这意味着你要提供4个信息(源仓库、源分支、目的仓库、目的分支),以发起Pull Request。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C1kS5kVr-1616635519615)(http://r.photo.store.qq.com/psc?/V13IdniL4CDhqM/TCfiP1YaPeRT4Jil9RANX7SLIJSUYxrmcZpwuXYsQB1Ya2zpcBawWJ7atpdZcoSsGWSrxt3XnkjpSfeaAffmHrs3SyEpgZCaBKHAdN3ReSA!/r)]

工作方式

Pull Request可以和功能分支工作流、GitFlow工作流或Forking工作流一起使用。

但Pull Request要求要么分支不同,要么仓库不同,所以不能用于集中式工作流。

在不同的工作流中使用pull Request会有一些不同,但基本的过程是这样的:

  • 开发者在本地仓库新建一个专门的分支开发功能;
  • 开发者push分支修改到公开的Bitbucket仓库中;
  • 开发者通过Bitbucket发起一个Pull Request;
  • 团队的其他成员review code,讨论并修改;
  • 项目维护者合并功能到官方仓库中并关闭Pull Request;

在功能分支工作流中使用Pull Request

功能分支工作流用一个共享的Bitbucket仓库来管理协作,开发者在专门的分支上开发功能。

但不是立即合并到master分支上,而是在合并到主代码之前开发这应该开一个Pull Request发起功能的讨论。

功能分支工作流只有一个公开的仓库,所以Pull Request的目的仓库和源仓库总是同一个。

通常开发者会指定他的功能分支作为源分支,master分支作为目的分支。

收到Pull Request后,项目维护者要决定如何做。

如果功能没问题,就简单地合并到master分支,关闭Pull Request。

但如果提交的变更有问题,他可以在Pull Request中反馈,之后的新加的评论也会评论之后接着显示出来。

在功能还没有完全开发完的时候,也可能发起一个pull Request。

比如开发者在实现某个需求时遇到了麻烦。

他可以发一个包含正在进行工作的Pull Request。

其他的开发者可以在Pull Request提供建议,或者甚至直接添加提交来解决问题。

在GitFlow工作流中使用Pull Request

GitFlow工作流和功能分支工作流类似,单围绕项目发布定义一个严格的分支模型。

在GitFlow工作流中使用Pull Request让开发者在发布分支或者是维护分支上工作时,可以有个方便的地方对关于发布分支或者是维护分支的问题进行交流。

GitFlow工作流中Pull Request的使用过程和上一节中完全一致:当一个功能、发布或者是热修复分支需要Review时,开发者简单发起一个Pull Request,团队的其他成员会通过Bitbucket收到通知。

新功能一般合并到develop分支,而发布和热修复则要同时合并到develop分支和master分支上。

Pull Request可能用作所有合并的正式管理。

在Forking工作流中使用Pull Request

在Forking工作流中,开发者push完成的功能到他自己的仓库中,而不是共享仓库。

然后,他发一个Pull Request,让项目维护者知道他的功能已经可以Review了。

在这个工作流,Pull Request的通知功能非常有用,因为项目维护者不可能知道其他开发者在他们自己的仓库添加了提交。

由于各个开发者有自己的公开仓库,Pull Request的源仓库和目标仓库不是同一个。

源仓库是开发者的公开仓库,源分支是包含了修改的分支。

如果开发者要合并修改到正式代码库中,那么目标仓库是正式仓库,目标分支是master分支。

Pull Request也可以用于正式项目之外的其他开发者之间的协作。

比如,如果一个开发者和一个团队成员一起开发一个功能,他们可以发起一个Pull Request,用团队成员的Bitbucket仓库作为目标,而不是正式项目的仓库。

然后使用相同的功能分支作为源和目标分支。

2个开发者之间可以在Pull Request中讨论和开发功能。

完成开发后,他们可以发起另一个Pull Request,请求合并功能到正式的master分支。

在Forking工作流中,这样的灵活性称为一个强有力的协作工具。

示例

下面的示例演示了Pull Request如何在Forking工作流中使用。

也同样适用于小团队的开发协作和第三方开发者向开源项目的贡献。

在示例中,小红是个开发,小明是项目维护者。

他们各自有一个公开的Bitbucket仓库,而小明的仓库包含了正式工程。

小红fork正式项目

小红先要fork小明的Bitbucket仓库,开始项目的开发。

她登录Bitbucket,浏览到小明的仓库页面,点fork按钮。

然后为fork出来的仓库填写名字和描述,这样小红就有了服务端的项目拷贝了。

小红克隆她的Bitbucket仓库

下一步,小红克隆自己刚才fork出来的Bitbucket仓库,以在本机上准备出工作拷贝。

命令如下:

git clone https://user@bitbucket.org/user/repo.git

请记住,git clone 会自动创建origin远程别名,是指向小红fork出来的仓库。

小红开发新功能

在开始改代码前,小红要为新功能新建一个新分支。

她会用这个分支作为Pull Request的源分支。

git checkout -b some-feature
编辑代码
git commit -a -m "Add first draft of some feature"

在新功能分支上,小红按照需要添加提交。

甚至如果小红觉得功能分支上的提交历史太乱了,她可以用交互式rebase来删除或者压制提交。

对于大型项目,整理功能分支的历史可以让项目维护者更容易看出在pull Request中做了什么内容。

小红push功能到她的Bitbucket仓库中

小红完成功能后,push功能到她自己的Bitbucket仓库中(不是正是仓库),用下面简单的命令。

git push origin some-branch

这时她的变更可以让项目维护者看到了(后者任何想要看的协作者)

小红发起Pull Request

Bitbucket上有了她的功能分支后,小红可以用她的Bitbucket账号浏览到她fork出来的仓库页面,点右上角的[ Pull Request ]按钮,发起一个Pull Request。

弹出的表单自动设置小红的仓库为源仓库,询问小红以指定源分支、目标仓库和目标分支。

小红想要合并功能到正式仓库,所以源分支是她的功能分支,目标仓库是小明的公开仓库,而目标分支是master分支。

另外,小红需要提供Pull Request的标题和描述信息。

如果需要小明以外的人审核批准diamante,她可以把这些人填在[ Reviewers ]文本框中。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6TxPoIQk-1616635519616)(http://r.photo.store.qq.com/psc?/V13IdniL4CDhqM/TCfiP1YaPeRT4Jil9RANX4eBUNEH.PnD8cXLFX3FNQ1TY28uOV3j2Ic*FLo6qk1HERoVGDzy.ccPi6KWHQ1Ha7aF4qrprhr6a71aswRPe1s!/r)]

创建好了Pull Request,通知会通过Bitbucket系统消息或者邮件(可选)发给小明。

小明 review Pull Request

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QA0Nehkp-1616635519617)(http://r.photo.store.qq.com/psc?/V13IdniL4CDhqM/TCfiP1YaPeRT4Jil9RANXz.TEdJt9fHfFvRXRaihUCZBZl8OSFD1T7r7GIRRSRDePO5EI5YO0pxG7Qo02eHht0.LfxlnFiUPPKgPzRY4U!/r)]

在小明的Bitbucket仓库页面的[ Pull Request ]Tab可以看到所有人发起的Pull Request。

点击小红的Pull Request会显示Pull Request的描述、功能的提交历史和每个变更的差异(diff)。

如果小明想要合并到项目中,只要点一下[ Merge ]按钮,就可以同意Pull Request并合并到master分支。

但如果像这个示例中一样,小明发现了在小红的代码中的一个小Bug,要在小红合并前修复。

小明可以在整个Pull Request上加上评注,或者是选择历史中的某个提交加上评注。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eEASrctv-1616635519618)(http://r.photo.store.qq.com/psc?/V13IdniL4CDhqM/TCfiP1YaPeRT4Jil9RANXywJcEdXUnF5drr2Tn8vpOshxucsOMz.iW9qg*vXiM80CBz6VcPZTn4e7NC2txFi9Xf.oe9HyW39vilYdBhizv0!/r)]

小红补加提交

如果小红对反馈有任何疑问,可以在Pull Request中响应,把Pull Request当做是她功能讨论的论坛。

小红在她的功能分支新加提交以解决代码问题,并push到她的Bitbucket仓库中,就像前一轮中的做饭一样。

这些提交会进入到Pull Request,小明在原来的评注旁边可以再次Review 变更。

小明接受Pull Request

最终,小明接受变更,合并功能分支到master分支,并关闭Pull Request。

至此,功能集成到项目中,其他的项目开发者可以用标准的git pull命令pull这些变更到自己的本地仓库中。

总结

到了这里,你应该有了所有需要的工具来集成Pull Request到你自己的工作流。

请记住,Pull Request并不是为了替代任何基于Git的协作工作流,而是它们的一个便利的补充,让团队成员间的协作更加轻松方便。

Git工作流学习笔记相关推荐

  1. 《Got Git》学习笔记(一)

    <Got Git>学习笔记(一) 最近想对自己的代码和文档进行归档整理,需要一个版本控制系统来进行 处理.自然而然的想到了目前流行的GitHub. GitHub,是一个面向开源及私有软件项 ...

  2. Activiti工作流学习笔记01

    Activiti6工作流学习笔记01 activiti工作流目前官方最新版本是7.x,但....版本不重要了.这篇笔记只是我学习activiti6过程中的自我总结.如果笔记上有错误的话,欢迎赐教,谢谢 ...

  3. git的学习笔记(二):git远程操作

    git的学习笔记(一):git本地操作 1.创建ssh key ssh-keygen -t rsa -C "your_email@example.com" 执行命令后会在用户的家目 ...

  4. Git 个人学习笔记及心得

    作为程序员如果你还不知道 Git 和 GitHub,说不过去吧,赶紧来学习一波. 一.认识GitHub Git 是个版本控制系统,说明白点就是进行代码的各种管理,比如你写错代码进行回滚啊.追寻 Bug ...

  5. Learn Git Branching 学习笔记(移动提交记录篇)

    目录 一.移动提交记录篇 1.Git Cherry-pick 2.交互式rebase Git用法高级篇在上一篇文章中Learn Git Branching 学习笔记(高级篇)_流年--by gone的 ...

  6. Learn Git Branching 学习笔记(高级话题篇)

    目录 一.高级话题篇 1.多分支rebase 2.选择父提交记录 3.纠缠不清的分支 Git的一些技术.技巧与贴士集合在上一篇文章中 Learn Git Branching 学习笔记(Git 技术.技 ...

  7. git/github学习笔记

    原文地址为: git/github学习笔记 请移步到:http://www.testclass.net/git/ ----- 我重新对git/github教程进行了编排和整理. 1. git 版本控制 ...

  8. git serialtool_Git学习笔记---协作的一般流程

    一般的操作流程 1.pull 王小坤与另一个同事张大炮一起开发一个项目,张大炮昨天修改了数据库读写的api,优化了执行速度,并把read()函数改名成了Read(),下午下班之前把这些代码push到服 ...

  9. 廖雪峰Git教程学习笔记

    廖雪峰git简单教程学习笔记 教程地址:https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b ...

最新文章

  1. 机器学习虽好,也要看什么场合!
  2. oracle10.2 管理工具,Oracle 10.2.0.5 EM管理器的BUG
  3. 【Linux 内核】进程管理 task_struct 结构体 ⑤ ( files 字段 | nsproxy 字段 | 信号处理相关字段 | 信号量和共享内存相关字段 )
  4. POJ 3159 Candies
  5. (HY000): Cannot modify @@session.sql_log_bin inside a transaction
  6. php asp 发起post请求,PHP用curl函数POST请求到ASP页面提示无效请求
  7. Android 网络协议
  8. ORA-01078: failure in processing system parameters
  9. 电池pack结构_锂电池pack性能测试标准,电池测试模组就选弹片微针模组
  10. Java TCP案例网络聊天室
  11. centos服务器之间copy文件夹命令,Centos下如何拷贝整个目录命令?Centos下拷贝目录命令的方法...
  12. TOC约束理论AUTOCAD技巧
  13. PIXI 宝物猎人(7)
  14. CDPSE-数据隐私解决方案工程师
  15. mysql出现core dumped_mysql 段错误 (core dumped)
  16. 上海税前12000的工资,税后能拿到多少?
  17. 上古卷轴3晨风职业_上古卷轴3晨风
  18. 计算机游戏教学中教师,计算机游戏教学法在信息技术教学中的运用
  19. spring的ioc和di
  20. 20162330 第六周 蓝墨云班课 队列课下作业

热门文章

  1. 算法设计与分析之回溯法
  2. 无线AP中小型、大型两种常见组网方式
  3. 空军某部一次有趣的飞行事故
  4. 山东十大计算机排名2015,2015山东省大学专业排名
  5. AI认知架构四十年的发展与挑战
  6. 考研数学核心知识点总结
  7. Spring深入学习笔记
  8. UC缓存的php格式视频,如何把UC浏览器缓存的零碎视频转换成完整的mp4
  9. 精品绿色便携软件下载站
  10. Swarm mode环境模型-小结篇