GitHub Flow & Git Flow 基于Git 的两种协作开发模式

01、分支模型

  • master:长期分支,一般用于管理对外发布版本,每个 commit 对一个 tag,也就是一个发布版本
  • develop:长期分支,一般用于作为日常开发汇总,即开发版的代码
  • feature: 短期分支,一般用于一个新功能的开发
  • hotfix :短期分支 ,一般用于正式发布以后,出现 bug,需要创建一个分支,进行 bug 修补。
  • release :短期分支,一般用于发布正式版本之前(即合并到 master 分支之前),需要有的预发布的版本进行测试。

master和develop作为主要分支。

新功能的开发在feature上进行,该分支从develop分支派生,功能开发完毕后merge到develop分支。 一般feature分支都存在与开发者本地,除非该分支需要多方合作才提交到远程仓库。

如何保证和develop分支的代码同步?每天从develop分支拉去最新的代码,使用rebase命令 不要使用pull,每次合并上游更改时feature 分支都会引入一个外来的合并提交,使用pull会生成一个新的合并commit。

在将其他分支的代码合并到当前分支时,如果那个分支是当前分支的父分支,为了保持图表的可读性和可追踪性,可以考虑用 git rebase 来代替 git merge;反过来或者不是父子关系的两个分支以及互相已经 git merge 过的分支,就不要采用 git rebase 了,避免出现重复的冲突和提交节点。

release分支是从develop分支派生, bug fix只在release分支上进行,该分支也是QA的测试分支,开发结束后同时合并进develop和master分支

使用merge request将release分支的提交合并master分支,并打上tag。

hotfix可以单独出一个分支,也可以直接在release分支上进行。

所有master上的代码都是从release分支合并进去的。

追踪远程develop分支

git checkout -b develop origin/develop

feature 分支操作

获取dev分支最新代码

$ git pull --rebase origin dev
或者
$ git rebase dev $ git checkout -b 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

rebase最大的好处是你的项目历史会非常整洁。首先,它不像git merge 那样引入不必要的合并提交。其次,如上图所示,rebase导致最后的项目历史呈现出完美的线性——你可以从项目终点到起点浏览而不需要任何的Fork。这让你更容易使用git log 、git bisect 和gitk 来查看项目历史。 不过,这种简单的提交历史会带来两个后果:安全性和可跟踪性。如果你违反了Rebase黄金法则,重写项目历史可能会给你的协作工作流带来灾难性的影响。此外,rebase不会有合并提交中附带的信息——你看不到feature分支中并入了上游的哪些更改。

rebase的黄金法则
git rebase 的黄金法则便是,绝不要在公共的分支上使用它。 比如说,如果你把master分支rebase到你的feature分支上会发生什么

场景:你在feature上开发了一些功能还没有能够提交,现在有个Bug需要在develop分支上fix,怎么操作?

在feature分支上 执行 add & stash ,将当前的更新暂存起来

切换到develop分支,fix bug,commit & push(也可以不push)

切换到feature分支,rebase develop分支,发现冲突就解决冲突

最后 git stash pop ,弹出之前暂存的内容,这时也可能发生冲突,也比较好解决

这里主要就是应用了stash的功能,防止在feature上开发的功能还未能够提交,同时又有紧急的bug需要fix。

release 分支操作

# 合并到master
$ 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 # 合并到develop
$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff release-1.2 # 删除release分支
$ git branch -d release-1.2

hotfix 分支操作

当产品发布出去之后,有紧急的bug,就需要从master分支中拉出一个hot fix分支。 这么做的好处是develop分支上的同事可以继续进行开发,另一个团队则可以在master分支上进行一个产品修复更新。 修复好之后,合并到mater分支和develop分支。

这里有一个特殊情况,如果当时的release分支还存在,那么hotfix的更新需要merge到相应的release分支上。 如果release分支已经不存在了,那么就只需要merge到master分支和develop分支。

创建远程分支

git push origin local_branch:remote_branch
local_branch必须为你本地存在的分支,remote_branch为远程分支,如果remote_branch不存在则会自动创建分支。

02、开发规范

commit规范

只要坚持做到以下几点就 OK 了:

  1. 提交时的粒度是一个小功能点或者一个 bug fix,这样进行恢复等的操作时能够将「误伤」减到最低;
  2. 用一句简练的话写在第一行,然后空一行稍微详细阐述该提交所增加或修改的地方;
  3. 不要每提交一次就推送一次,多积攒几个提交后一次性推送,这样可以避免在进行一次提交后发现代码中还有小错误。

谁说历史不可篡改了?前提是,想要合并的那几次提交还没有推送到远程!

Commit Message 格式

<type>(<scope>): <subject>
<空行>
<body>
<空行>
<footer>

type

  • feat:新功能(feature)
  • fix:修补bug
  • docs:文档(documentation)
  • style: 格式(不影响代码运行的变动)
  • refactor:重构(即不是新增功能,也不是修改bug的代码变动)
  • test:增加测试
  • chore:构建过程或辅助工具的变动

Scope
用来说明本次Commit影响的范围,即简要说明修改会涉及的部分。这个本来是选填项,但从AngularJS实际项目中可以看出基本上也成了必填项了。

Subject

用来简要描述本次改动,概述就好了,因为后面还会在Body里给出具体信息。并且最好遵循下面三条:

  • 以动词开头,使用第一人称现在时,比如change,而不是changed或changes
  • 首字母不要大写
  • 结尾不用句号(.)

Body

<body>里的内容是对上面subject里内容的展开,在此做更加详尽的描述,内容里应该包含修改动机和修改前后的对比。

Footer

footer里的主要放置不兼容变更和Issue关闭的信息

Revert

此外如果需要撤销之前的Commit,那么本次Commit Message中必须以revert:开头,后面紧跟前面描述的Header部分,格式不变。并且,Body部分的格式也是固定的,必须要记录撤销前Commit的SHA值。

提交

在具体开发工作中主要需要遵守的原则就是「使每次提交都有质量」,只要坚持做到以下几点就 OK 了:
1. 提交时的粒度是一个小功能点或者一个 bug fix,这样进行恢复等的操作时能够将「误伤」减到最低;
2. 用一句简练的话写在第一行,然后空一行稍微详细阐述该提交所增加或修改的地方;
3. 不要每提交一次就推送一次,多积攒几个提交后一次性推送,这样可以避免在进行一次提交后发现代码中还有小错误。
 
假如已经把代码提交了,对这次提交的内容进行检查时发现里面有个变量单词拼错了或者其他失误,只要还没有推送到远程,就有一个不被他人发觉你的疏忽的补救方法——
使用 git rebase -i [SHA] , 具体参考,link
 

推送

当自己一个人进行开发时,在功能完成之前不要急着创建远程分支。
 

拉取

git pull --rebase
1. 把本地repo从上次pull之后的变更暂存起来
2. 恢复到上次pull时的情况
3. 套用远端的变更
4. 最后再套用刚暂存下来的本地变更
 
有冲突怎么办?
rebase跟merge类似,出现conflict会暂停rebase动作,需要你手动修复后,然后才可以继续动作。这也是rebase比merge复杂一点的地方:merge如果发生conflict,你只需要解决冲突一次,然后commit出去就完成了。而rebase的conflict可能会发生在上述步骤4的每一次重新套用上,所以可能需要解决冲突好几次。
 
到底什么时候用merge?什么时候用rebase?
如果你修改比较多,预期会有较多的conflict,建议用merge。(不过,如果是多次大范围的主题式修改,那是不是应该一开始就多开一个branch来做呢?)。
如果改动范围较小,不太预期有conflict,则建议可以加上rebase参数。
 
如果想要把 rebase 當做 git pull 的預設值,可以在專案的 .git/config 加上
[branch "master"]
remote = origin
merge = refs/heads/master
rebase = true
 
也可以直接加到 ~/.gitconfig 讓所有的 tracked branches 都自動套用這個設定:
[branch]
autosetuprebase = always

 

合并

在将其他分支的代码合并到当前分支时,如果那个分支是当前分支的父分支,为了保持图表的可读性和可追踪性,可以考虑用 git rebase 来代替 git merge;反过来或者不是父子关系的两个分支以及互相已经 git merge 过的分支,就不要采用 git rebase 了,避免出现重复的冲突和提交节点。

分支命名

除了主要分支的名字是固定的之外,派生分支是需要自己命名的,这里就要有个命名规范了。强烈推荐用如下形式:
feature——按照功能点(而不是需求)命名;
release——用发布时间命名,可以加上适当的前缀;
hotfix——GitLab 的 issue 编号或 bug 性质等。

另外还有 tag,用语义化的版本号命名。

03、链接

Git 分支模型与开发规范的更多相关文章

  1. 近期关于CI/CD策略以及git分支模型的思考

    近两个月由于个人处于新环境.新项目的适应阶段,没怎么提笔写些文章.中间有好几个想法想记录下来分享,但受限于没有很好的时间段供自己总结思考(也可以总结为间歇性懒癌和剧癌发作),便啥也没有更新.借这个周末 ...

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

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

  3. 项目开发中git常用命令、git工作流、git分支模型

    #新建代码库git init # 在当前目录新建一个Git代码库git init [project-name] # 新建一个目录,将其初始化为Git代码库git clone [url] # 下载一个项 ...

  4. 成熟的 Git 分支模型

    个人博客原文: 成熟的 Git 分支模型 今天介绍一下工作中会用到的 Git 分支模型. 先贴上图以表敬意 闲言 在学校不管是自己写课程设计还是给老师做项目,有 2 到 3 个人一起协作开发时就会使用 ...

  5. Git 分支模型

    翻译自:https://nvie.com/posts/a-successful-git-branching-model/ 在这篇文章中,主要介绍 Git 分支模型.不会谈论任何项目的细节,只讨论分支策 ...

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

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

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

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

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

    在这篇文章中介绍的开发模型在大约一年前已经在我的私有项目和工作引入的,而且已经被证明是非常成功的.我想写一些关于这个模型的东西已经好一段时间了,但是一直苦于没有时间,不过现在可以了.我不想探讨任何项目 ...

  9. Git分支模型

    转自:http://www.cnblogs.com/byeyear/archive/2012/11/28/2793374.html 本文介绍一种使用Git进行源代码管理的分支模型,着重于如何使用Git ...

随机推荐

  1. [自学] MIT的EECS本科+研究生课程【持续更新中-2020.06.02】

    前言 我的本科是读的电子信息工程,研究生跟着老师做项目,参与到深度学习中来,毕业后做了算法工程师,工作之后愈发发现,不论从事什么岗位,基础都很重要,但现在也没有时间再读一遍本科了,自学的话也不知道从何 ...

  2. 微信小程序里如何使用npm?小程序集成友盟举例

    1.执行npm初始化指令 小程序根目录,命令执行如下指令: npm init 执行后会让加载项目初始信息,具体截图如下: 2.执行安装npm包指令 在这我们举个例子,以接入友盟统计SDK为例,执行命令 ...

  3. Linux 硬盘挂载及开机挂载

    一.分区 主分区.扩展分区.逻辑分区的区别 主分区:包含操作系统启动所必需的文件和数据的硬盘分区,如需在硬盘上安装操作系统,该硬盘必须得有一个主分区 扩展分区:除主分区外的分区,不能直接使用,必须再划 ...

  4. C#9.0新特性之四:顶级程序语句(Top-Level Programs)

    1 背景与动机 通常,如果只想用C#在控制台上打印一行"Hello World!",这可不是Console.WriteLine("Hello World!"); ...

  5. 第3章 Python的数据类型 第3.1节 功能强大的 Python序列概述

    一.概述 序列是Python中最基本的数据结构,C语言中没有这样的数据类型,只有数组有点类似,但序列跟数组差异比较大. 序列的典型特征如下: 序列使用索引来获取元素,这种索引方式适用于所有序列: 序列 ...

  6. 【Alpha冲刺阶段】Scrum Meeting Daily6

    [Alpha冲刺阶段]Scrum Meeting Daily6 1.会议简述 会议开展时间 2020/5/27 8:00 - 8:15 PM 会议基本内容摘要 每日汇报 个人进度.遇到的困难.明日的计 ...

  7. Algorithm homework 1

    一.已知下列递推式: \[C(n)= \begin{cases} 1 & , & n = 1 \\ 2C(n/2) + n - 1& , & n \geq 2 \end ...

  8. ARC109D - L

    平面上一开始有三个点\((0,0),(0,1),(1,0)\)形成成L形(点连续),每次操作可以将一个点改变位置,使得得到的仍然是L形.给出终止L形的位置,问移动的最小步数. \(|x|,|y|\le ...

  9. 使用纯js 不导包实现 table 导出 Excel

    1.将js粘贴到项目 2.设置table标签 id3.定义按钮,调用方法即可 1 <!DOCTYPE html> 2 <html lang="zh_CN"> ...

  10. C++ 纯虚函数与抽象类——virtual 和纯说明符 “=0”

    什么时候使用纯虚函数 某些类,在现实角度和项目角度都不需要实例化(不需要创建它的对象),这个类中定义的某些成员函数只是为了提供一个形式上的接口,准备上子类来做具体的实现.此时这个方法就可以定义为&qu ...