Git的分支模型

原来对于源码管理中分支的创建并没有很好的概念,只有一个简单朴素的概念:在已经发布的以前版本上进行开发时,就创建一个分支;或者要同时开发两个版本,就创建分支,并没有对分支进行什么样的管理。今天看了这篇文章(A successful Git branching model)后,对分支有了一个更好的认识,感觉在源码管理中,确实应该利用好分支的概念。这儿就参照前面这篇文章讲的整理一下其中的内容。

关于Git的几个理念

  • 分支与合并:在Git中分支与合并是很平常的事情,在开发过程中要适应经常进行分支和合并操作。在Git中,分支只是一个指针,并不会进行物理拷贝,所以快捷易用。
  • 非中心化:虽然平常都有一个Git服务器,称为origin,实际上origin跟每个开发人员机器上的代码库是平等的。我认为只是我们在借用它来永久保存代码,来在各开发人员之间协同。但从技术上来说,它跟各人机器上的库没有什么不同。
  • 分支:Git上所有的分支都是一样的,虽然一般都有一个master分支,但它与我们创建的其它分支并没有什么不同,只是我们在使用上区别对待而已。

总述

分支模型,主要讲在开发过程中需要创建的几种分支的管理方式。这儿说的“几种”是为管理需要,只是逻辑上的区分。主要有以下几种分支:

  • 主要分支:
    • master
    • develop
  • 辅助分支:
    • feature
    • release
    • hotfix

这个图比较系统地体现了它们之间的关系:

image

一个分支可以认为是一个被隔离的工作空间,master和develop是两个长期保留的工作空间,其它的工作空间根据需要随时创建,完成相应任务后,将工作成果合并到develop和maste上,然后删除之。

主要分支

主要分支是所有开发过程中必不可少的分支。原来我都是只用master这一个,现在觉得需要再加develop这一个。

master和develop是两个并行的分支,在代码库创建一开始,就把它们都建好。这两个分支的生命周期最长,应该跟整个产品的生命周期一样。主要分支都创建在origin上。

master分支:我们把正式发版的产品代码放到master分支中。master中的每一次提交,都对应产品的一个版本,HEAD总是最新的版本。

develop分支:是开发用的主要分支,HEAD反应了开发人员为开发下一版本所提交的最新状态。这个分支常用来进行每天晚上的自动构建。

合并时机

develop分支上的代码稳定之后,将要发版之时,将develop合并到master上,并打标签。合并使使用--no-ff选项,避免在master上生成大量的revision。(有时在将要发版时,会创建release分支,这时就不是develop分支直接向master合并,而是release分支分别向master和develop合并。)

每一次向master的合并,都是一次定义明确的发版,必须严格遵循这个约定。所以理论上讲,我们可以在master上加一个触发器,每次提交时,自动触发进行产品新版本的构建。

辅助分支

辅助分支是根据开发需要而创建的分支,它们的生命周期一般不会很长,用完(向master或develop分支合并后)就可以删除了。

辅助分支都是为一个特定目的而创建的,而且,对于它们应该从哪个分支上创建及最后应该合并到哪个分支上,都有严格的约束。

feature分支

  • 分支来源:develop
  • 最后合并:develop
  • 命名规则:除master、develop、release-*、或 hotfix-*之外的都可以。
  • 目的:feather分支是为将来版本开发一个新的功能,这个功能将要在哪个版本中体现还不一定。也可能开发了一段时间之后最后放弃不要了。

feature分支有时可能只存在于开发人员的库中,并没有push到origin上。

新功能开发完成后,合并到develop分支,确定在下一个版本中体现该功能。合并时也要使用--no-ff选项。

image
  • 创建feature分支
$ git checkout -b myfeature develop
Switched to a new branch "myfeature"
  • 合并一个完成的功能到develop分支
$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff myfeature
Updating ea1b82a..05e9557
(Summary of changes)
$ git branch -d myfeature
Deleted branch myfeature (was 05e9557).
$ git push origin develop

release分支

  • 分支来源:develop
  • 最后合并:master和develop
  • 命名规则:release-*
  • 目的:用来准备一个新版本的发布。当想要发布一个新版本,但develop分支还要继续开发下一版本时,就创建一个release分支来做要发布的新版本的开发工作。

可以参看最前面的那个完整的图。

  • 创建一个release分支
$ git checkout -b release-1.2 develop
Switched to a new branch "release-1.2"
$ ./bump-version.sh 1.2
Files modified successfully, version bumped to 1.2.
$ git commit -a -m "Bumped version number to 1.2"
[release-1.2 74d9424] Bumped version number to 1.2
1 files changed, 1 insertions(+), 1 deletions(-)

bump-version.sh是一个假想的命令,意思是要做一些关于修改版本号之类的工作。

  • 完成release工作,合并分支

这个新版本发布后,一方面,要合并到master上,形成一个新的版本;另一方面,要把做的所有修改都合并到develop上。

$ git checkout master
Switched to branch 'master'
$ git merge --no-ff release-1.2
Merge made by recursive.
(Summary of changes)
$ git tag -a 1.2

$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff release-1.2
Merge made by recursive.
(Summary of changes)

$ git branch -d release-1.2
Deleted branch release-1.2 (was ff452fe).

在release分支的开发过程中,也可能多次向develop分支合并修复的bug。

如果要发布新版本时,没有同时进行下一版本的开发,就没有必要新建release分支,直接在develop分支上进行即可。等完成发版的测试工作,确定要发版后,把develop分支合并到master上。

hotfix分支

  • 分支来源:master
  • 最后合并:master和develop
  • 命名规则:hotfix-*
  • 目的:对已发布的版本出现的重大bug进行修复。跟release分支类似,完成修复后要发布一个新版本。

hotfix应该是对最新版本的修复。如果已经发布2.0,就不能再去在1.0上去修复出一个1.1版本,而是需要用2.0版本或修复后的2.1版本去完成bug的修复。如果说由于某些限制(比如2.0跟1.0不兼容,或商务上不允许以2.0去修复1.0)而必须需要在1.0上修复出一个1.1版本,参见后面的讨论。

image
  • 创建一个hotfix分支

比如,当前已经发布1.2版本,develop上正在进行下一版本(1.3或2.0)的开发,这时,需要对1.2版本的bug做紧急修复,修复后要发版。

$ git checkout -b hotfix-1.2.1 master
Switched to a new branch "hotfix-1.2.1"
$ ./bump-version.sh 1.2.1
Files modified successfully, version bumped to 1.2.1.
$ git commit -a -m "Bumped version number to 1.2.1"
[hotfix-1.2.1 41e61bb] Bumped version number to 1.2.1
1 files changed, 1 insertions(+), 1 deletions(-)
  • 完成修复后,合并hotfix分支

完成修复后需要把这个分支合并到master和develop分支。

$ git checkout master
Switched to branch 'master'
$ git merge --no-ff hotfix-1.2.1
Merge made by recursive.
(Summary of changes)
$ git tag -a 1.2.1

$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff hotfix-1.2.1
Merge made by recursive.
(Summary of changes)

$ git branch -d hotfix-1.2.1
Deleted branch hotfix-1.2.1 (was abbe5d6).

有一个例外情况是,如果当前正有一个release分支进行中,那么hotfix分支应该合并到release分支上而不是develop分支,在release分支结束时,将修复一并合并到develop分支上。

多master、develop分支

上面所述的模型是一个基本的模型。对于一般情况下的软件开发只需要一个master和一个develop分支,直接套用这个模型即可。对于有多条主线同时进行的产品研发来说,在这个模型上变通一下,复制多份就是。

比如,象tomcat,同时有6.x、7.x和8.x版本在维护升级着,不可能只有一个master分支,否则,这个分支上的tag就会在6.x、7.x、8.x之间来回跳跃,显得很乱。可以这样来处理:

比如当前已经发布7.0版本,前一版本是6.4,现在需要将6.4版本升级到6.5,就可以在当前master分支上的6.4版本上创建一个分支,叫master-6.4,同时从master-6.4上创建一个develop-6.4,将这两个分支做为主要分支,参考上面的模型,进行6.x版本的后续开发。

同样,若当前已经发布8.0版本,想从上一版本7.5开始维护7.x版本,就可以创建master-7.5和develop-7.5两个分支,参考上面的模型,进行7.x的后续开发。

前面在讨论hotfix分支时提到,在发布2.0版本后,“如果说由于某些限制(比如2.0跟1.0不兼容,或商务上不允许以2.0去修复1.0)而必须需要在1.0上修复出一个1.1版本”,这时就可以采用类似上面的办法,创建一个master-1.0分支,这儿可能就不需要创建develop-1.0分支了,直接创建hotfix-1.1分支,完成修复后,将hotfix-1.1合并到master-1.0上。可根据需要将hotfix-1.1也合并或不合并到master分支上。

所有的master*分支和develop*分支都是主分支,都应该长期保存。

你可能感兴趣的:(Git的分支模型)