深刻理解学习Git工做流

文/ixirong(简书做者)
原文连接:http://www.jianshu.com/p/91acec85c3a4
著做权归做者所有。转载请联系做者得到受权,并标注“简书做者”。

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

我我的很是感激这篇文章,因此进行了整理,但愿能帮到不少其它的人。git

整篇文章由 xirong 整理自 oldratlee 的github。方便统一的学习回想。在此感谢如下两位的贡献。github

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


1、译序

工做流事实上不是一个0基础主题,背后的本质问题事实上是有效的项目流程管理和高效的开发协同约定,不只是GitSVNVCSSCM工具的使用。安全

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

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

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

PSapp

文中Pull Request的介绍用的是Bitbucket代码托管服务,由于和GitHub基本同样,假设你用的是GitHub(我本身也主要使用GitHub托管代码),不影响理解和操做。框架

PPSssh

本指南按部就班地解说工做流。假设Git用的很少,可以从前面的讲的工做流開始操练。操做过程去感觉指南的解说:解决什么问题、怎样解决这个问题,这样理解就深了,也方便活用。

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

Forking工做流是协做的(GitHub风格)可以先看看Github的Help:Fork A RepoUsing pull requests 。照着操做,给一个Github项目贡献你的提交,有操做经验再看指南easy意会。指南中给了本身实现Fork的方法Fork就是服务端的克隆。在指南的操练中使用代码托管服务(如GitHubBitbucket),可以点一下button就让开发人员完毕仓库的fork操做。

:see_no_evil: 本身理解粗浅。翻译中不足和不正确之处,欢迎建议(提交Issue)和指正(Fork后提交代码)!

2、Git工做流指南

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

在阅读的过程当中请记住,本文中的几种工做流是做为方案指导而不是条例规定。在展现了各类工做流可能的使用方法后,你可以从不一样的工做流中挑选或揉合出一个知足你本身需求的工做流。

Git Workflows
Git Workflows

2.1 集中式工做流

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

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

Git Workflows: SVN-style
Git Workflows: SVN-style

转到分布式版本号控制系统看起来像个使人生畏的任务,但不改变已用的工做流你也可以用上Git带来的收益。团队可以用和Subversion全然不变的方式来开发项目。

但使用Git增强开发的工做流,Git有相比SVN的几个优点。


首先,每个开发可以有属于本身的整个project的本地拷贝。隔离的环境让各个开发人员的工做和项目的其它部分改动独立开来 ——
即自由地提交到本身的本地仓库,先全然忽略上游的开发,直到方便的时候再把改动反馈上去。

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

2.1.1 工做方式

Subversion同样。集中式工做流以中央仓库做为项目所有改动的单点实体。

相比SVN缺省的开发分支trunkGit叫作master。所有改动提交到这个分支上。

本工做流仅仅用到master这一个分支。

开发人员開始先克隆中央仓库。在本身的项目拷贝中像SVN同样的编辑文件和提交改动;但改动是存在本地的。和中央仓库是全然隔离的。开发人员可以把和上游的同步延后到一个方便时间点。

要公布改动到正式项目中。开发人员要把本地master分支的改动『推』到中央仓库中。这至关于svn commit操做。但push操做会把所有还不在中央仓库的本地提交都推上去。

git-workflow-svn-push-local
git-workflow-svn-push-local

2.1.2 冲突解决

中央仓库表明了正式项目,因此提交历史应该被尊重且是稳定不变的。假设开发人员本地的提交历史和中央仓库有分歧,Git会拒绝push提交不然会覆盖已经在中央库的正式提交。

git-workflow-svn-managingconflicts
git-workflow-svn-managingconflicts

在开发人员提交本身功能改动到中央库前,需要先fetch在中央库的新增提交。rebase本身提交到中央库提交历史之上。
这样作的意思是在说,『我要把本身的改动加到别人已经完毕的改动上。』终于的结果是一个完美的线性历史,就像曾经的SVN的工做流中同样。

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

Git解决合并冲突,用和生成提交同样的git statusgit add命令,很是一致方便。另外一点,假设解决冲突时遇到麻烦,Git可以很是easy停止整个rebase操做,重来一次(或者让别人来帮助解决)。

2.1.3 演示样例

让咱们一块儿逐步分解来看看一个常见的小团队怎样用这个工做流来协做的。有两个开发人员小明和小红,看他们是怎样开发本身的功能并提交到中央仓库上的。

有人先初始化好中央仓库


第一步。有人在server上建立好中央仓库。假设是新项目,你可以初始化一个空仓库;不然你要导入已有的GitSVN仓库。

中央仓库应该是个裸仓库(bare repository)。即没有工做文件夹(working directory)的仓库。

可以用如下的命令建立:

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

确保写上有效的userSSH的username),host(server的域名或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的方式讨论变动。

Git Workflows: Feature Branch
Git Workflows: Feature Branch

一旦你玩转了集中式工做流,在开发过程当中可以很是easy地加上功能分支,用来鼓舞开发人员之间协做和简化交流。

功能分支工做流背后的核心思路是所有的功能开发应该在一个专门的分支。而不是在master分支上。
这个隔离可以方便多个开发人员在各自的功能上开发而不会弄乱主干代码。


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

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

2.2.1 工做方式

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


但不是直接提交本地历史到各自的本地master分支,开发人员每次在開始新功能前先建立一个新分支。
功能分支应该有个有描写叙述性的名字,比方animated-menu-itemsissue-#1061。这样可以让分支有个清楚且高聚焦的用途。

master分支和功能分支之间,Git是没有技术上的差异。因此开发人员可以用和集中式工做流中全然同样的方式编辑、暂存和提交改动到功能分支上。

另外,功能分支也可以(且应该)push到中央仓库中。这样不改动正式代码就可以和其余开发人员分享提交的功能。
由于master仅有的一个『特殊』分支,在中央仓库上存多个功能分支不会有不论什么问题。固然。这样作也可以很是方便地备份各自的本地提交。

2.2.2 Pull Requests

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


一旦某个开发完毕一个功能,不是立刻合并到master。而是push到中央仓库的功能分支上并发起一个Pull Request请求去合并改动到master
在改动成为主干代码前,这让其余的开发人员有机会先去Review变动。

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

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

仓库管理的产品解决方式像BitbucketStash,可以良好地支持Pull Requests

可以看看StashPull 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 GUIclient中发起Pull Request,请求合并marys-featuremaster,团队成员会本身主动收到通知。
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)的合并。

一些GUIclient可以仅仅要点一下『接受』button运行好上面的命令来本身主动化Pull Request接受过程。


假设你的不能这样。至少在功能合并到master分支后能本身主动关闭Pull Request

与此同一时候,小明在作和小红同样的事

当小红和小黑在marys-feature上工做并讨论她的Pull Request的时候。小明在本身的功能分支上作全然同样的事。

经过隔离功能到独立的分支上,每个人都可以自主的工做,固然必要的时候在开发人员之间分享变动仍是比較繁琐的。

到了这里,希望你发现了功能分支可以很是直接地在 集中式工做流 的仅有的master分支上完毕多功能的开发。


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

功能分支工做流是开发项目异常灵活的方式。问题是,有时候太灵活了。对于大型团队,常常需要给不一样分支分配一个更详细的角色。
Gitflow工做流是管理功能开发、公布准备和维护的常用模式。


2.3 Gitflow工做流

Gitflow工做流经过为功能开发、公布准备和维护分配独立的分支,让公布迭代过程更流畅。

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

Git Workflows: Gitflow Cycle
Git Workflows: Gitflow Cycle

这节介绍的Gitflow工做流借鉴自在nvieVincent 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到server上:

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工做流要先有一个公开的正式仓库存储在server上。
但一个新的开发人员想要在项目上工做时,不是直接从正式仓库克隆,而是fork正式项目在server上建立一个拷贝。

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

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

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

2.4.2 正式仓库

Forking工做流中,『官方』仓库的叫法仅仅是一个约定,理解这点很是重要。
从技术上来看,各个开发人员仓库和正式仓库在Git看来没有不论什么差异。
其实,让正式仓库之因此正式的惟一缘由是它是项目维护者的公开仓库。

2.4.3 Forking工做流的分支使用方式

所有的我的公开仓库实际上仅仅是为了方便和其余的开发人员共享分支。
各个开发人员应该用分支隔离各个功能,就像在功能分支工做流Gitflow工做流同样。
惟一的差异是这些分支被共享了。在Forking工做流中这些分支会被pull到还有一个开发人员的本地仓库中,而在功能分支工做流和Gitflow工做流中是直接被push到正式仓库中。

2.4.4 演示样例

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


和不论什么使用Git项目同样,第一步是建立在server上一个正式仓库,让所有团队成员都可以訪问到。
一般这个仓库也会做为项目维护者的公开仓库。

公开仓库应该是裸仓库。不管是否是正式代码库。
因此项目维护者会执行像如下的命令来搭建正式仓库:

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

BitbucketStash提供了一个方便的GUIclient以完毕上面命令行作的事。


这个搭建中央仓库的过程和前面提到的工做流全然同样。
假设有现存的代码库,维护者也要push到这个仓库中。

开发人员fork正式仓库


其余所有的开发需要fork正式仓库。
可以用git clone命令SSH协议连通到server
拷贝仓库到server还有一个位置 —— 是的。fork操做基本上就仅仅是一个服务端的克隆。
BitbucketStash上可以点一下button就让开发人员完毕仓库的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.git

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

开发人员开发本身的功能


在刚克隆的本地仓库中,开发人员可以像其余工做流同样的编辑代码、提交改动新建分支

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远程别名指向开发人员本身的服务端仓库,而不是正式仓库。

第二件事,开发人员要通知项目维护者。想要合并他的新功能到正式库中。
BitbucketStash提供了Pull Requestbutton,弹出表单让你指定哪一个分支要合并到正式仓库。


通常你会想集成你的功能分支到上游远程仓库的master分支中。

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


当项目维护者收到pull request,他要作的是决定是否集成它到正式代码库中。有二种方式来作:

  1. 直接在pull request中查看代码
  2. pull代码到他本身的本地仓库。再手动合并

第一种作法更简单。维护者可以在GUI中查看变动的差别。作评注和运行合并。
但假设出现了合并冲突。需要另一种作法来解决。

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

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

变动集成到本地的master分支后。维护者要push变动到server上的正式仓库,这样其余的开发人员都能訪问到:

git push origin master

注意,维护者的origin是指向他本身公开仓库的。便是项目的正式代码库。到此,开发人员的贡献全然集成到了项目中。

开发人员和正式仓库作同步


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

git pull upstream master

假设你以前是使用SVNForking工做流可能看起来像是一个激进的范式切换(paradigm shift)。


但不要惧怕。这个工做流实际上就是在功能分支工做流之上引入还有一个抽象层。
不是直接经过单个中央仓库来分享分支,而是把贡献代码公布到开发人员本身的服务端仓库中。

演示样例中解释了。一个贡献怎样从一个开发人员流到正式的master分支中,但相同的方法可以把贡献集成到任一个仓库中。
比方,假设团队的几我的协做实现一个功能,可以在开发之间用一样的方法分享变动。全然不涉及正式仓库。

这使得Forking工做流对于松散组织的团队来讲是个很强大的工具。任一开发人员可以方便地和还有一开发人员分享变动,不论什么分支都能有效地合并到正式代码库中。


2.5 Pull Requests

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


开发人员向团队成员通知功能开发已经完毕,Pull Requests是最简单的使用方法。
开发人员完毕功能开发后。经过Bitbucket帐号发起一个Pull Request
这样让涉及这个功能的所有人知道要去作Code Review和合并到master分支。

但是。Pull Request远不止一个简单的通知,而是为讨论提交的功能的一个专门论坛。
假设变动有不论什么问题,团队成员反馈在Pull Request中,甚至push新的提交微调功能。


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


相比其余的协做模型,这样的分享提交的形式有助于打造一个更流畅的工做流。
SVNGit都能经过一个简单的脚本收到通知邮件;但是,讨论变动时,开发人员一般仅仅能去回复邮件。
这样作会变得杂乱。尤为还要涉及后面的几个提交时。
Pull Requests把所有相关功能整合到一个和Bitbucket仓库界面集成的用户友好Web界面中。

2.5.1 解析Pull Request

当要发起一个Pull Request,你所要作的就是请求(Request)还有一个开发人员(比方项目的维护者)
pull你仓库中一个分支到他的仓库中。这意味着你要提供4个信息以发起Pull Request
源仓库、源分支、目的仓库、目的分支。


这几值多数Bitbucket都会设置上合适的缺省值。

但取决你用的协做工做流,你的团队可能会要指定不一样的值。


上图显示了一个Pull Request请求合并一个功能分支到正式的master分支上,但可以有多种不一样的Pull Request使用方法。

2.5.2 工做方式

Pull Request可以和功能分支工做流Gitflow工做流Forking工做流一块儿使用。
但一个Pull Request要求要么分支不一样要么仓库不一样,因此不能用于集中式工做流
在不一样的工做流中使用Pull Request会有一些不一样,但主要的过程是这种:

  1. 开发人员在本地仓库中新建一个专门的分支开发功能。
  2. 开发人员push分支改动到公开的Bitbucket仓库中。
  3. 开发人员经过Bitbucket发起一个Pull Request
  4. 团队的其余成员review code,讨论并改动。
  5. 项目维护者合并功能到官方仓库中并关闭Pull Request

本文后面内容说明,Pull Request在不一样协做工做流中怎样应用。

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

功能分支工做流用一个共享的Bitbucket仓库来管理协做,开发人员在专门的分支上开发功能。
但不是立刻合并到master分支上,而是在合并到主代码库以前开发人员应该开一个Pull Request发起功能的讨论。


功能分支工做流仅仅有一个公开的仓库,因此Pull Request的目的仓库和源仓库老是同一个。
一般开发人员会指定他的功能分支做为源分支,master分支做为目的分支。

收到Pull Request后,项目维护者要决定怎样作。

假设功能没问题,就简单地合并到master分支。关闭Pull Request
但假设提交的变动有问题,他可以在Pull Request中反馈。以后新加的提交也会评论以后接着显示出来。

在功能尚未全然开发完的时候,也可能发起一个Pull Request
比方开发人员在实现某个需求时碰到了麻烦。他可以发一个包括正在进行中工做的Pull Request
其余的开发人员可以在Pull Request提供建议。或者甚至直接加入提交来解决这个问题。

2.5.4 在Gitflow工做流中使用Pull Request

Gitflow工做流和功能分支工做流相似。但环绕项目公布定义一个严格的分支模型。
Gitflow工做流中使用Pull Request让开发人员在公布分支或是维护分支上工做时,
可以有个方便的地方对关于公布分支或是维护分支的问题进行交流。


Gitflow工做流中Pull Request的使用过程和上一节中全然一致:
当一个功能、公布或是热修复分支需要Review时。开发人员简单发起一个Pull Request
团队的其余成员会经过Bitbucket收到通知。

新功能通常合并到develop分支。而公布和热修复则要同一时候合并到develop分支和master分支上。


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

2.5.5 在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成为一个强有力的协做工具。

2.5.6 演示样例

如下的演示样例演示了Pull Request怎样在在Forking工做流中使用。
也相同适用于小团队的开发协做和第三方开发人员向开源项目的贡献。

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

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

小红fork正式项目


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

她登录Bitbucket,浏览到小明的仓库页面,
Forkbutton。


而后为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来删除或压制提交。
对于大型项目,整理功能分支的历史可以让项目维护者更easy看出在Pull Request中作了什么内容。

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


小红完毕了功能后,push功能到她本身的Bitbucket仓库中(不是正式仓库)。用如下简单的命令:

git push origin some-branch

这时她的变动可以让项目维护者看到了(或者不论什么想要看的协做者)。

小红发起Pull Request


Bitbucket上有了她的功能分支后,小红可以用她的Bitbucket帐号浏览到她的fork出来的仓库页面,
点右上角的【Pull Request】button,发起一个Pull Request
弹出的表单本身主动设置小红的仓库为源仓库,询问小红以指定源分支、目标仓库和目标分支。

小红想要合并功能到正式仓库。因此源分支是她的功能分支,目标仓库是小明的公开仓库,
而目标分支是master分支。另外。小红需要提供Pull Request的标题和描写叙述信息。
假设需要小明之外的人审核批准代码。她可以把这些人填在【Reviewers】文本框中。


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

小明review Pull Request


在小明的Bitbucket仓库页面的【Pull Request】Tab可以看到所有人发起的Pull Request
点击小红的Pull Request会显示出Pull Request的描写叙述、功能的提交历史和每个变动的差别(diff)。

假设小明想要合并到项目中,仅仅要点一下【Merge】button。就可以容许Pull Request并合并到master分支。

但假设像这个演示样例中同样小明发现了在小红的代码中的一个小Bug。要小红在合并前修复。
小明可以在整个Pull Request上加上评注。或是选择历史中的某个提交加上评注。


小红补加提交

假设小红对反馈有不论什么疑问。可以在Pull Request中响应。把Pull Request看成是她功能讨论的论坛。

小红在她的功能分支新加提交以解决代码问题,并push到她的Bitbucket仓库中。就像前一轮中的作法同样。
这些提交会进入的Pull Request。小明在原来的评注旁边可以再次review变动。

小明接受Pull Request

终于,小明接受变动,合并功能分支到master分支,并关闭Pull Request


至此,功能集成到项目中,其余的项目开发人员可以用标准的git pull命令pull这些变动到本身的本地仓库中。

到了这里,你应该有了所有需要的工具来集成Pull Request到你本身的工做流。
请记住,Pull Request并不是为了替代不论什么 基于Git的协做工做流, 而是它们的一个便利的补充,让团队成员间的协做更轻松方便。

相关文章
相关标签/搜索