昨天改了git flow feature的实现,提供一个选项,finish时不再保留feature分支上的提交历史(http://www.jiangyouxin.net/2013/02/12/git_flow_1.html)。今天的主题是release分支。
在原版git flow的实现中,release分支与feature分支很像,都是基于develop创建,并在结束时合并回develop。所不同的是,release分支还要合并到master分支并打TAG。注意这里的次序是合并(git merge no-ff)在前,TAG在后,这在两个方面都是有点问题的:
(1) 如果master上,存在没有合并到develop和release分支的修改,则会有灾难性后果。
当然,如果所有开发者都严格遵守git flow的规范,这种情况不会出现;但git flow的原版中并没有对此做sanity检查。在准备发布时,release分支上的代码是经过测试的,但这个代码与master(如果master有过修改)的合并结果是未经测试的。在把TAG打在合并结点上,就得保证合并前后代码是一致的,否则就有些草率了。
(2) TAG是极强的标志(在gitk中有醒目的显示),足以区分版本边界;没有必要再单独创建一个merge结点。
在nvie的原文中有一句话,可以用来解释他对--no-ff的偏爱:the release branch is merged into master (since every commit on master is a new release by definition, remember)
也就是说,原作者期望每一次版本发布,都在master分支上产生一个(有且只有一个)提交结点,--no-ff就是用来创建这个结点的。遗憾的是,这在SVN等线性提交的版本管理系统中成立,在git中则不成立。git中merge结点的两个父亲是对等的,整条被合并的release分支(而不仅仅是最后那个合并结点)都是master分支的一部分,在这一点上,nvie画的那张图把他自己误导了:
上图的master分支看上去特别干净,只有少数几个结点,每个结点都是一个发布版本。但其实这张图里,除了develop分支最下面的那个黄色结点之外,都在master分支上。master只是一个指向最新发布版本的引用而已,要区分哪些结点代表发布版本,只能靠TAG。所以这里--no-ff是白费工夫的。
在我对git flow的修改中,这里git merge的参数反过来了,用的是--ff-only。如果出现上面的情况(1),merge会失败,此时报一个错误信息来警示用户(有的时候出现这条错误信息是正常的,详见下一篇 http://www.jiangyouxin.net/2013/02/14/git_flow_3.html);如果merge成功,由于是Fast Forward,在当前位置打TAG是安全的。
另一个问题,是git flow原作者可能没有去考虑,但厂里的开发却常有的情况:release分支创建之后,因为种种原因,该版本不需要再发布,但修改需要保留,下次发布时间再议。git flow release finish命令(git flow一个让人很不爽的地方就是命令太长)有一个参数-n(不打TAG),跟这个需求最接近。但光不打TAG不行,还得不向master合并才行。所以在我的版本中,-n的语义做了修改,相当于取消发布,release分支退化为feature分支,只向develop合并。
然后就是和feature分支类似的问题了:release分支的提交历史是否需要保留?我觉得大部分情况是需要保留的。release分支在版本发布之前创建,上面的提交大多是bug fix,而且各个提交之间的关联性较小,这一点与feature分支是大不一样的。git flow原版对release分支也提供了-S(squash)参数,但遗憾的是,实现也是有问题的;因为我现在也没把正确的实现写出来,这个就等以后有空再说了。
来源:oschina
链接:https://my.oschina.net/u/987964/blog/108566