默认情况下合并分支常常直接使用 git merge 命令,是最方便快速的合并方法.其实这种情况下 git 采用的是 fast forward 模式,特点是删除分支后,会丢失分支信息,好像从来没存在该分支一样,而我们推荐的是recursive 模式,能够保留分支的版本记录.

递归模式(recursive)

创建并切换 dev 分支,提交版本后切换回 master 分支,然后再合并 dev 分支,这不过这一次不再使用 git merge dev 命令:

# 创建并切换 dev 分支
$ git checkout -b dev
Switched to a new branch 'dev'
# 提交版本
$ echo "git checkout -b dev" >> test.txt
$ git add test.txt
$ git commit -m "git checkout -b dev"
[dev 44d68f6] git checkout -b dev
1 file changed, 1 insertion(+)
# 切换回 master 分支
$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 6 commits.
(use "git push" to publish your local commits)
$

现在添加 --no-ff 参数禁用 fast forward 模式,即git merge --no-ff:

$ git merge --no-ff -m "git merge --no-ff dev" dev
Merge made by the 'recursive' strategy.
test.txt | 1 +
1 file changed, 1 insertion(+)
$

上述内容显示,这次使用的不再是 fast forward 模式,而是 recursive 模式,那让我们看一下提交历史有什么不同吧!

$ git log --pretty=oneline --graph
* 22fbef7 (HEAD -> master) git merge --no-ff dev
|\
| * 44d68f6(dev) git checkout -b dev
|/
* 3b8f434 fix conflict
|\
| * 0fe95f8 git commit c2
* | 0949cc3 git commit c3
|/
* 5c482cd git commit c1
* 413a4d1 see https://snowdreams1006.github.io/git/usage/branch-overview.html
* 9c30e51 learn git branch
* b3d8193 (origin/master, origin/HEAD) see https://snowdreams1006.github.io/git/usage/remote-repository.html
* 8e62564 add test.txt
* 9b196aa Initial commit
$

这种递归模式(recursive) 有一个明显的特点就是会产生一个新的 commit ,并不会像之前快速前进模式(fast forward)那样单纯更改 HEAD 的指向.

秉承着阅后即焚的习惯,分支一旦合并后就立即删除,现在删除 dev 分支,看一下会发生什么:

# 删除 dev 分支
$ git branch -d dev
Deleted branch dev (was 44d68f6).
# 查看提交历史
$ git log --pretty=oneline --graph
* 22fbef7 (HEAD -> master) git merge --no-ff dev
|\
| * 44d68f6 git checkout -b dev
|/
* 3b8f434 fix conflict
|\
| * 0fe95f8 git commit c2
* | 0949cc3 git commit c3
|/
* 5c482cd git commit c1
* 413a4d1 see https://snowdreams1006.github.io/git/usage/branch-overview.html
* 9c30e50 learn git branch
* b3d8193 (origin/master, origin/HEAD) see https://snowdreams1006.github.io/git/usage/remote-repository.html
* 8e62564 add test.txt
* 9b196aa Initial commit
$

由此可见,删除 dev 分支后仅仅少了 dev 的引用而已,原来 dev 分支所做的更改全部保留下来了!

快速前进模式(fast forward)

创建并切换 dev 分支,提交版本后切换回 master 分支,然后再合并 dev 分支,使用 git merge dev 命令:

# 创建并切换 dev 分支
$ git checkout -b dev
Switched to a new branch 'dev'
# 提交版本
$ echo "fast forward" >> test.txt
$ git add test.txt
$ git commit -m "fast forward"
[dev 3fe94c0] fast forward
1 file changed, 1 insertion(+)
$

现在切换回 master 分支,采用默认的git merge 命令合并 dev 分支:

$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 8 commits.
(use "git push" to publish your local commits)
sunpodeMacBook-Pro:git-demo sunpo$ git merge dev
Updating 22fbef7..3fe94c0
Fast-forward
test.txt | 1 +
1 file changed, 1 insertion(+)
$

上述内容显示这次合并采用的是快速前进模式(fast forward),让我们看一下提交历史:

$ git log --pretty=oneline --graph
* 3fe94c0 (HEAD -> master, dev) fast forward
* 22fbef7 git merge --no-ff dev
|\
| * 44d68f6 git checkout -b dev
|/
* 3b8f434 fix conflict
|\
| * 0fe95f8 git commit c2
* | 0949cc3 git commit c3
|/
* 5c482cd git commit c1
* 413a4d1 see https://snowdreams1006.github.io/git/usage/branch-overview.html
* 9c30e50 learn git branch
* b3d8193 (origin/master, origin/HEAD) see https://snowdreams1006.github.io/git/usage/remote-repository.html
* 8e62564 add test.txt
* 9b196aa Initial commit
$

上述内容表明,此次合并并没有产生新的 commit ,只是更改下 HEAD 指向而已(HEAD -> master, dev).

同样,现在删除 dev 分支,再看一下提交历史:

# 删除 dev 分支
$ git branch -d dev
Deleted branch dev (was 3fe94c0).
# 查看提交历史
$ git log --pretty=oneline --graph
* 3fe94c0 (HEAD -> master) fast forward
* 22fbef7 git merge --no-ff dev
|\
| * 44d68f6 git checkout -b dev
|/
* 3b8f434 fix conflict
|\
| * 0fe95f8 git commit c2
* | 0949cc3 git commit c3
|/
* 5c482cd git commit c1
* 413a4d1 see https://snowdreams1006.github.io/git/usage/branch-overview.html
* 9c30e50 learn git branch
* b3d8193 (origin/master, origin/HEAD) see https://snowdreams1006.github.io/git/usage/remote-repository.html
* 8e62564 add test.txt
* 9b196aa Initial commit
$

由此可见,快速前进模式一旦删除分支后就彻底丢失了分支的信息,即便是从提交历史中也找不到曾经存在的痕迹!

分支策略

git 是分布式版本控制系统,同时鼓励大量使用分支,如此一来大量的分支该如何管理?

实际开发中,建议准从以下原则进行分支管理:

  • master 分支作为主干分支,负责对外提供服务,要求稳定可靠,因为应该专人负责更新维护.
  • dev 分支作为开发分支,取代 master 分支的开发地位,积累到一定产出时再合并到 master 分支.
  • feature 分支作为新功能分支,根据实际情况动态创建,删除分支,并适时合并到 dev 分支.
  • bugFixed 分支作为修复特定 bug 分支,可能由 master 分支衍生而来,也可能由 dev 分支衍生等等,修复后及时合并到原分支.
  • custom 自定义分支,项目成员私有分支,由上级领导分配任务后各开发人员自行选择创建自己的分支,并根据实际情况决定合并到 dev 分支或 feature 等分支.

小结

  • 快速前进模式(git merge <name>)不保留分支合并历史,递归模式(git merge --no-ff -m <remark> <name>)保留分支合并历史.
  • 制定大家都认同的分支管理原则,并严格准守规则.

git 入门教程之分支策略的更多相关文章

  1. git 入门教程之分支总览

    分支就是一条独立的时间线,既有分支,必有主干,正如一棵树谈到树枝,必有树干一样的道理.我们先前对git 的全部操作默认都是在主干上进行的,这个主干也是一种特殊的分支,名为 master 分支. 无论是 ...

  2. git 入门教程之分支管理

    背景 什么是分支?简单地说,分支就是两个相对独立的时间线,正常情况下,独立的时间线永远不会有交集,彼此不知道对方的存在,只有特定情况下,两条时间线才会相遇,因为相遇,所以相知,因为相知,所以改变! 正 ...

  3. git 入门教程

    git 入门教程之协同开发 前面我们已经介绍过远程仓库的相关概念,不过那时并没有深入探讨,只是讲解了如何创建远程仓库以及推送最新工作成果到远程仓库,实际上远程仓库对于团队协同开发很重要,不仅仅是团队协 ...

  4. 廖雪峰Git入门教程

    廖雪峰Git入门教程  2018-05-24 23:05:11     0     0     0 https://www.liaoxuefeng.com/wiki/00137395163059296 ...

  5. 创建与合并分支-git入门教程

    在版本回退里,你已经知道,每次提交,Git都把它们串成一条时间线,这条时间线就是一个分支.截止到目前,只有一条时间线,在Git里,这个分支叫主分支,即master分支.HEAD严格来说不是指向提交,而 ...

  6. git 入门教程之远程仓库

    远程仓库 如果说本地仓库已经足够个人进行版本控制了,那么远程仓库则使多人合作开发成为可能. 如果你只是打算自己使用git,你的工作内容不需要发布给其他人看,那就用不到远程仓库的概念. git 是分布式 ...

  7. 史上最简单Git入门教程

    一:Git是什么? Git是目前世界上最先进的分布式版本控制系统. 工作原理 / 流程: Workspace:工作区Index / Stage:暂存区Repository:仓库区(或本地仓库)Remo ...

  8. 解决冲突-git入门教程

    人生不如意之事十之八九,合并分支往往也不是一帆风顺的. 准备新的feature1分支,继续我们的新分支开发: $ git checkout -b feature1 Switched to a new ...

  9. 深入学习:Windows下Git入门教程(下)

    声明:由于本人对于Git的学习还处于摸索阶段,对有些概念的理解或许只是我断章取义,有曲解误导的地方还请见谅指正! 一.分支 1.1分支的概念. 对于的分支的理解,我们可以用模块化这个词来解释:在日常工 ...

随机推荐

  1. tensorflow 迭代周期长,每个epoch时间变慢

    理论上,session启动后,每个epoch训练时间应该是差不多,而且不会因为迭代周期变长,epoch时间变慢.原因是session里定义了tf.op导致的,每一次迭代都会在graph里增加新的节点, ...

  2. yii学习笔记--url解析

    在通过yiic命令生成了一个app之后,我们通过浏览器访问会看到这样的一个页面.   点击home时,url为:http://localhost/blog/index.php?r=site/index ...

  3. mysql 开发进阶篇系列 3 SQL 优化(索引使用方法)

    一. 本章介绍mysql中的索引的分类,存储,使用方法的介绍 1.  索引的存储分类 MyISAM存储引擎的表的数据和索引是自动分开存储的,各自是独立的一个文件, innodb 存储引擎的表的数据和索 ...

  4. 【杂谈】Remember-Me的实现

    前言 此篇随笔记录了Remember-Me实现过程中出现的问题和解决方案,以及相关的思考. 正文 1. RememberMe是什么? RememberMe意为记住我,对应登录界面的那个勾选项.另一种说 ...

  5. 在.net core 中PetaPoco结合EntityFrameworkCore使用codefirst方法进行开发

    在.net core开发过程中,使用最多的就是注入方法.但是在.net core使用PetaPoco时,PetaPoco还不支持进行注入方式进行处理一些问题. 今天对PetaPoco进行了一些扩展,可 ...

  6. Java 锁优化

    一.重量级锁   Java中,Synchronized是通过对象内部的一个叫做监视器锁(monitor)来实现的.但是监视器锁本质又是依赖于底层的操作系统的Mutex Lock来实现的.而操作系统实现 ...

  7. 为什么你作为一个.NET的程序员工资那么低?

    最近看到很多抱怨贴,也许有一定的道理,但是你想过没,为什么大部分.NET程序员工资相对低?我个人是这么看的: 大批半罐子水的程序员,永远被局限在.NET的原始的小圈圈里.前端不会(你放弃了一项很重要的 ...

  8. python闯关之路(五)前端开发

    一,HTML部分 1,XHTML和HTML有什么区别 HTML是一种基本的WEB网页设计语言,XHTML是一个基于XML的置标语言最主要的不同: XHTML 元素必须被正确地嵌套. XHTML 元素必 ...

  9. [THUWC2017] 在美妙的数学王国畅游

    Description 懒得概括了.. Solution 挺裸的LCT+挺裸的泰勒展开吧... 稍微了解过一点的人应该都能很快切掉...吧? 就是把每个点的函数泰勒展开一下然后LCT维护子树sum就行 ...

  10. [PHP] php + phpstudy + phpstrom + xdebug + postman开启调试

    主体 php + phpstudy + phpstrom + xdebug + postman + vue + chrome 使用的是前后端分离的开发方式,vue 在 webpack 通过代理进行请求 ...