git merge 和 git rebase的区别

git rebase 让你的提交记录更加清晰可读

git rebase 的使用

rebase 翻译为变基,它的作用和 merge 很相似,用于把一个分支的修改合并到另外一个分支上。

如下图所示,下图介绍了经过 rebase 前后提交历史的变化情况。

现在我们来用一个例子来解释一下上面的过程。

假设我们现在有2条分支,一个为 <math xmlns="http://www.w3.org/1998/Math/MathML"> m a s t e r \color{#2196F3}{master} </math>master ,一个为 <math xmlns="http://www.w3.org/1998/Math/MathML"> f e a t u r e / 1 \color{#2196F3}{feature/1} </math>feature/1,他们都基于初始的一个提交 <math xmlns="http://www.w3.org/1998/Math/MathML"> a d d r e a d m e \color{#2196F3}{add \ readme} </math>add readme 进行检出分支,之后,master 分支增加了 <math xmlns="http://www.w3.org/1998/Math/MathML"> 3. j s \color{red}{3.js} </math>3.js,和 <math xmlns="http://www.w3.org/1998/Math/MathML"> 4. j s \color{red}{4.js} </math>4.js 的文件,分别进行了2次提交, <math xmlns="http://www.w3.org/1998/Math/MathML"> f e a t u r e / 1 \color{#2196F3}{feature/1} </math>feature/1 也增加了 <math xmlns="http://www.w3.org/1998/Math/MathML"> 1. j s \color{red}{1.js} </math>1.js 和 <math xmlns="http://www.w3.org/1998/Math/MathML"> 2. j s \color{red}{2.js} </math>2.js 的文件,分别对应以下2条提交记录。

<math xmlns="http://www.w3.org/1998/Math/MathML"> m a s t e r \color{#2196F3}{master} </math>master 分支如下图:

<math xmlns="http://www.w3.org/1998/Math/MathML"> f e a t u r e / 1 \color{#2196F3}{feature/1} </math>feature/1 分支如下图:

结合起来看是这样的:

此时,切换到 feature/1 分支下,执行 git rebase master ,成功之后,通过 log 查看记录。

如下图所示:可以看到先是逐个应用了 master 分支的更改,然后以 <math xmlns="http://www.w3.org/1998/Math/MathML"> m a s t e r \color{#2196F3}{master} </math>master 分支最后的提交作为基点,再逐个应用 <math xmlns="http://www.w3.org/1998/Math/MathML"> f e a t u r e / 1 \color{#2196F3}{feature/1} </math>feature/1 的每个更改。

所以,我们的提交记录就会非常清晰,没有分叉,上面演示的是比较顺利的情况,但是大部分情况下,rebase 的过程中会产生冲突的,此时,就需要手动解决冲突,然后使用 git addgit rebase --continue 的方式来处理冲突,完成 rebase,如果不想要某次 rebase 的结果,那么需要使用 git rebase --skip 来跳过这次 rebase

git merge 和 git rebase 的区别

不同于 git rebase的是,git merge 在不是 fast-forward(快速合并)的情况下,会产生一条额外的合并记录,类似 Merge branch 'xxx' into 'xxx' 的一条提交信息。

另外,在解决冲突的时候,用 merge 只需要解决一次冲突即可,简单粗暴,而用 rebase 的时候 ,需要一次又一次的解决冲突。

git rebase 交互模式

在开发中,常会遇到在一个分支上产生了很多的无效的提交,这种情况下使用 rebase 的交互式模式可以把已经发生的多次提交压缩成一次提交,得到了一个干净的提交历史,例如某个分支的提交历史情况如下:

进入交互式模式的方法是执行:

git 复制代码
git rebase -i <base-commit>

参数 base-commit 就是指明操作的基点提交对象,基于这个基点进行 rebase 的操作,对于上述提交历史的例子,我们要把最后的一个提交对象 ( <math xmlns="http://www.w3.org/1998/Math/MathML"> a c 18084 \color{#F19E38}{ac18084} </math>ac18084) 之前的提交压缩成一次提交,我们需要执行的命令格式是

git 复制代码
git rebase -i ac18084

此时会进入一个 vim 的交互式页面,编辑器列出的信息像下列这样。

想要合并这一堆更改,我们要使用 squash 策略进行合并,即把当前的 commit 和它的上一个 commit 内容进行合并, 大概可以表示为下面这样。

erlang 复制代码
pick  ... ...
s     ... ... 
s     ... ... 
s     ... ... 

修改文件后 按下 : 然后 wq 保存退出,此时又会弹出一个编辑页面,这个页面是用来编辑提交的信息,修改为 feat: 更正,最后保存一下,接着使用 git branch 查看提交的 commit 信息,rebase 后的提交记录如下图所示,是不是清爽了很多? rebase 操作可以让我们的提交历史变得更加清晰。
特别注意,只能在自己使用的 feature 分支上进行 rebase 操作,不允许在集成分支上进行 rebase,因为这种操作会修改集成分支的历史记录。

rebase 的风险

patch:【假设本地分支为 dev1,c1 和 c2 是本地往 dev1 分支上做的两次提交】把 dev1 分支上的c1和 c2 "拆"下来,并临时保存成 c1' 和 c2'。git 里将其称为 patch

<math xmlns="http://www.w3.org/1998/Math/MathML"> r e b a s e \color{red}{rebase} </math>rebase 会将当前分支的新提交拆下来,保存成 <math xmlns="http://www.w3.org/1998/Math/MathML"> p a t c h \color{red}{patch} </math>patch,然后合并进其他分支新的 <math xmlns="http://www.w3.org/1998/Math/MathML"> c o m m i t \color{red}{commit} </math>commit,最后将 <math xmlns="http://www.w3.org/1998/Math/MathML"> p a t c h \color{red}{patch} </math>patch 接进当前分支。这是 <math xmlns="http://www.w3.org/1998/Math/MathML"> r e b a s e \color{red}{rebase} </math>rebase 对多条分支的操作。对于单条分支, <math xmlns="http://www.w3.org/1998/Math/MathML"> r e b a s e \color{red}{rebase} </math>rebase 还能够合并多个 <math xmlns="http://www.w3.org/1998/Math/MathML"> c o m m i t \color{red}{commit} </math>commit 单号,将多个提交合并成一个提交。

git rebase -i [commit id]命令能够合并(整改) commit id 之前的所有 <math xmlns="http://www.w3.org/1998/Math/MathML"> c o m m i t \color{red}{commit} </math>commit 单。加上-i选项能够提供一个交互界面,分阶段修改commit信息并 <math xmlns="http://www.w3.org/1998/Math/MathML"> r e b a s e \color{red}{rebase} </math>rebase。

但这里就会出现一个问题:如果你合并多个单号时,一不小心合并多了,将别人的提交也合并了,此时你本地的 <math xmlns="http://www.w3.org/1998/Math/MathML"> c o m m i t h i s t o r y \color{red}{commit \ history} </math>commit history 和远程仓库的 <math xmlns="http://www.w3.org/1998/Math/MathML"> c o m m i t h i s t o r y \color{red}{commit \ history} </math>commit history 不一样了,无论你如何 <math xmlns="http://www.w3.org/1998/Math/MathML"> p u s h \color{red}{push} </math>push,都无法推送你的代码了。如果你并不记得 <math xmlns="http://www.w3.org/1998/Math/MathML"> r e b a s e \color{red}{rebase} </math>rebase 之前的 <math xmlns="http://www.w3.org/1998/Math/MathML"> H E A D \color{red}{HEAD} </math>HEAD 指向的 <math xmlns="http://www.w3.org/1998/Math/MathML"> c o m m i t \color{red}{commit} </math>commit 的 <math xmlns="http://www.w3.org/1998/Math/MathML"> c o m m i t I D \color{red}{commit \ ID} </math>commit ID 的话, <math xmlns="http://www.w3.org/1998/Math/MathML"> g i t r e f l o g \color{red}{git \ reflog} </math>git reflog 都救不了你。

tips: 你可以 <math xmlns="http://www.w3.org/1998/Math/MathML"> p u s h \color{red}{push} </math>push 时带上 <math xmlns="http://www.w3.org/1998/Math/MathML"> − f \color{red}{-f} </math>−f 参数,强制覆盖远程 <math xmlns="http://www.w3.org/1998/Math/MathML"> c o m m i t h i s t o r y \color{red}{commit \ history} </math>commit history,你这样做估计会被打,因为覆盖之后,团队的其他人的本地 <math xmlns="http://www.w3.org/1998/Math/MathML"> c o m m i t h i s t o r y \color{red}{commit \ history} </math>commit history 就与远程的不一样了,都无法推送了。

因此,请保证仅仅对自己私有的提交单进行 <math xmlns="http://www.w3.org/1998/Math/MathML"> r e b a s e \color{red}{rebase} </math>rebase 操作,对于已经合并进远程仓库的历史提交单,不要使用 <math xmlns="http://www.w3.org/1998/Math/MathML"> r e b a s e \color{red}{rebase} </math>rebase 操作合并 <math xmlns="http://www.w3.org/1998/Math/MathML"> c o m m i t \color{red}{commit} </math>commit 单。

相关推荐
大卫小东(Sheldon)7 小时前
面向 Git 用户的 jujutsu 使用入门
git
大飞pkz12 小时前
【Git】git lfs自动跟踪大文件
git·lfs·git lfs·大文件传入github·lfs大文件自动跟踪
自学也学好编程13 小时前
Git分支管理与工作流详解
git
自学也学好编程15 小时前
Git基础概念与常用命令详解
git
linrunxinnn18 小时前
Git 团队协作总结 —— 不只是版本控制的工具
git
吱吱02号机1 天前
<Git>从零创建远程新仓库(最小操作)
git
测试开发技术1 天前
使用 Git 时出现 unable to access,如何解决?
git·面试题
zhougl9962 天前
git项目,有idea文件夹,怎么去掉
java·git·intellij-idea
tmacfrank2 天前
Git 使用技巧与原理(一)—— 基础操作
git
dilvx2 天前
git 配置 default editor
git