我的在学习Git
工做流的过程当中,从原有的 SVN 模式很难彻底理解Git
的协做模式,直到有一天我看到了下面的文章,好多遗留在心中的困惑迎刃而解:git
Git
有什么不妥?Git
方便的branch在哪里,团队多人如何协做?冲突了怎么办?如何进行发布控制?GitHub
上面与他人一块儿协做,star-fork-pull request是怎样的流程?我我的很感激这篇文章,因此进行了整理,但愿能帮到更多的人。整篇文章由 xirong 整理自 oldratlee 的GitHub
,方便统一的学习回顾,在此感谢下面两位的贡献。github
原文连接:Git Workflows and Tutorials
简体中文:由 oldratlee 翻译在 GitHub
上 Git
工做流指南shell
在第三部分 企业平常开发模式探索,xirong 结合本身所在公司使用git的版本分支开发过程,进行了总结,欢迎你们提出更好的建议。安全
在第四部分 开发工做流的讨论 中,引用了几篇文章,包括 Github 的开发流程以及 Thoughtworkers 工程师发表的「Gitflow 有害论」,旨在表名流程并非惟一的,适合本身当前团队的才是最好的。服务器
这篇指南以你们在SVN
中已经广为熟悉使用的集中式工做流做为起点,按部就班地演进到其它高效的分布式工做流,还介绍了如何配合使用便利的Pull Request
功能,系统地讲解了各类工做流的应用。 若是你Git
用的还很少,能够从前面的讲的工做流开始操练。在操做过程当中去感觉指南的讲解:解决什么问题、如何解决问题,这样理解就深了,也方便活用。并发
行文中实践原则和操做示例并重,对于Git
的资深玩家能够梳理思考提高,而新接触的同窗,也能够跟着step-by-step操练学习并在实际工做中上手使用。app
工做流其实不是一个初级主题,背后的本质问题是 有效的项目流程管理 和 高效的开发协同约定,而不只仅是Git
或SVN
等VCS
或SCM
工具的使用。框架
关于Git
工做流主题,网上体系的中文资料很少,主要是零散的操做说明,但愿这篇文章能让你更深刻理解并在工做中灵活有效地使用起来。ssh
Gitflow
工做流是经典模型,处于核心位置,体现了工做流的经验和精髓。随着项目过程复杂化,你会感觉到这个工做流中的深思熟虑和威力!分布式
Forking
工做流是分布式协做的(GitHub
风格)能够先看看GitHub
的Help:Fork A Repo和Using pull requests 。照着操做,给一个GitHub
项目贡献你的提交,有操做经验再看指南容易意会。指南中给了本身实现Fork
的方法:Fork
就是服务端的克隆。在指南的操练中使用代码托管服务(如GitHub
、Bitbucket
),能够点一下按钮就让开发者完成仓库的fork
操做。
PS:
文中Pull Request
的介绍用的是Bitbucket
代码托管服务,因为和GitHub
基本同样,若是你用的是GitHub
(我本身也主要使用GitHub
托管代码),不影响理解和操做。
PPS:
更多Git
学习资料参见
Git
工做流指南👉 工做流有各式各样的用法,但也正所以使得在实际工做中如何上手使用变得很头大。这篇指南经过总览公司团队中最经常使用的几种Git
工做流让你们能够上手使用。
在阅读的过程当中请记住,本文中的几种工做流是做为方案指导而不是条例规定。在展现了各类工做流可能的用法后,你能够从不一样的工做流中挑选或揉合出一个知足你本身需求的工做流。
若是你的开发团队成员已经很熟悉Subversion
,集中式工做流让你无需去适应一个全新流程就能够体验Git
带来的收益。这个工做流也能够做为向更Git
风格工做流迁移的友好过渡。
转到分布式版本控制系统看起来像个使人生畏的任务,但不改变已用的工做流,你也能够用上Git
带来的收益。团队能够用和Subversion
彻底不变的方式来开发项目。
但使用Git
增强开发的工做流,相比SVN
,Git
有如下两个优点: 首先,每一个开发者能够有属于本身的整个工程的本地拷贝。隔离的环境让各个开发者的工做和项目的其余部分修改独立开来 —— 即自由地提交到本身的本地仓库,先彻底忽略上游的开发,直到方便的时候再把修改反馈上去。
其次,Git
提供了强壮的分支和合并模型。不像SVN
,Git
的分支设计成能够作为一种用来在仓库之间集成代码和分享修改的『失败安全』的机制。
像Subversion
同样,集中式工做流以中央仓库做为项目全部修改的单点实体。相比SVN
缺省的开发分支trunk
,Git
叫作master
,全部修改提交到这个分支上。本工做流只用到master
这一个分支。
首先,开发者克隆中央仓库。在本身的项目拷贝中,像SVN
同样的编辑文件和提交修改;但修改是存在本地的,和中央仓库是彻底隔离的。开发者能够把和上游的同步延后到一个方便时间点。
而后,开发者发布修改到正式项目中,开发者要把本地master
分支的修改『推』到中央仓库中。这至关于svn commit
操做,但push
操做会把全部还不在中央仓库的本地提交都推上去。
中央仓库表明了正式项目,因此提交历史应该被尊重且是稳定不变的。若是开发者本地的提交历史和中央仓库有分歧,Git
会拒绝push
提交不然会覆盖已经在中央库的正式提交。
在开发者提交本身功能修改到中央库前,须要先fetch
在中央库的新增提交,rebase
本身提交到中央库提交历史之上。 这样作的意思是在说,『我要把本身的修改加到别人已经完成的修改上。』最终的结果是一个完美的线性历史,就像之前的SVN
的工做流中同样。
若是本地修改和上游提交有冲突,Git
会暂停rebase
过程,给你手动解决冲突的机会。Git
解决合并冲突,用和生成提交同样的git status
和git add
命令,很一致方便。还有一点,若是解决冲突时遇到麻烦,Git
能够很简单停止整个rebase
操做,重来一次(或者让别人来帮助解决)。
让咱们一块儿逐步分解来看看一个常见的小团队如何用这个工做流来协做的。有两个开发者小明和小红,看他们是如何开发本身的功能并提交到中央仓库上的。
第一步,有人在服务器上建立好中央仓库。若是是新项目,你能够初始化一个空仓库;不然你要导入已有的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
分布式本质的优点。
若是你的团队适应了集中式工做流,但想要更流畅的协做效果,绝对值得探索一下 功能分支工做流
的收益。 经过为一个功能分配一个专门的分支,可以作到一个新增功能集成到正式项目以前对新功能进行深刻讨论。
功能分支工做流以集中式工做流为基础,不一样的是为各个新功能分配一个专门的分支来开发。这样能够在把新功能集成到正式项目前,用Pull Requests
的方式讨论变动。
一旦你玩转了集中式工做流,在开发过程当中能够很简单地加上功能分支,用来鼓励开发者之间协做和简化交流。
功能分支工做流背后的核心思路是全部的功能开发应该在一个专门的分支,而不是在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 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
文档。
下面的示例演示了如何把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
工做流是管理功能开发、发布准备和维护的经常使用模式。
Gitflow
工做流Gitflow
工做流经过为功能开发、发布准备和维护分配独立的分支,让发布迭代过程更流畅。严格的分支模型也为大型项目提供了一些很是必要的结构。
这节介绍的Gitflow
工做流借鉴自在nvie的Vincent Driessen。
Gitflow
工做流定义了一个围绕项目发布的严格分支模型。虽然比功能分支工做流复杂几分,但提供了用于一个健壮的用于管理大型项目的框架。
Gitflow
工做流没有用超出功能分支工做流的概念和命令,而是为不一样的分支分配一个明确的角色,并定义分支之间如何和何时进行交互。 除了使用功能分支,在作准备、维护和记录发布时,也定义了各自的分支。 固然你能够用上功能分支工做流全部的好处:Pull Requests
、隔离实验性开发和更高效的协做。
Gitflow
工做流仍然用中央仓库做为全部开发者的交互中心。和其它的工做流同样,开发者在本地工做并push
分支到要中央仓库中。
相对于使用仅有的一个master
分支,Gitflow
工做流使用两个分支来记录项目的历史。master
分支存储了正式发布的历史,而develop
分支做为功能的集成分支。 这样也方便master
分支上的全部提交分配一个版本号。
剩下要说明的问题围绕着这2个分支的区别展开。
每一个新功能位于一个本身的分支,这样能够push
到中央仓库以备份和协做。 但功能分支不是从master
分支上拉出新分支,而是使用develop
分支做为父分支。当新功能完成时,合并回develop
分支。 新功能提交应该从不直接与master
分支交互。
注意,从各类含义和目的上来看,功能分支加上develop
分支就是功能分支工做流的用法。但Gitflow
工做流没有在这里止步。
一旦develop
分支上有了作一次发布(或者说快到了既定的发布日)的足够功能,就从develop
分支上checkout
一个发布分支。 新建的分支用于开始发布循环,因此从这个时间点开始以后新的功能不能再加到这个分支上—— 这个分支只应该作Bug
修复、文档生成和其它面向发布任务。 一旦对外发布的工做都完成了,发布分支合并到master
分支并分配一个版本号打好Tag
。 另外,这些重新建发布分支以来的作的修改要合并回develop
分支。
使用一个用于发布准备的专门分支,使得一个团队能够在完善当前的发布版本的同时,另外一个团队能够继续开发下个版本的功能。 这也打造定义良好的开发阶段(好比,能够很轻松地说,『这周咱们要作准备发布版本4.0』,而且在仓库的目录结构中能够实际看到)。
经常使用的分支约定:
用于新建发布分支的分支: develop 用于合并的分支: master 分支命名: release-* 或 release/*
维护分支或说是热修复(hotfix
)分支用于给产品发布版本(production releases
)快速生成补丁,这是惟一能够直接从master
分支fork
出来的分支。 修复完成,修改应该立刻合并回master
分支和develop
分支(当前的发布分支),master
分支应该用新的版本号打好Tag
。
为Bug
修复使用专门分支,让团队能够处理掉问题而不用打断其它工做或是等待下一个发布循环。 你能够把维护分支想成是一个直接在master
分支上处理的临时发布。
下面的示例演示本工做流如何用于管理单个发布循环。假设你已经建立了一个中央仓库。
第一步为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
为你所用。
Forking
工做流Forking
工做流是分布式工做流,充分利用了Git
在分支和克隆上的优点。能够安全可靠地管理大团队的开发者(developer
),并能接受不信任贡献者(contributor
)的提交。
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.git
这时在克隆和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
工做流对于松散组织的团队来讲是个很是强大的工具。任一开发者能够方便地和另外一开发者分享变动,任何分支都能有效地合并到正式代码库中。
Pull Requests
Pull requests
是Bitbucket
提供的让开发者更方便地进行协做的功能,提供了友好的Web
界面能够在提议的修改合并到正式项目以前对修改进行讨论。
开发者向团队成员通知功能开发已经完成,Pull Requests
是最简单的用法。 开发者完成功能开发后,经过Bitbucket
帐号发起一个Pull Request
。 这样让涉及这个功能的全部人知道要去作Code Review
和合并到master
分支。
可是,Pull Request
远不止一个简单的通知,而是为讨论提交的功能的一个专门论坛。 若是变动有任何问题,团队成员反馈在Pull Request
中,甚至push
新的提交微调功能。 全部的这些活动都直接跟踪在Pull Request
中。
相比其它的协做模型,这种分享提交的形式有助于打造一个更流畅的工做流。 SVN
和Git
都能经过一个简单的脚本收到通知邮件;可是,讨论变动时,开发者一般只能去回复邮件。 这样作会变得杂乱,尤为还要涉及后面的几个提交时。 Pull Requests
把全部相关功能整合到一个和Bitbucket
仓库界面集成的用户友好Web
界面中。
Pull Request
当要发起一个Pull Request
,你所要作的就是请求(Request
)另外一个开发者(好比项目的维护者) 来pull
你仓库中一个分支到他的仓库中。这意味着你要提供4个信息以发起Pull Request
: 源仓库、源分支、目的仓库、目的分支。
这几值多数Bitbucket
都会设置上合适的缺省值。但取决你用的协做工做流,你的团队可能会要指定不一样的值。 上图显示了一个Pull Request
请求合并一个功能分支到正式的master
分支上,但能够有多种不一样的Pull Request
用法。
Pull Request
能够和功能分支工做流、Gitflow
工做流或Forking
工做流一块儿使用。 但一个Pull Request
要求要么分支不一样要么仓库不一样,因此不能用于集中式工做流。 在不一样的工做流中使用Pull Request
会有一些不一样,但基本的过程是这样的:
push
分支修改到公开的Bitbucket
仓库中。Bitbucket
发起一个Pull Request
。review
code
,讨论并修改。Pull Request
。本文后面内容说明,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
成为一个强有力的协做工具。
下面的示例演示了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
的标题和描述信息。 若是须要小明之外的人审核批准代码,她能够把这些人填在【Reviewers】文本框中。
建立好了Pull Request
,通知会经过Bitbucket
系统消息或邮件(可选)发给小明。
Pull Request
在小明的Bitbucket
仓库页面的【Pull Request
】Tab能够看到全部人发起的Pull Request
。 点击小红的Pull Request
会显示出Pull Request
的描述、功能的提交历史和每一个变动的差别(diff
)。
若是小明想要合并到项目中,只要点一下【Merge
】按钮,就能够赞成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的协做工做流
, 而是它们的一个便利的补充,让团队成员间的协做更轻松方便。
在看这部分前,请先回顾阅读业界承认的成功的 Git Branch Work Flow 模型 A Successful Git Branching Model ,了解平常开发中的场景,有助于熟悉下面的使用过程。
在企业开发中,使用 Git 做为版本控制软件最看重的仍是结合公司本身搭建的 Gitlab,将 Code Review 加入打包部署持续集成的流程中,这样,代码开发完成,提交测试前,即可以对开发人员提交的代码进行 Review,发现潜在的问题,及时指导,对于新人来说,也能更快更好的学习。
解决的需求场景以下:
上图就是 xirong 团队在平常开发中总结出来的适合企业开发的模式,下面进行简单的介绍,方便你们学习了解,欢迎提交 Issue 进行讨论。(本模式适合敏捷开发流程,小迭代上线,传统的瀑布开发模型并无进行测试)
git merge --no-ff origin/master
,使得 Master 分支上的变动更新到迭代开发分支dev上面,以后,在 Gitlab 上面发起 pull request
请求,并指定 Code Review 人,请求的分支选择本次上线的 release 分支,即 release20150730。这样通过上面的1-5步骤,企业平常迭代开发中的代码版本控制基本上就 Ok 了,有问题欢迎 Issue 讨论。
2016-11月 更新 Git 分支开发部署模型 的一些使用原则以下:
Git-Develop 分支模式是基于 Git 代码库设计的一种须要严格控制发布质量和发布节奏的开发模式。develop 做为固定的持续集成和发布分支,而且分支上的代码必须通过 CodeReview 后才能够提交到 Develop 分支。它的基本流程以下: