git分支管理规范
现在EFE在git上的仓库众多,但是每个仓库都有自己的一套开发模型,有些是master推送,有些是分支开发,有些是git flow。这不利于工程师贡献,因此最好有一个统一的分支管理的规范
下面是我经过N种玩法后总结出来的一种方式,供讨论
MUST、SHOULD、MAY、RECOMMEND不再赘述
本规范强制用于github上各项目的开发管理,对于其它环境下基于git的开发不作硬性要求,但建议(RECOMMEND)参考此规范
版本
版本号必须符合semver,其的形式为{major}.{minor}.{patch}[-{pre-release-type}.{pre-release}]
其中major、minor、patch和{pre-release}`必须为十进制数字,且随版本发布递增。
{pre-release-type}必须选择以下关键词之一:
-
alpha表示内部测试版本,不建议任何非参与开发人员所在团队使用,在alpha版本期间会不断增加新的功能并修复已有BUG -
beta表示公开测试版本,不建议稳定项目使用,在beta版本期间会酌情增加新功能,修复已知BUG -
rc表示发布候选版本,推荐各项目使用,在rc期间不得增加任何新功能,仅修复BUG。如果rc版本未发现任何BUG,则此版本直接转为正式发布版
分支
所有项目采用分支开发方式,分支分为开发分支、发布分支、功能分支、修复分支和master分支
- 实际的分支以版本号为前缀,其中版本号精确到第1个子版本,如
1.0或3.1 - 开发分支的形式为
{version}/develop,此类分支用于维护一个版本的开发过程 - 发布分支的形式为
{version}/release,此类分支用于维护每一个发布版本的状态,不得将功能或修复直接合并至此分类支 - 功能分支的形式为
{version}/feature/{feature-desc},此类分支用于开发单一的原子性的功能 - 修复分支的形式为
{version}/fix/{bug-desc},此类分支用于修复一个已有的BUG - master分支即
master,此分支用于维护当前主流版本的稳定状态,不得将任何功能、修复、开发分支合并至此分支
对于fork式开发,也需要按以上形式建立分支
开发
- 开发任何功能前,应该(SHOULD)有一个github issue对应其功能
- 从对应版本的开发分支中拉取功能分支,命名形式为
{version}/feature/{feature-desc} - 在分支上完成开发,在分支的commit中应该(SHOULD)添加形如
Fix #xxx的信息对应github issue - 开发完成后,发起pull request,需注意pull request的对应目标为 开发分支
- 进行Code Review,通过后merge
- 删除开发分支
发布
- 在 开发分支 上修改版本号为即将发布的版本
- 从 开发分支 向对应的 发布分支 发起Pull Request
- 进行Code Review,通过后merge
- 从 发布分支 创建一个tag,tag的命名必须(MUTST)为符合semver的当前发布的版本号
- 如果需要,同时将版本发布至edp
在创建tag后,如果发现紧急的BUG,可在12小时内删除该tag,通过 修复分支 修复BUG后再行发布,不应该(SHOULD NOT)删除任何发布超过12小时的tag
紧急BUG修复
该过程仅用于发布后发现的必须修复的紧急BUG,不适用于正常开发规划中对BUG的修复
- 在github上添加一个对应的issue
- 从对应版本的 发布分支 中拉取 修复分支 ,命名形式为
{version}/fix/{bug-desc} - 在分支上开发,在分支的commit中应该(SHOULD)添加形如
Fix #xxx的信息对应github issue - 开发完成后,发起2个pull request,对应目标分别为 开发分支 和 发布分支
- 进行Code Review,通过后merge
- 删除修复分支
同步master
当且仅当目前的主流版本的发布分支稳定(确认不再会有紧急BUG修复产生)后,可通过pull request合并至master分支
任何时候不得直接向master分支提交来自非发布分支的pull request
+1
再补充下对版本的控制:
- major版本,第1位数字变化表示一个major版本,此类版本通常是完全的重新设计的版本,可自由做任意更改
- minor版本,第2位数字变化表示一个minor版本,此类版本会有新功能的引入,但应该(SHOULD)保持向后兼容性,如有向后兼容性问题,必须(MUST)在发布的时候说明,并必须(MUST)提供升级指导
- patch版本,第3位数字变化表示一个patch版本,此类版本不得(MUST NOT)引入新的功能或接口,仅能包含重构或功能修复,不得(MUST NOT)引入不向后兼容的变化
- 例外的,在alpha状态时,可以对当前版本中新增的功能和接口引入非兼容性的变化,即所有新的功能或接口在beta版本发布前处于不稳定状态,alpha阶段的使用者不应该(SHOULD NOT)依赖新接口的稳定性
- 在发布新的major或minor版本后,应当(SHOULD)保证原版本的BUG修复工作,不应该(SHOULD NOT)放弃2个minor版本之内的版本的维护,可以(MAY)放弃2个minor版本之前的版本的维护,即如发布了
3.4.0,由应该(SHOULD)继续维护3.2.x和3.3.x版本,可以(MAY)不再维护3.0.x和3.1.x
对使用者的建议:
- 所有依赖的版本控制在minor版本不变,使用如
1.3.x形式的semver表达式 - 如非参与开发者,不要使用alpha版本
- 如无能力发现和处理BUG,不要使用beta版本
- 对于任何minor版本有变化的更新,升级后应该(SHOULD)进行谨慎地测试
- 对于任何major版本有变化的更新,先确定这还是不是你要的那个库
@leeight 如果此规范得以实行,则pre-release版本的类型将受限,因此进一步建议edp支持可配置升级时指定排除alpha或beta或rc版本
+1
有两个问题:
- 12 小时内删除 tag 有什么讲究,为什么是 12 小时?
- 这个开发流程,能否基于 git-flow 或 git-ext 实现?
- 这个数字没有科学论证,我大致整出来的,可以讨论来定。我基本上认为12小时是个界限,12小时足够其它人开始用这个更新,同时超过12小时还没发现BUG这次发布也太失败了
- git flow我也有试过,事实上我上面描述的模型其实就是个加强的git flow你应该看得出来。git flow就一个缺点,不支持多个版本并行,即我现在主流开发
4.2版本,但我不能直接删了3.3,因为有一些功能可能同时要加到两个版本中形成4.3和3.4,也有可能一些BUG修复要同时放进不同的版本里不断维护。像jq就同时维护1.9和2.0`两个版本,这在git flow只支持release、develop、feature、hotfix、master这几种分支的模型上是办不了的,也有人在git flow的issue上提出了这问题但短时间我看不到那边解决的意愿……至于自己开发工具,以后的事了?
因此进一步建议edp支持可配置升级时指定排除alpha或beta或rc版本
这个貌似不是通过edp来控制的,因为大部分package都是通过npm来安装的,所以应该是在npm安装的时候指定版本,例如:
npm i -g edp-build@stable edp-project@alpha
github上也有不少包是edp import和edp update管理的啊
在 2014年7月28日,上午10:02,leeight [email protected] 写道:
因此进一步建议edp支持可配置升级时指定排除alpha或beta或rc版本
这个貌似不是通过edp来控制的,因为大部分package都是通过npm来安装的,所以应该是在npm安装的时候指定版本,例如:
npm i -g edp-build@stable edp-project@alpha — Reply to this email directly or view it on GitHub.
如果是edp import或者edp update来用的话,可以在发布package的时候,指定tag,例如:
npm publish --tag [stable | alpha | beta | rc]
如果不指定的话,默认用的是latest这个tag。
我可以升级来edp import的功能默认只用stable和rc的tag,不过现在已经发布过的package,貌似是没有办法更新了,不知道人肉去修改数据库是否可以。
能不用管publish,只在import时先拿到版本列表,找版本的时候看一下pre-release版本,找最后一个符合条件的吗?
找版本的时候看一下pre-release版本,找最后一个符合条件的吗?
你指的pre-release应该是非alpha和beta吧,rc和stable都算作pre-release?
pre-release指3个数字后面的那部分,没有的就是stable,按这个标准的话是允许alpha、beta、rc
然后我建议是,在dependencies中,可以写er: '3.1.x@stable'这种形式,表示允许3.1.x版本,但不要alpha和beta,除了@stable外,还能写@beta和@alpha,分别表示允许选定的类型及之后的(beta包含beta + rc + stable,依次类推)
另外,这种形式的分支创建不了吧?莫非我用法的问题?
➜ edp-package git:(master) git checkout -b '0.5/feature/hello-world'
error: unable to resolve reference refs/heads/0.5/feature/hello-world: Not a directory
fatal: Failed to lock ref for update: Not a directory
你必须没有任何一个分支叫0.5或者0.5/feature,git不允许一个东西又是分支名又是目录
~/Dev/er on ⭠ use-eoo ⌚ 13:49:15
$ git co -b 4.0/features/test
Switched to a new branch '4.0/features/test'
然后我建议是,在dependencies中,可以写er: '3.1.x@stable'这种形式,表示允许3.1.x版本,但不要alpha和beta,除了@stable外,还能写@beta和@alpha,分别表示允许选定的类型及之后的(beta包含beta + rc + stable,依次类推)
-
er: 3.1.x,应该是(stable和rc),实际上等同于er: 3.1.x@rc -
er: 3.1x@stable,应该只有(stable) -
er: 3.1x@beta,应该有(beta, rc, stable)
...
OK,这个可以有
但要考虑到向后兼容,比如我现在已经是3.1.0-beta.2了,edp升级后再update总不能退回3.0.4稳定版去
因为dependencies中的value可以写的很复杂,例如:
{ "dependencies" :
{ "foo" : "1.0.0 - 2.9999.9999"
, "bar" : ">=1.0.2 <2.1.2"
, "baz" : ">1.0.2 <=2.3.4"
, "boo" : "2.0.1"
, "qux" : "<1.0.0 || >=2.3.1 <2.4.5 || >=2.5.2 <3.0.0"
, "asd" : "http://asdf.com/asdf.tar.gz"
, "til" : "~1.2"
, "elf" : "~1.2.3"
, "two" : "2.x"
, "thr" : "3.3.x"
}
}
另外,此时再版本号后面再添加'@beta', '@alpha',其实就不是一个合法的semver了。
所以通过命令行添加参数来支持?比如 edp import --tag=alpha 之类的?
主要是担心2种情况:
-
package.json里写完依赖,一次edp import自动安装,这种情况出现在clone一个github包后要看demo的情况 -
edp update自动升级
那能不能edp update --accept=beta这样所有包都会自动找beta版本呢?
那能不能edp update --accept=beta这样所有包都会自动找beta版本呢?
再考虑考虑。
@errorrik @otakustay @chriswong @firede @Justineo @kener 现在通过webhook自动发布到edp-registry.baidu.com上面的package,如果create tag的时候,带有alpha, beta, rc之类的话,npm publish的时候会自动添加对应的dist-tag,不会更新latest。如果没有的话,会更新latest这个dist-tag。
所以建议都配置好web hook,发布package的时候不要手工操作了,让那个jenkins的job自己去搞。
这货为啥不是在ecomfe/spec下的issue...
放错地方了……
总的来说,我觉得:
- 需要规范开发过程
- 这个过程有点复杂
具体我的问题如下:
- 分支name建议以
-分隔,我们知道git会出现origin/master这样的分支代表远程分支的本地映射,用/分隔容易凌乱 - 功能分支和开发分支是否有些职责重复,是否需要区分这么细?如果按照现在的说明,我们很可能
建立开发分支-建立功能分支-开发功能-切换开发分支-合并功能分支-干掉功能分支 - 发布是否有些麻烦?现在看来,如果不发布到npm,没人用的话,bug也看不出来。如果有bug,要修复,npm也必须增加版本号。我觉得,发布后如果发现紧急的BUG,需要修正,也应该是up patch version。如果是这样,那现在的发布流程就有些不必要
分支name建议以-分隔,我们知道git会出现origin/master这样的分支代表远程分支的本地映射,用/分隔容易凌乱
这个是从git flow参考过来的,分隔符我觉得都可以
功能分支和开发分支是否有些职责重复,是否需要区分这么细?
单个功能一个分支,使用尽量多的分支是能体现git优势的一个良好的开发习惯,至少有助于:
- 多个功能并行开发时,一个功能要抛弃了不需要去看回滚哪些commit,直接删除分支即可
- 每一个分支都可以做完自己的测试再合并到开发分支,保持开发分支的代码相对稳定
- 一个功能开发一半,但另一个比较急的功能要做,现有的功能又处于还不能用的状态,却没有一个分支可以作为base拉取新的功能分支
在我实际的开发过程中,确实出现过很多次1和3的情况,当然如果一个库真的是完全线性开发的,不会有多个功能穿插着来,那确实这个没有太大的帮助
发布是否有些麻烦?现在看来,如果不发布到npm,没人用的话,bug也看不出来。如果有bug,要修复,npm也必须增加版本号。我觉得,发布后如果发现紧急的BUG,需要修正,也应该是up patch version。如果是这样,那现在的发布流程就有些不必要
我想保证的是:
- master上的永远对应现在主流版本
- 所有release和master的代码都是绝对可用的,不会有“因为开发了一半所以不能参考”这样的情况
发布不能回滚我也比较认同,但会产生“一个版本有严重BUG不能用”这样的问题,而我们没有机制告诉别人哪个版本不能用
关于功能分支
好吧,确实会有1和3这种情况出现,但是当多个feature同时开发时,如果有多个分支,可能会出现后来的分支需要手工merge的情况。2不是问题,我觉得2是每个开发者都需要保证的。
所以我觉得,这个可以有,但是需要对开发分支和功能分支的作用和使用场景,做一些简单的说明。比如什么场景需要用,什么场景就算了。
关于release
我认同要保证的两点,不过我通常的做法是,dev测试充分后,打tag,master merge。这样就代表了一个发布。相比之下,我没看出一个release分支的好处?
关于release
release分支有2个作用:
- 减去去找最新tag的步骤,很多人上github都不一定找得到tag在哪里,但能切到release分支就一定能看到最新的发布的代码
- 如果有一个BUG比较重要紧急,要基于现有发布的版本+仅仅此BUG的修复后发一个新版本,那么可以从release分支接一个hotfix分支出来,开发完merge回release和当前的develop分支,再从release分支重新发版本,这样develop分支上新增的功能(可能还不稳定)不会被一起发布出去。没有release分支的话,要从tag去拉分支,这是个很麻烦的操作,会出现dettached head状态让人头疼
其实基本就是git flow,在它的基础上加了版本空间
- 我认为这个不是理由,找不到tag就去找药
- 从release分支接hotfix是从最近的release还是以前的release?
从release分支接hotfix是从最近的release还是以前的release?
每个大版本(x.x)只有一个release分支,永远代表这个大版本下最新的那个tag的内容
我其实一直没有完整的走过git flow,因为,感觉实在是有点重
那我可以基本认为,最大一个release应该==master。
虽然不太属于这个issue的内容,但我还是想问一句:如果从一个从前的大版本的release出来hotfix,搞定后如何merge到最新的release?
因为如果允许从历史release去hotfix,并且无法自动merge到最新release,那就会面临下面的选择:
- 手工merge
- 不merge
如果不允许,就不会有这些问题
如果从一个从前的大版本的release出来hotfix,搞定后如何merge到最新的release?
避免这种情况,hotfix肯定在最新发布的版本上搞,不然会出现3.1.4是3.1.2加上一个BUG修复,其功能比3.1.3更差,这是不合理的
我原来也认为git flow实在太重,但在维护了这么多仓库,这么多版本之后,慢慢地我改变了想法……