前面一篇文章中提到了"git pull"等价于"git fetch"加上"git merge",然后还提到了pull命令支持rebase模式,这篇文章就介绍一下merge和rebase之间有什么差别。

由于我们主要是想看看merge跟rebase之间的区别,这里就是用本地仓库的分支进行演示了。

merge

其实在介绍分支的那篇文章中已经介绍过了一些分支merge的内容,这里就进行一些补充和总结。

下面我们基于本地一个仓库开始介绍,当前仓库的分支情况如下:

其实,merge命令总结下来会有三种情况发生:

  1. merge命令不生效

    当目标分支是当前分支的祖先commit节点,也就是说当前分支已经是最新的了,在这种情况下merge命令没有任何效果。

    在当前仓库中,当我们把dev分支merge到master的时候,会得到"Already up-to-date."

  2. Fast-forward合并模式

    当前分支是目标分支的祖先commit节点时,会发生Fast-forward的merge,看下图

    这时的对象模型就更新了,这里merge的操作只是把dev分支的HEAD引用进行更新,指向最新的commit对象

  3. 三方合并

    请参照"Git Step by Step – (5) Git分支(branch)"中分支合并的内容。如果没有冲突,Git会帮我们完成分支的合并,如果有冲突,就需要我们手动解决冲突了。

Fast-forward合并模式

在前面我们看到了Fast-forward合并模式,这种合并模式很简单,只是HEAD引用的更新。但是合并后,我们从"git log"中将看不到分支的信息。

在Git中,我们可以选择在merge的时候禁止Fast-forward。现在,我们通过"git reset --hard HEAD~1"撤销前面的Fast-forward合并。

然后,我们在merge命令中加上"--no-ff"进行合并操作。

cherry-pick

这里我们将插入介绍一个非常有用的命令,虽然它跟merge没有什么关系。

在实际应用中,我们可能会经常碰到这种情况,在分支A上提交了一个更新,但是后来发现我们同样需要在分支B上应用这个更新。那么这时cherry-pick就可以帮助你解决问题。

我们要做的就是通过"git reflog"找到A上那个更新的SHA1哈希值,然后切换到B分支上使用"git cherry-pick"。

当我们手动合并过冲突,然后继续执行"cherry-pick"时候,Git会给出友好的交互界面,如果我们不需要更新这个提交的message,我们可以直接":wq"进行保存退出。到此,这个"cherry-pick"操作就成功了。

rebase

前面我们介绍了merge,现在来看看rebase。在merge的过程中,比较好的就是我们可以看到分支的历史信息,但是,如果分支很多的时候,这个分支历史可能就会变得很复杂了。如果我们使用rebase,那么提交的历史会保持线性。

rebase的原理:先将当前分支的HEAD引用指向目标分支和当前分支的共同祖先commit节点,然后将当前分支上的commit一个个apply到目标分支上,apply完以后再将HEAD引用指向当前分支。是不是有点绕,下面我们看个实例。

下面就开始rebase的介绍,我们会基于master新建一个release-1.0的分支,并在该分支上提交一个更新。

这时,我们在release-1.0分支上执行"git rebase master",就会得到下面的对象关系图。

根据rebase的工作原理进行分析:

  1. 把当前分支的HEAD引用指向"00abc3f"
  2. 然后将当前分支上的commit一个个apply到目标分支,这里就是把"ed53897"更新apply到master上;注意,如果没有冲突,这里将直接生成一个新的更新
  3. 最后更新当前分支的HEAD引用执行最新的提交"8791e3b"

这个就是rebase操作,可以看到通过rebase操作的话,我们的commit历史会一直保持线性。在这种情况下,当我们切换到master分支,然后进行"git merge release-1.0"分支合并时,master将会直接是Fast-forward合并模式,commit历史也会是线性的。

当然rebase操作也会产生冲突,当一个冲突发生的时候,我们可以skip过当前的patch(一定要当心,不要随便使用,以免丢失更新);也可以手动的解决冲突,然后继续rebase操作

rebase交互模式

其实,rebase还有别的很强大功能,比如rebase交互模式,通过交互模式我们可以改变commit的信息,删除commit,合并commit以及更改commit的顺序等等。

假如我们现在想要更新一个commit的信息,我们就可以使用rebase交互模式,找到commit的哈希值,然后进入交互模式。


根据rebase的操作提示,我们选择edit操作,然后保存退出。

这时,Git将会提示我们,是进行更改,还是可以继续操作。这里我们通过"git commit --amend"进入编辑模式。

在编辑模式中对commit进行更新,然后保存退出,继续rebase操作。

关于rebase交互模式的其他命令,这里就不做介绍了,有兴趣的同学可以google一下。

总结

这篇文章主要对merge和rebase进行了介绍。对于最终的结果而言,rebase和merge是没有区别的,不会发生rebase和merge导致最终更新不一致的情况。

rebase和merge的差别主要是:

  • rebase更清晰,因为commit历史是线性的,但commit不一定按日期先后排,而是当前分支的commit总在后面(参考rebase原理)
  • merge之后commit历史变得比较复杂,并且一定程度上反映了各个分支的信息,而且 commit按日期排序的。

大家可以根据自己的项目需求进行选择使用哪种方式拉取远程的更新。

Git Step by Step – (8) Git的merge和rebase的更多相关文章

  1. git代码合并:Merge、Rebase的选择

    代码合并:Merge.Rebase的选择 Zhongyi Tong edited this page on Dec 7, 2015 · 3 revisions Pages 19 Home 2.1 快速 ...

  2. Git Step by Step – (7) Git远程仓库(续)

    上一篇文章介绍了Git远程仓库的一些使用,但是还是有些东西需要补充一下,所以有了这个续篇. .gitignore 前一篇中,我们介绍了Git的patch功能,当我们生成patch之后,"gi ...

  3. Git Step by Step – (5) Git分支(branch)

    在前面两盘文章中介绍了Git的基本原理,都是理论知识.这篇文章我们再次回到实践中,看看Git分支(branch)的使用. 在代码版本控制工具中,都会有branch的概念.刚开始建立版本仓库的时候,我们 ...

  4. Git Step by Step

    原文地址:http://www.cnblogs.com/wilber2013/category/643754.html 1.Git简介 2.Git本地仓库 3.Git对象模型 4.探索.git目录 5 ...

  5. Git Step by Step – (6) Git远程仓库

    前面文章中出现的所有Git操作都是基于本地仓库的,但是日常工作中需要多人合作,不可能一直都在自己的代码仓库工作.所以,这里我们就开始介绍Git远程仓库. 在Git系统中,用户可以通过push/pull ...

  6. Git Step by Step – (4) 探索.git目录

    前面一篇文章介绍了Git对象模型,接下来我们就进入".git"目录看看到底有什么东西,目录中哪些东西又跟Git对象模型相关.结合这个目录,我们将进一步了解Git的工作原理. .gi ...

  7. Git Step by Step – (3) Git对象模型

    前面一篇文章介绍了本地仓库的一系列操作,下面我们将进一步了解Git的工作原理,介绍Git对象模型. 刚开始使用Git的时候,对Git对象模型.工作原理并不理解,但是经过一段时间的使用.熟悉之后,然后再 ...

  8. Git Step by Step – (2) 本地Repo

    前面一篇文章简单介绍了Git,并前在Windows平台上搭建了Git环境,现在就正式的Git使用了. Git基本概念 在开始Git的使用之前,需要先介绍一些概念,通过这些概念对Git有些基本的认识,这 ...

  9. Git 少用 Pull 多用 Fetch 和 Merge

    本文有点长而且有点乱,但就像Mark Twain Blaise Pascal的笑话里说的那样:我没有时间让它更短些.在Git的邮件列表里有很多关于本文的讨论,我会尽量把其中相关的观点列在下面. 我最常 ...

随机推荐

  1. 1px的border

    css中是这样写的: div{ border-bottom: 1px solid #dfe5e4; } 但在手机上,像素比不为 1 ,由于 webview 的灰度渲染, border 一般会显示为 2 ...

  2. 【C】——fread函数和read函数的区别

    1,fread是带缓冲的,read不带缓冲. 2,fopen是标准c里定义的,open是POSIX中定义的. 3,fread可以读一个结构.read在linux/unix中读二进制与普通文件没有区别. ...

  3. Java初始化顺序(静态变量、静态初始化块、实例变量、实例初始化块、构造方法)

    1.执行顺序 1.1.一个类中的初始化顺序 类内容(静态变量.静态初始化块) => 实例内容(变量.初始化块.构造器) 1.2.两个具有继承关系类的初始化顺序 父类的(静态变量.静态初始化块)= ...

  4. android适配pad和部分手机底部虚拟按键+沉浸式状态栏

    在使用沉浸式状态栏设置界面全屏时发现pad和部分手机(华为和魅族系统自带)屏幕底部会带有虚拟按键,遮挡住界面本身的一部分. 为了设置隐藏,在网上找了一些方法,设置Activity主题再在布局加fits ...

  5. Coneroller执行时候的-26374及-26377错误

    有时候一些不必要的关联也会引起这个问题, 1.首先看下脚本中有没有使用了自动关联(web_reg_save_param) 2.在Virtual的脚本里查询下web_reg_save_param的参数使 ...

  6. mock数据和代码生成

    git clone https://gitee.com/fleam/CodeGeneration.git

  7. 第三百三十四节,web爬虫讲解2—Scrapy框架爬虫—Scrapy爬取百度新闻,爬取Ajax动态生成的信息

    第三百三十四节,web爬虫讲解2—Scrapy框架爬虫—Scrapy爬取百度新闻,爬取Ajax动态生成的信息 crapy爬取百度新闻,爬取Ajax动态生成的信息,抓取百度新闻首页的新闻rul地址 有多 ...

  8. Mybatis增删改查(CURD)

    前面的小节我们已经讲到用接口的方式编程.使用这种方式,需要注意的一个地方就是,在User.xml 配置文件中,mapper namespace="com.yiibai.mybatis.int ...

  9. Python——eventlet.greenpool

    该模块提供对 greenthread 池的支持. greenthread 池提供了一定数量的备用 greenthread ,有效限制了孵化 greenthread 过多导致的内存不足,当池子中没有足够 ...

  10. Linux使用 tar命令-g参数进行增量+差异备份、还原文件

    原文链接:http://www.cnblogs.com/gnuhpc/ 完整备份: 建立测试路径与档案 mkdir test touch test/{a,b,c} 在test下生成三个文件 执行完整备 ...