深刻理解学习Git工做流,程序猿必看。

我的在学习git工做流的过程当中,从原有的 SVN 模式很难彻底理解git的协做模式,直到有一天我看到了下面的文章,好多遗留在心中的困惑迎刃而解,因而我将这部分资料进行整理放到了github上,欢迎star查看最新更新内容, https://github.com/xirong/my-...css

咱们以使用SVN的工做流来使用git有什么不妥?
git 方便的branch在哪里,团队多人如何协做?冲突了怎么办?如何进行发布控制?
经典的master-发布、develop-主开发、hotfix-不过修复如何避免代码不通过验证上线?
如何在github上面与他人一块儿协做,star-fork-pull request是怎样的流程?

我我的很感激这篇文章,因此进行了整理,但愿能帮到更多的人。整篇文章由 xirong 整理自 oldratlee 的github,方便统一的学习回顾,在此感谢下面两位的贡献。python

原文连接:Git Workflows and Tutorials
简体中文:由 oldratlee 翻译在 github 上 git-workflows-and-tutorials
1、译序git

工做流其实不是一个初级主题,背后的本质问题实际上是有效的项目流程管理和高效的开发协同约定,不只是Git或SVN等VCS或SCM工具的使用。github

这篇指南以你们在SVN中已经广为熟悉使用的集中式工做流做为起点,按部就班地演进到其它高效的分布式工做流,还介绍了如何配合使用便利的Pull Request功能,体系地讲解了各类工做流的应用。安全

行文中实践原则和操做示例并重,对于Git的资深玩家能够梳理思考提高,而新接触的同窗,也能够跟着step-by-step操做来操练学习并在实际工做中上手使用。服务器

关于Git工做流主题,网上体系的中文资料很少,主要是零散的操做说明,但愿这篇文章能让你更深刻理解并在工做中灵活有效地使用起来。并发

PS:app

文中Pull Request的介绍用的是Bitbucket代码托管服务,因为和GitHub基本同样,若是你用的是GitHub(我本身也主要使用GitHub托管代码),不影响理解和操做。python爬虫

PPS:框架

本指南按部就班地讲解工做流,若是Git用的很少,能够从前面的讲的工做流开始操练。操做过程去感觉指南的讲解:解决什么问题、如何解决问题,这样理解就深了,也方便活用。

Gitflow工做流是经典模型,体现了工做流的经验和精髓。随着项目过程复杂化,会感觉到这个工做流中深思熟虑和威力!

Forking工做流是协做的(GitHub风格)能够先看看Github的Help:Fork A Repo和Using pull requests 。照着操做,给一个Github项目贡献你的提交,有操做经验再看指南容易意会。指南中给了本身实现Fork的方法:Fork就是服务端的克隆。在指南的操练中使用代码托管服务(如GitHub、Bitbucket),能够点一下按钮就让开发者完成仓库的fork操做。

本身理解粗浅,翻译中不足和不对之处,欢迎建议(提交Issue)和指正(Fork后提交代码)!
2、Git工做流指南

工做流有各式各样的用法,但也正所以使得在实际工做中如何上手使用变得很头大。这篇指南经过总览公司团队中最经常使用的几种Git工做流让你们能够上手使用。

在阅读的过程当中请记住,本文中的几种工做流是做为方案指导而不是条例规定。在展现了各类工做流可能的用法后,你能够从不一样的工做流中挑选或揉合出一个知足你本身需求的工做流。
这里写图片描述
2.1 集中式工做流
若是你的开发团队成员已经很熟悉Subversion,集中式工做流让你无需去适应一个全新流程就能够体验Git带来的收益。这个工做流也能够做为向更Git风格工做流迁移的友好过渡。
这里写图片描述
转到分布式版本控制系统看起来像个使人生畏的任务,但不改变已用的工做流你也能够用上Git带来的收益。团队能够用和Subversion彻底不变的方式来开发项目。

但使用Git增强开发的工做流,Git有相比SVN的几个优点。
首先,每一个开发能够有属于本身的整个工程的本地拷贝。隔离的环境让各个开发者的工做和项目的其余部分修改独立开来 ——
即自由地提交到本身的本地仓库,先彻底忽略上游的开发,直到方便的时候再把修改反馈上去。

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

2.1.1 工做方式
像Subversion同样,集中式工做流以中央仓库做为项目全部修改的单点实体。相比SVN缺省的开发分支trunk,Git叫作master,全部修改提交到这个分支上。本工做流只用到master这一个分支。

开发者开始先克隆中央仓库。在本身的项目拷贝中像SVN同样的编辑文件和提交修改;但修改是存在本地的,和中央仓库是彻底隔离的。开发者能够把和上游的同步延后到一个方便时间点。

要发布修改到正式项目中,开发者要把本地master分支的修改『推』到中央仓库中。这至关于svn commit操做,但push操做会把全部还不在中央仓库的本地提交都推上去。
这里写图片描述
2.1.2 冲突解决
中央仓库表明了正式项目,因此提交历史应该被尊重且是稳定不变的。若是开发者本地的提交历史和中央仓库有分歧,Git会拒绝push提交不然会覆盖已经在中央库的正式提交。
这里写图片描述
在开发者提交本身功能修改到中央库前,须要先fetch在中央库的新增提交,rebase本身提交到中央库提交历史之上。
这样作的意思是在说,『我要把本身的修改加到别人已经完成的修改上。』最终的结果是一个完美的线性历史,就像之前的SVN的工做流中同样。

若是本地修改和上游提交有冲突,Git会暂停rebase过程,给你手动解决冲突的机会。Git解决合并冲突,用和生成提交同样的git status和git add命令,很一致方便。还有一点,若是解决冲突时遇到麻烦,Git能够很简单停止整个rebase操做,重来一次(或者让别人来帮助解决)。

2.1.3 示例
让咱们一块儿逐步分解来看看一个常见的小团队如何用这个工做流来协做的。有两个开发者小明和小红,看他们是如何开发本身的功能并提交到中央仓库上的。
有人先初始化好中央仓库

这里写图片描述

第一步,有人在服务器上建立好中央仓库。若是是新项目,你能够初始化一个空仓库;不然你要导入已有的Git或SVN仓库。

中央仓库应该是个裸仓库(bare repository),即没有工做目录(working directory)的仓库。能够用下面的命令建立:

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

确保写上有效的user(SSH的用户名),host(服务器的域名或IP地址),/path/to/repo.git(你想存放仓库的位置)。
注意,为了表示是一个裸仓库,按照约定加上.git扩展名到仓库名上。

全部人克隆中央仓库
这里写图片描述
下一步,各个开发者建立整个项目的本地拷贝。经过git clone命令完成:

git clone ssh://user@host/path/to/repo.git
基于你后续会持续和克隆的仓库作交互的假设,克隆仓库时Git会自动添加远程别名origin指回『父』仓库。

小明开发功能

这里写图片描述

在小明的本地仓库中,他使用标准的Git过程开发功能:编辑、暂存(Stage)和提交。
若是你不熟悉暂存区(Staging Area),这里说明一下:暂存区的用来准备一个提交,但能够不用把工做目录中全部的修改内容都包含进来。
这样你能够建立一个高度聚焦的提交,尽管你本地修改不少内容。

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

请记住,由于这些命令生成的是本地提交,小明能够按本身需求反复操做屡次,而不用担忧中央仓库上有了什么操做。
对须要多个更简单更原子分块的大功能,这个作法是颇有用的。

小红开发功能

这里写图片描述

与此同时,小红在本身的本地仓库中用相同的编辑、暂存和提交过程开发功能。和小明同样,她也不关心中央仓库有没有新提交;
固然更不关心小明在他的本地仓库中的操做,由于全部本地仓库都是私有的。

小明发布功能

这里写图片描述

一旦小明完成了他的功能开发,会发布他的本地提交到中央仓库中,这样其它团队成员能够看到他的修改。他能够用下面的git push命令:

git push origin master
注意,origin是在小明克隆仓库时Git建立的远程中央仓库别名。master参数告诉Git推送的分支。
因为中央仓库自从小明克隆以来尚未被更新过,因此push操做不会有冲突,成功完成。

小红试着发布功能

这里写图片描述

一块儿来看看在小明发布修改后,小红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
--rebase选项告诉Git把小红的提交移到同步了中央仓库修改后的master分支的顶部,以下图所示:

这里写图片描述

若是你忘加了这个选项,pull操做仍然能够完成,但每次pull操做要同步中央仓库中别人修改时,提交历史会以一个多余的『合并提交』结尾。
对于集中式工做流,最好是使用rebase而不是生成一个合并提交。

小红解决合并冲突

这里写图片描述

rebase操做过程是把本地提交一次一个地迁移到更新了的中央仓库master分支之上。
这意味着可能要解决在迁移某个提交时出现的合并冲突,而不是解决包含了全部提交的大型合并时所出现的冲突。
这样的方式让你尽量保持每一个提交的聚焦和项目历史的整洁。反过来,简化了哪里引入Bug的分析,若是有必要,回滚修改也能够作到对项目影响最小。

若是小红和小明的功能是相关的,不大可能在rebase过程当中有冲突。若是有,Git在合并有冲突的提交处暂停rebase过程,输出下面的信息并带上相关的指令:

CONFLICT (content): Merge conflict in <some-file>

这里写图片描述

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 <some-file>
git rebase --continue就这些了。Git会继续一个一个地合并后面的提交,如其它的提交有冲突就重复这个过程。

若是你碰到了冲突,但发现搞不定,不要惊慌。只要执行下面这条命令,就能够回到你执行git pull --rebase命令前的样子:

git rebase --abort

小红成功发布功能

这里写图片描述

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

git push origin master
如你所见,仅使用几个Git命令咱们就能够模拟出传统Subversion开发环境。对于要从SVN迁移过来的团队来讲这太好了,但没有发挥出Git分布式本质的优点。

若是你的团队适应了集中式工做流,但想要更流畅的协做效果,绝对值得探索一下 功能分支工做流 的收益。
经过为一个功能分配一个专门的分支,可以作到一个新增功能集成到正式项目以前对新功能进行深刻讨论。

2.2 功能分支工做流
功能分支工做流以集中式工做流为基础,不一样的是为各个新功能分配一个专门的分支来开发。这样能够在把新功能集成到正式项目前,用Pull Requests的方式讨论变动。

这里写图片描述
这里写图片描述

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

功能分支工做流背后的核心思路是全部的功能开发应该在一个专门的分支,而不是在master分支上。
这个隔离能够方便多个开发者在各自的功能上开发而不会弄乱主干代码。
另外,也保证了master分支的代码必定不会是有问题的,极大有利于集成环境。

功能开发隔离也让pull requests工做流成功可能,
pull requests工做流能为每一个分支发起一个讨论,在分支合入正式项目以前,给其它开发者有表示赞同的机会。
另外,若是你在功能开发中有问题卡住了,能够开一个pull requests来向同窗们征求建议。
这些作法的重点就是,pull requests让团队成员之间互相评论工做变成很是方便!

2.2.1 工做方式
功能分支工做流仍然用中央仓库,而且master分支仍是表明了正式项目的历史。
但不是直接提交本地历史到各自的本地master分支,开发者每次在开始新功能前先建立一个新分支。
功能分支应该有个有描述性的名字,好比animated-menu-items或issue-#1061,这样可让分支有个清楚且高聚焦的用途。

在master分支和功能分支之间,Git是没有技术上的区别,因此开发者能够用和集中式工做流中彻底同样的方式编辑、暂存和提交修改到功能分支上。

另外,功能分支也能够(且应该)push到中央仓库中。这样不修改正式代码就能够和其它开发者分享提交的功能。
因为master仅有的一个『特殊』分支,在中央仓库上存多个功能分支不会有任何问题。固然,这样作也能够很方便地备份各自的本地提交。

2.2.2 Pull Requests
功能分支除了能够隔离功能的开发,也使得经过Pull Requests讨论变动成为可能。
一旦某个开发完成一个功能,不是当即合并到master,而是push到中央仓库的功能分支上并发起一个Pull Request请求去合并修改到master。
在修改为为主干代码前,这让其它的开发者有机会先去Review变动。

Code Review是Pull Requests的一个重要的收益,但Pull Requests目的是讨论代码一个通用方式。
你能够把Pull Requests做为专门给某个分支的讨论。这意味着能够在更早的开发过程当中就能够进行Code Review。
好比,一个开发者开发功能须要帮助时,要作的就是发起一个Pull Request,相关的人就会自动收到通知,在相关的提交旁边能看到须要帮助解决的问题。

一旦Pull Request被接受了,发布功能要作的就和集中式工做流就很像了。
首先,肯定本地的master分支和上游的master分支是同步的。而后合并功能分支到本地master分支并push已经更新的本地master分支到中央仓库。

仓库管理的产品解决方案像Bitbucket或Stash,能够良好地支持Pull Requests。能够看看Stash的Pull Requests文档。

2.2.3 示例
下面的示例演示了如何把Pull Requests做为Code Review的方式,但注意Pull Requests能够用于不少其它的目的。

小红开始开发一个新功能

这里写图片描述

在开始开发功能前,小红须要一个独立的分支。使用下面的命令新建一个分支:

git checkout -b marys-feature master
这个命令检出一个基于master名为marys-feature的分支,Git的-b选项表示若是分支还不存在则新建分支。
这个新分支上,小红按老套路编辑、暂存和提交修改,按须要提交以实现功能:

git status
git add <some-file>
git commit

小红要去吃个午餐

这里写图片描述

早上小红为新功能添加一些提交。
去吃午餐前,push功能分支到中央仓库是很好的作法,这样能够方便地备份,若是和其它开发协做,也让他们能够看到小红的提交。

git push -u origin marys-feature

这条命令push marys-feature分支到中央仓库(origin),-u选项设置本地分支去跟踪远程对应的分支。
设置好跟踪的分支后,小红就可使用git push命令省去指定推送分支的参数。

小红完成功能开发

这里写图片描述

小红吃完午餐回来,完成整个功能的开发。在合并到master以前,
她发起一个Pull Request让团队的其它人知道功能已经完成。但首先,她要确认中央仓库中已经有她最近的提交:

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工做流是管理功能开发、发布准备和维护的经常使用模式。

2.3 Gitflow工做流
Gitflow工做流经过为功能开发、发布准备和维护分配独立的分支,让发布迭代过程更流畅。严格的分支模型也为大型项目提供了一些很是必要的结构。

这里写图片描述

这节介绍的Gitflow工做流借鉴自在nvie的Vincent Driessen。

Gitflow工做流定义了一个围绕项目发布的严格分支模型。虽然比功能分支工做流复杂几分,但提供了用于一个健壮的用于管理大型项目的框架。

Gitflow工做流没有用超出功能分支工做流的概念和命令,而是为不一样的分支分配一个很明确的角色,并定义分支之间如何和何时进行交互。
除了使用功能分支,在作准备、维护和记录发布也使用各自的分支。
固然你能够用上功能分支工做流全部的好处:Pull Requests、隔离实验性开发和更高效的协做。

2.3.1 工做方式
Gitflow工做流仍然用中央仓库做为全部开发者的交互中心。和其它的工做流同样,开发者在本地工做并push分支到要中央仓库中。

2.3.2 历史分支
相对使用仅有的一个master分支,Gitflow工做流使用2个分支来记录项目的历史。master分支存储了正式发布的历史,而develop分支做为功能的集成分支。
这样也方便master分支上的全部提交分配一个版本号。

这里写图片描述

剩下要说明的问题围绕着这2个分支的区别展开。

2.3.3 功能分支
每一个新功能位于一个本身的分支,这样能够push到中央仓库以备份和协做。
但功能分支不是从master分支上拉出新分支,而是使用develop分支做为父分支。当新功能完成时,合并回develop分支。
新功能提交应该从不直接与master分支交互

这里写图片描述

注意,从各类含义和目的上来看,功能分支加上develop分支就是功能分支工做流的用法。但Gitflow工做流没有在这里止步。

2.3.4 发布分支

这里写图片描述

一旦develop分支上有了作一次发布(或者说快到了既定的发布日)的足够功能,就从develop分支上fork一个发布分支。
新建的分支用于开始发布循环,因此从这个时间点开始以后新的功能不能再加到这个分支上——
这个分支只应该作Bug修复、文档生成和其它面向发布任务。
一旦对外发布的工做都完成了,发布分支合并到master分支并分配一个版本号打好Tag。
另外,这些重新建发布分支以来的作的修改要合并回develop分支。

使用一个用于发布准备的专门分支,使得一个团队能够在完善当前的发布版本的同时,另外一个团队能够继续开发下个版本的功能。
这也打造定义良好的开发阶段(好比,能够很轻松地说,『这周咱们要作准备发布版本4.0』,而且在仓库的目录结构中能够实际看到)。

经常使用的分支约定:

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

2.3.5 维护分支

这里写图片描述

维护分支或说是热修复(hotfix)分支用于生成快速给产品发布版本(production releases)打补丁,这是惟一能够直接从master分支fork出来的分支。
修复完成,修改应该立刻合并回master分支和develop分支(当前的发布分支),master分支应该用新的版本号打好Tag。

为Bug修复使用专门分支,让团队能够处理掉问题而不用打断其它工做或是等待下一个发布循环。
你能够把维护分支想成是一个直接在master分支上处理的临时发布。

2.3.6 示例
下面的示例演示本工做流如何用于管理单个发布循环。假设你已经建立了一个中央仓库。

建立开发分支

这里写图片描述

第一步为master分支配套一个develop分支。简单来作能够本地建立一个空的develop分支,push到服务器上:

git branch develop
git push -u origin develop
之后这个分支将会包含了项目的所有历史,而master分支将只包含了部分历史。其它开发者这时应该克隆中央仓库,建好develop分支的跟踪分支:

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

如今每一个开发都有了这些历史分支的本地拷贝。

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

这里写图片描述

这个示例中,小红和小明开始各自的功能开发。他们须要为各自的功能建立相应的分支。新分支不是基于master分支,而是应该基于develop分支:

git checkout -b some-feature develop
他们用老套路添加提交到各自功能分支上:编辑、暂存、提交:

git status
git add <some-file>
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分支。
冲突解决方法和集中式工做流同样。

小红开始准备发布

这里写图片描述

这个时候小明正在实现他的功能,小红开始准备她的第一个项目正式发布。
像功能开发同样,她用一个新的分支来作发布准备。这一步也肯定了发布的版本号:

git checkout -b release-0.1 develop
这个分支是清理发布、执行全部测试、更新文档和其它为下个发布作准备操做的地方,像是一个专门用于改善发布的功能分支。

只要小红建立这个分支并push到中央仓库,这个发布就是功能冻结的。任何不在develop分支中的新功能都推到下个发布循环中。

小红完成发布

这里写图片描述

一旦准备好了对外发布,小红合并修改到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

这里写图片描述

对外发布后,小红回去和小明一块儿作下个发布的新功能开发,直到有最终用户开了一个Ticket抱怨当前版本的一个Bug。
为了处理Bug,小红(或小明)从master分支上拉出了一个维护分支,提交修改以解决问题,而后直接合并回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为你所用。

2.4 Forking工做流
Forking工做流是分布式工做流,充分利用了Git在分支和克隆上的优点。能够安全可靠地管理大团队的开发者(developer),并能接受不信任贡献者(contributor)的提交。

Forking工做流和前面讨论的几种工做流有根本的不一样,这种工做流不是使用单个服务端仓库做为『中央』代码基线,而让各个开发者都有一个服务端仓库。这意味着各个代码贡献者有2个Git仓库而不是1个:一个本地私有的,另外一个服务端公开的。

这里写图片描述

Forking工做流的一个主要优点是,贡献的代码能够被集成,而不须要全部人都能push代码到仅有的中央仓库中。
开发者push到本身的服务端仓库,而只有项目维护者才能push到正式仓库。
这样项目维护者能够接受任何开发者的提交,但无需给他正式代码库的写权限。

效果就是一个分布式的工做流,能为大型、自发性的团队(包括了不受信的第三方)提供灵活的方式来安全的协做。
也让这个工做流成为开源项目的理想工做流。

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

这个仓库拷贝做为他我的公开仓库 ——
其它开发者不容许push到这个仓库,但能够pull到修改(后面咱们很快就会看这点很重要)。
在建立了本身服务端拷贝以后,和以前的工做流同样,开发者执行git clone命令克隆仓库到本地机器上,做为私有的开发环境。

要提交本地修改时,push提交到本身公开仓库中 —— 而不是正式仓库中。
而后,给正式仓库发起一个pull request,让项目维护者知道有更新已经准备好能够集成了。
对于贡献的代码,pull request也能够很方便地做为一个讨论的地方。

为了集成功能到正式代码库,维护者pull贡献者的变动到本身的本地仓库中,检查变动以确保不会让项目出错,
合并变动到本身本地的master分支,
而后pushmaster分支到服务器的正式仓库中。
到此,贡献的提交成为了项目的一部分,其它的开发者应该执行pull操做与正式仓库同步本身本地仓库。

2.4.2 正式仓库
在Forking工做流中,『官方』仓库的叫法只是一个约定,理解这点很重要。
从技术上来看,各个开发者仓库和正式仓库在Git看来没有任何区别。
事实上,让正式仓库之因此正式的惟一缘由是它是项目维护者的公开仓库。

2.4.3 Forking工做流的分支使用方式
全部的我的公开仓库实际上只是为了方便和其它的开发者共享分支。
各个开发者应该用分支隔离各个功能,就像在功能分支工做流和Gitflow工做流同样。
惟一的区别是这些分支被共享了。在Forking工做流中这些分支会被pull到另外一个开发者的本地仓库中,而在功能分支工做流和Gitflow工做流中是直接被push到正式仓库中。

2.4.4 示例
项目维护者初始化正式仓库
和任何使用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/us...

相比前面介绍的工做流只用了一个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/ma...
这时在克隆和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操做结果会都是快进合并。

开发者发布本身的功能

这里写图片描述

一旦开发者准备好了分享新功能,须要作二件事。
首先,经过push他的贡献代码到本身的公开仓库中,让其它的开发者均可以访问到。
他的origin远程别名应该已经有了,因此要作的就是:

git push origin feature-branch
这里和以前的工做流的差别是,origin远程别名指向开发者本身的服务端仓库,而不是正式仓库。

第二件事,开发者要通知项目维护者,想要合并他的新功能到正式库中。
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工做流对于松散组织的团队来讲是个很是强大的工具。任一开发者能够方便地和另外一开发者分享变动,任何分支都能有效地合并到正式代码库中。

更过资源上就上:去转盘,www.quzhuanpan.com,我创建了一个Q群欢迎你们加入讨论学习js,css,python爬虫等技术(Q群:512245829)。

相关文章
相关标签/搜索