详细图文并茂以及git flow工具解释参考: http://danielkummer.github.io/git-flow-cheatsheet/index.zh_CN.html

原文地址:http://nvie.com/posts/a-successful-git-branching-model/  

本文中我将介绍我在多年的项目开发中使用的开发模型,这个模型被实践检验为正确有效的模式。本文中,我将不会涉及到项目的任何细节,只讨论关于分支策略和release管理

为什么要使用Git?

网上有很多关于Git和集中式代码管理控制系统的比较,作为一个开发人员,我更喜欢Git,Git实际上颠覆了开发人员关于merge/branch的想法。从经典的CVS/SVN世界过来,merging/branching总是被认为是一个痛苦和令人胆寒的事情。但是在Git中,这些行为是非常简单和代价低廉的。比如在CVS/SVN的书籍中,branching和merging往往都在最后几章中讨论(专为高级用户所写),而在每一本Git的书籍中,这些merge/branch总在前三章中介绍(因为它们很基础)。

正是源于这些操作在Git中简单,重复的特性,branching/merging不再是一个令人生畏的事情。

Decenteralized but cdentralized:

库作为中央“truth”repo.在Git中,虽然这个repo可能被认为是中央的repo,但是你要明白GIT是一个分布式的版本控制系统,也就是说从技术角度来说没有这个central repo!我们更确切地将这个central repo称为origin

每个开发人员pull/push to origin.但是除了中央式的pull/push关系,每一个开发人员之间也可能从他们的子team之间pull changes。例如,对于两个或更多的开发人员同时工作在一个大的feature上,这种模型就更加有用了(特别是正在工作中的feature代码永久性push到origin前)。上面的图中,在alice和bob,alice和david,clair和david之间形成了subteam。

技术上说,实际上就是Alice定义了一个Git remote, 命名为bob,指向bob的repo,同样反之亦然。

The main branches

核心上说,开发模型被已有的模型所启发,中央repo将永久保留两个主要的branches:

  • master
  • develop

origin上的master分支对于每一个GIT用户来说是非常熟悉的.和master branch平行的,有一个另外叫做develop的分支。

我们考虑orgin/master作为main branch,这个分支上的HEAD总是反映了一个production-ready的状态;

我们将origin/develop视作一个HEAD永远指示为了下一个release而最近递交的开发变化。有些人比较喜欢将此称为integration branch.在这个分支上,每日的build将从这里构建。

当在develop分支上的代码达到一个稳定状态点,达到可以发布的状态时,所有的变更都应该merge back到master,并且在master上tag一个release number。

这样每次当变更merge back到master时,这就是一个新的production release by definition.我们更倾向于对此非常严格,因此理论上,我们可以使用一个Git hook sciprt实现每当有一个向master的commit,我们自动构建和部署master上的软件到生产环境上去(因为master总是一个Production ready的状态)

Supporting branches:

除了main branches: master和develop,我们的开发模型中也将使用一系列的supporting branches以便支持在team member之间实现并行开发,更加容易地实现feature的tracking,更方便地准备产品release,更好的辅助解决产品的问题。不像main branch(master,develop),这些branch总是有一个生命周期,因为他们最终将被删除。

我们建议以下几种类型的分支:

  • feature branches;
  • release branches
  • hotfix branches

每种非main branch都有一个特定的目的,并且有严格的定义规则:这个分支应该从那个分支来创建,以及该分支最终的merge targets都有明确的定义。下面我们将明确说明。

从技术角度来说,这些branch本身并无特别之处。这些branch的类型是由"how we use them"来分类的。他们就是简单的普通的Git branch.

Feature branches:

May branch off from: develop;

Must merge back into: develop;

Branch naming convention: 任何除了master,develop,release-*,hotfix-*之外都可以

Feature branch(或者被叫做topic branch)被用来为了即将到来的(upcoming)或者长远计划的release而做开发之用的。当开始开发一个feature时,这个feature的target release(目标release)在那时可能根本还确定。feature branch的本质是:只要feature仍在开发中,它将一直存续,但是最终它将被merged back到dvelop分支(to definitely add the new feature to the upcoming release)或者被discarded(in case of a disappointing experiment)。

Feature branche典型地只存在于开发人员的repo中,并不在origin repo中存在。

当开始一个新的feature开发时,feature branch从develop branch中创建出来

$ git checkout -b myfeature develop
Switched to a new branch "myfeature"

结束的feature将被merged into the develop branch以便在即将到来的release中添加这个feature.

$ 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

--no-ff flag使得这个merge动作即便是这个merge属于fast-forward(no conflict)也总会产生一个新的commit object。这样就避免了关于曾近为了开发一个新的feature而做了feature branch并递交了多个文件的历史。

上图中,后一个fast-forward merge的场景,你将无法得知哪些commit objects最终形成了那个feature---你可能必须手动的查阅所有的log信息才能得知。同样在后一个场景中,你想rollback一个feature也是一个非常头疼的问题,然而如果我们增加了--no--ff flag则很容易做到这些。

当然,使用--no-ff flag确实会产生一些可能是空的commit objects,但是这个坏处相比其带来的好处是可以忍受的。

Release branches:

May branch off from: develop

Must merge back into: develop and master

Branch naming convention: release-*

注意release branch一般命名只包含major+minor,而不包含patch。比如release-1.0,release-2.3,对于release-1.5.1这样的tag只存在于hotfix生成的版本中

Release branches支持准备一个新的产品release而存在。They allow for last-minute dotting of i’s and crossing t’s.而且,他们允许晓得bug fix并且为那个release准备一些meta-data(比如version number, build dates,etc)。这些工作都在一个release branch上做,那么develop分支总是很清晰地准备为下一个大的release接受新的feature.

开始从develop branch off一个新的release branch的时机往往是在当develop基本反映了新的release的可接受状态时。至少所有的必须在这个release中deliver的feature必须被merge到了develop分支,这个时刻就是创建release branch的时机。所有为将来release计划的feature都不能merge下来直到上一个release branch已经被创建。

通常直到将要到来的release被赋予一个版本号,这将是这个release branch的一个起点。直到那个时刻,develop分支反映了下一个release的变化,但是关于是否那个下一个release会最终变成0.3或者1.0并不是很清晰,直到release branch开始工作。这个决定在release branch 开始时决定下来,由项目的版本号命名规则来决定

Release branch由develop branch来创建。比如,版本v1.1.5是当前产品release,而我们将有一个大的release将被release。develop分支的状态已经为下一个release做好了准备,而我们决定这个release将命名为v1.2(而不是v1.1.6或者v2.0)。那么我们可以branch off并且给这个release branch一个1.2的名称:

$ 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
files changed, insertions(+), deletions(-)

在创建一个新的release branch并且切换到该branch后,我们bump the version number。这里bump-verison.sh是一个虚构的shell脚本,该脚本更改一些文件以便反映新的版本号变更。(这当然也可以是一个手工的变更)然后,这个bumped version number is commited.

这个新的branch可能会存续一段时间,直到这个release被正式rollout.在这个时间段内,bugfix可能会被应用到这个release branch上去(而不是应用到develop branch上去)。在这里增加大的新功能将被严格禁止。这些bugfix必须被merge到develop分支上去,这样又开始等待下一个大的release.

当releasea branch的状态真正达到实际能够release质量时,也需要做一些工作。首先,release branch需要merge到master(可能包含一些bug fix)(since every commit on master is a new release by definition, remember!)。接着,那个对master的commit必须被打上tag,以便该历史版本将来能够容易地被引用。最后,在release branch上做的bugfix变更需要被merge到develop上去,以便将来的release中包含这些bugfix。

前两步Git操作:

$ 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

release现在已经结束了,并且被打了标签1.2以便将来引用

为了将release branch上做的bugfix保持好,我们需要将这些fix merge到develop分支上:

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

在这一步,我们可能会碰到merge conflict(probably even, since we have changed the version number),如果发现conflict,则解决它并且commit掉

现在我们确实完成了这个release的工作,release branch可以被删除了:

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

Hotfix branches:

May branch off from:

master

Must merge back into:

develop and master

Branch naming convention:

hotfix-*

hotfix branch和release branch非常相似,因为他们本身也是用于为准备一个新的产品release而存在的(尽管是非计划的,往往由某个release现场发现紧急问题而触发的)。他们往往是由一个现场运行的产品release上报的问题来触发产生的。当一个critical bug必须马上解决时,一个hotfix branch将从master branch中的相应tag版本处branch off出来。这样做的本质是:团队其他成员可以在develop branch上继续工作,而指定团队一个人在这个hotfix branch上准备一个快速产品fix版本。

hotfix branch由master branch来创建。比如,假设v1.2是当前报严重问题的产品release版本,但是由于在develp branch上的变更还不稳定,所以我们开始从master上拉一个hotfix branch开始工作:

$ git checkout -b hotfix-1.2. master
Switched to a new branch "hotfix-1.2.1"
$ ./bump-version.sh 1.2.
Files modified successfully, version bumped to 1.2..
$ git commit -a -m "Bumped version number to 1.2.1"
[hotfix-1.2. 41e61bb] Bumped version number to 1.2.
files changed, insertions(+), deletions(-)

不要忘记bump the version number after branching off~!

然后,fix the bug,commit the fix in one or more seperate commits:

$ git commit -m "Fixed severe production problem"
[hotfix-1.2. abbe5d6] Fixed severe production problem
files changed, insertions(+), deletions(-)

Finishing a hotfix branch:

当完成该问题的fix时,bugfix需要merged back到master中去,同时也需要merge到develop branch中去,只有这样才能保证bugfix本身将会在下一个release中自动包含。这和release branch结束的动作是一样的。

首先,更新master并且tag the release:

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

下一步,也需要同时包含bugfix到develop分支中去:

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

在这里有一个例外的rule:当一个release branch当前存续,那么这个hotfix change需要merge到那个release branch中去,而不是develop分支。Back-merging the bugfix into the release branch will eventually result in the bugfix being merged into the develop too, when the release branch is finished, (If work in develop immediately requires this bugfix and cannot wait for the release branch to be finished, you may safely merge the bugfix into the develop now already as well.)

最后,删除这个临时的branch

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

原创:在github上大型项目团队branch策略:

Summary:

虽然本篇文章本身对于分支策略并无令人震惊之处,但是那个big picture图片确实对我们的项目成功有非常重要的意义。它构建了一个优雅地心智模型,而该模型易于理解并且允许团队充分理解整个产品的branching/releasing流程。

两个team member有两个repo,互为remote,当git push时,有可能出现conflict,这时需要做的事情是必须先git pull操作,解决冲突以后,再做git push。这和在一个repo时merge冲突是类似的。

https://github.com/nvie/gitflow 是一个对git扩充的flow惯例,非常实用

成功的GIT开发分支模型和策略的更多相关文章

  1. Git开发分支管理

    远程仓库有master和dev分支的情况 1. 克隆代码 git clone https://somewhere.com/master-dev.git 2. 查看所有分支 git branch --a ...

  2. Git开发分支使用与管理规范

    最稳定的代码放在 master 分支上(相当于 SVN 的 trunk 分支),我们不要直接在 master 分支上提交代码,只能在该分支上进行代码合并操作,例如将其它分支的代码合并到 master ...

  3. 第二篇:版本控制git之分支

    有人把 Git 的分支模型称为它的`‘必杀技特性’',也正因为这一特性,使得 Git 从众多版本控制系统中脱颖而出. 为何 Git 的分支模型如此出众呢? Git 处理分支的方式可谓是难以置信的轻量, ...

  4. git branch 分支

    几乎所有的版本控制系统都以某种形式支持分支. 使用分支意味着你可以把你的工作从开发主线上分离开来,以免影响开发主线. 在很多版本控制系统中,这是一个略微低效的过程——常常需要完全创建一个源代码目录的副 ...

  5. 理解git的分支原理,更好地使用git

    文章内容转载于git-scm. 部分内容涉嫌枯燥 一.git分支概念 几乎每一种版本控制系统都以某种形式支持分支.使用分支意味着你可以从开发主线上分离开来,然后在不影响主线的同时继续工作.在很多版本控 ...

  6. 从本质彻底精通Git——4个模型1个周期1个史观1个工作流

    一.什么是Git? Git是一个开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目. Git是Linus Torvalds为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软 ...

  7. 一个成功的 Git 分支模型(适用于商业应用开发)

    在这篇文章中,我将推广一下大约一年前我介绍过的一些项目(公私皆有)中使用的开发模型,它们的结果都非常成功.有段时间我非常想写出来分享一下,但是我至今才抽出时间来.我不会言及任何项目细节,仅讨论分支策略 ...

  8. 介绍一个成功的 Git 分支模型 Release 分支

    英文原文: http://nvie.com/posts/a-successful-git-branching-model/ 中文版: 在这篇文章中,我提出一个开发模型.我已经将这个开发模型引入到我所有 ...

  9. 一个成功的Git分支模型

    原文: http://www.juvenxu.com/2010/11/28/a-successful-git-branching-model/ 本文中我会展示一种开发模型,一年前该模型就已经被我用在所 ...

随机推荐

  1. 用DIV+CSS切割多背景合并图片 CSS Sprites 技术

    很久之前就在互联网网站和一些js插件中见过这种技术的应用,当时觉得很麻烦,就没有用,也没有去深究. 近段时间一直在做前台的一些东西,涉及到很多div+css的问题.这个东东我又碰到了,所以我花了点时间 ...

  2. 单例模式及C++实现

    单例模式及C++实现代码 C++中的单例模式http://blog.csdn.net/hackbuteer1/article/details/7460019

  3. Subclasses

    Given a collection of numbers, return all possible subclasses. public class Solution { public List&l ...

  4. idHTTP访问百度

    百度屏蔽了indy的客户端标识的 Mozilla/3.0 (compatible; Indy Library),把‘Indy Library’去掉就可以了. try IdHTTP1.Request.U ...

  5. mysql 存储过程事务支持回滚

    如图查看表的属性: InnoDB 支持事务. MyISAM 不支持事务,不过性能更优越.

  6. 安装mysql之后,存入中文出现乱码

    如图显示:安装mysql之后,存入中文出现乱码 解决方案: 找到如图的文件位置 打开进行如图的修改: 结果:

  7. 数据库(.udl)简单测试连接

    当我们烦于打开数据库进行连接的时候,我们可以用udl进行测试连接,并可以获得连接字符串. 1.新建一个txt文件,然后将后缀改成udl保存. 2.双击打开udl文件. 3.进行数据库连接测试. 4.用 ...

  8. Shell练习 验证号码

    原文: https://leetcode.com/problems/valid-phone-numbers/ Given a text file file.txt that contains list ...

  9. weka平台下手动造.arff的数据

    若数据为 sunny,hot,high,FALSE,nosunny,hot,high,TRUE,noovercast,hot,high,FALSE,yesrainy,mild,high,FALSE,y ...

  10. android学习--radiogroup学习

    这个阶段在学习android的相关基本UI现将相关练习的代码粘贴在此便于后期学习之用(radio控件) 效果图:   main_layout.xml <?xml version="1. ...