git merge 和 git rebase 的区别

git merge vs. git rebase

本人原来一直都是个人单机使用git,使用的操作基本只限于git addgit commit,对git的其他操作都是一知半解。直到现在进入公司接触团队开发,需要了解必要的分支相关的知识,其中最让我费解的就是git mergegit rebase了,于是花了半天时间好好了解了一下相关知识,写下本文记录一下。

首先,本文不考虑发生冲突的情况,只是描述了两种操作的原理以及区别。

git merge操作

git merge的操作分为以下两种情况:

fast-forward模式

假设你现在的分支情况如图所示:

在这里插入图片描述

如今你已经完成了基于master分支的问题分支hotfix,此时你需要将hotfix分支进行合并,操作如下:

$ git checkout master
$ git merge hotfix
Updating f42c576..3a0874c
Fast-forward
 index.html | 2 ++
 1 file changed, 2 insertions(+)

git merge操作首先会找到两个分支的公共分支C2,判断公共分支C2到两分支的路线是否有分叉(即两分支的提交历史是否是线性的),如果没有分叉,则默认使用fast-forward模式,git合并两者时只会简单的将master指针从C2移动到hotfix指针相同的位置C4

在这里插入图片描述

三方合并

当然,在正常生产环境中出现公共分支有分叉的情况往往更容易见到。接着上文的情形,合并并删除hotfix分支后,你回到iss53的工作中完成了后续工作。

在这里插入图片描述

此时你需要将iss53合并到master分支,这里同样通过git merge进行合并操作:

$ git checkout master
Switched to branch 'master'
$ git merge iss53
Merge made by the 'recursive' strategy.
index.html |    1 +
1 file changed, 1 insertion(+)

此时两个分支的公共分支C2到两分支的路线有分叉,所以git会使用两分支所指快照C4C5以及两分支的公共祖先C2做一个简单的三方合并。

在这里插入图片描述

它将创建一个提交记录,其父提交记录有两个,此时的提交记录已经变成拓扑结构了。此时可以删除iss53分支,拓扑结构仍旧保留。

(注:对于前面的fast-forward的情况,如果要在此情况下执行三方合并,需要输入git merge --no-ff指令)

git rebase操作

理解rebase的字面意思对于了解该指令操作起到很好的作用。rebase的意思是“变基”,理解为“基底的改变”,琢磨这个单次的含义,继续下面的情形。

在这里插入图片描述

假设此时有两个分支,我们想将master分支合并到experiment(不要搞反对象,更改的分支为experiment),此时我们进行git rebase操作:

$ git checkout experiment
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: added staged command

首先给出git rebase的结果

在这里插入图片描述

下面来说原理,总结为:

  1. 找两分支的公共祖先C2,为当前基底
  2. 当前分支C4对于公共祖先C2的修改保存Actions(C2<-C4)
  3. 当前分支的基底从C2移动到合并的分支位置,即目标基底C3
  4. Actions(C2<-C4)依次应用于此时的基底

中间有一个很明显的基底切换的操作,这是rebase的重点。

这里拿出git merge合并experiment(更改的分支为master)的操作结果图与上面的git rebase结果进行一个比较:

在这里插入图片描述

根据分析,可以得到一些结论:

  1. git merge在三方合并的时候会产生一个新的提交,指向两个父提交,版本树呈拓扑结构;git rebase则会多一部分基底(零个或多个提交),不会出现指向多个父提交的情况,版本树呈线性结构
  2. git merge操作不会修改基底,git rebase操作会修改基底,修改基底的操作会导致历史信息产生改变(例如上文,rebase前是C0<-C1<-C2<-C4,rebase后是C0<-C1<-C2<-C3<-C4’,相当于修改了历史)

使用场景

两种合并方式的差异没有绝对的优劣,在不同的场景下,使用不同的合并方法可能会事半功倍。

在master分支上一定不要使用git rebase指令

因为rebase指令会修改历史,当你通过rebase操作将master分支的历史修改,那么master分支与所有其他的开发者的分支的历史信息都不一样了(因为其他开发者的分支的基底都和你的分支基底不相同),要解决这个问题非常麻烦。

推荐在功能分支上使用git rebase指令

通过git rebase指令,可以将master分支的最新版本作为基底,功能分支的版本更改都在最后面,这样利于功能分支版本操作(比如版本回退)。

本地拉取远端对应同一条分支,推荐使用git rebase指令

本地分支和远端分支本质上是不同的两个分支,所以在git pull操作中,其实包含git fetchgit merge两步操作,通过rebase操作,可以将本地分支的最新修改的版本都保存在本地分支的版本树的最后面,有利于版本回退等操作。

参考资料

Git 分支 - 分支的新建与合并

Git 分支 - 变基

Git Merge和Rebase的区别

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值