git工作流最佳实践
参考:my-git/git-workflow-tutorial.md at master · xirong/my-git
git工作流有多种使用方法,在实际工作中的不良工作习惯,会造成很让人头大的麻烦。下面距离一些常用的工作流。
集中式
类似SVN,集中式工作流以中央仓库作为项目所有修改的单点实体,只用到master这一个分支。开发者提交功能修改到中央库前,采用rebase
的方式“在其基础上添加自己的修改”,得到完美的线性历史;遇到冲突时,通过git status
和git add
合并冲突。最后git rebase --continue
即可。遇到困难无法进行下去时,git rebase --abort
就可以撤回到rebase前的状态。
在这种工作流下,使用rebase
参数比不使用的git pull
好处在于,rebase后的提交记录会少一次累赘的“合并提交”。
功能分支
git相较SVN强大在分布式的特征。功能分支工作流主要针对新增功能集成到正式项目。功能分支工作流仍然以中央仓库为基础,但不是直接提交本地历史到各自的本地master分支,而是在开发新功能时创建新的分支,描述新功能。不同的功能分支相互隔离,同时也保证master分支的代码一定没有问题。一旦功能分支push到master,意味着功能与其他开发者共享。
合并到master分支的过程通过创建pull request进行,在pull request请求中,让其他开发者有机会先去review变更。Pull request被接受后,剩下的工作就和集中式很像了,拉取master分支代码,合并,提交。
工作流程上:
- 先checkout功能分支
- 做本地开发提交,以及
push -u
推送到远端分支(-u
是跟踪远端对应分支的意思) - 完成开发后,提交pull request,请求合并远端功能分支到master,团队其他成员可以进行评论
- 在接受前,团队所有成员有需要,可以提交自己的修改到该功能分支,也会显示在pull request里
- 在pull-request被接受后,在本地master上可以用pull或者
pull -r
的方式合并功能分支,前者更像功能和原来代码的合并,后者更偏向线型的提交历史
gitflow
Gitflow工作流通过为功能开发、发布准备和维护分配独立的分支,让发布迭代过程更流畅。相较功能分支更复杂,但也更健壮。仍然用中央仓库作为所有开发者的交互中心。相对于使用仅有的一个master分支,Gitflow工作流使用两个分支来记录项目的历史。master分支存储了正式发布的历史,而develop分支作为功能的集成分支。从而可以在master的所有提交附上版本号。
每个新功能位于一个自己的分支,有着和功能分支一样的开发工作流,唯一不同的是,功能分支不是从master分支上拉出新分支,而是使用develop分支作为父分支。每次合并都位于develop分支。
一旦develop分支上有了做一次发布(或者说快到了既定的发布日)的足够功能,就从develop分支上checkout一个发布分支release。从这个时间点开始之后新的功能不能再加到这个分支上——这个分支只应该做Bug修复、文档生成和其它面向发布任务。在release工作完成后,合并release分支到master,并加上tag。同时,release上做的修改要合并会develop分支。最后删除release分支。
维护分支或说是热修复(hotfix)分支用于给产品发布版本(production releases)快速生成补丁,这是唯一可以直接从master分支fork出来的分支。修改完成后,修改应该立马合并回master和develop。master也应该为合并生成新的tag。
forking
Forking工作流是分布式工作流,可以安全可靠地管理大团队的开发者(developer)和不信任贡献者(contributor)的提交。这种工作流不是使用单个服务端仓库作为『中央』代码基线,而让各个开发者都有一个服务端仓库。这意味着各个代码贡献者有2个Git仓库而不是1个:一个本地私有的,另一个服务端公开的。Forking工作流的一个主要优势是,贡献的代码可以被集成,而不需要所有人都能push代码到仅有的中央仓库中。开发者push到自己的服务端仓库,而只有项目维护者才能push到正式仓库。
新开发者想要在项目上工作时,不是直接从正式仓库克隆,而是fork正式项目在服务器上创建一个拷贝。这个仓库拷贝作为他个人公开仓库 —— 其它开发者不允许push到这个仓库,但可以pull下来修改。要提交本地修改时,push提交到自己公开仓库中 —— 而不是正式仓库中。 然后,给正式仓库发起一个pull request,让项目维护者知道有更新已经准备好可以集成了。为了集成功能到正式代码库,维护者pull贡献者的变更到自己的本地仓库中,检查变更以确保不会让项目出错, 合并变更到自己本地的master分支, 然后push master分支到服务器的正式仓库中。到此,贡献的提交成为了项目的一部分,其它的开发者应该执行pull操作与正式仓库同步自己本地仓库。
具体来说,大致有下面几步:
- 开发者fork正式仓库
- 开发者clone自己的fork出来的仓库,与之前工作流不一样的是,Forking工作流需要2个远程别名 —— 一个指向正式仓库,另一个指向开发者自己的服务端仓库。,像下面这样
1
git remote add upstream https://bitbucket.org/maintainer/repo
- 开发者修改都是私有的,如果项目往前走了,可以用git pull获得新的提交
- 开发者准备分享新功能时,需要先push到自己的公开仓库中,然后发起pull request通知项目维护者,集成开发者的功能分支
- 项目维护者通过GUI岔开pull request或者pull代码到自己的本地仓库,再手动合并。
- 开发者通过
pull upstream master
的方式拉取项目最新进展
pull request
pull request用于合并不同分支或不同仓库的代码,并在合并前进行一些讨论和代码微调,在上面不同工作流的情况下具体功能体现也不同。
上面几种工作流范式只是几种标准的建议,正式的项目版本管理中,可以糅合上面的一些特点。