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 单。

相关推荐
源码12152 小时前
git命令提交项目
git
周星星_少年只有一个面10 小时前
git入门环境搭建
git
五味香10 小时前
Linux学习,ip 命令
linux·服务器·c语言·开发语言·git·学习·tcp/ip
aPurpleBerry11 小时前
【问题解决】Github上手动Delete file之后, git remote add+git push出错
git·github
M_emory_13 小时前
解决 git clone 出现:Failed to connect to 127.0.0.1 port 1080: Connection refused 错误
前端·vue.js·git
Make_magic13 小时前
Git学习教程(更新中)
大数据·人工智能·git·elasticsearch·计算机视觉
不穿铠甲的穿山甲13 小时前
git-.git目录解析
git
唔知小罗1 天前
git config是做什么的?
git
不是鱼1 天前
新人程序猿必备的git技能(超实用基础版)
git·github
Exclusive_Cat1 天前
Git的使用(基础语句)
git