git merge 和 git rebase的区别

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

git rebase 的使用

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

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

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

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

m a s t e r \color{#2196F3}{master} master 分支如下图:

f e a t u r e / 1 \color{#2196F3}{feature/1} feature/1 分支如下图:

结合起来看是这样的:

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

如下图所示:可以看到先是逐个应用了 master 分支的更改,然后以 m a s t e r \color{#2196F3}{master} master 分支最后的提交作为基点,再逐个应用 f e a t u r e / 1 \color{#2196F3}{feature/1} 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 的操作,对于上述提交历史的例子,我们要把最后的一个提交对象 ( a c 18084 \color{#F19E38}{ac18084} 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

r e b a s e \color{red}{rebase} rebase 会将当前分支的新提交拆下来,保存成 p a t c h \color{red}{patch} patch,然后合并进其他分支新的 c o m m i t \color{red}{commit} commit,最后将 p a t c h \color{red}{patch} patch 接进当前分支。这是 r e b a s e \color{red}{rebase} rebase 对多条分支的操作。对于单条分支, r e b a s e \color{red}{rebase} rebase 还能够合并多个 c o m m i t \color{red}{commit} commit 单号,将多个提交合并成一个提交。

git rebase -i [commit id]命令能够合并(整改) commit id 之前的所有 c o m m i t \color{red}{commit} commit 单。加上-i选项能够提供一个交互界面,分阶段修改commit信息并 r e b a s e \color{red}{rebase} rebase。

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

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

因此,请保证仅仅对自己私有的提交单进行 r e b a s e \color{red}{rebase} rebase 操作,对于已经合并进远程仓库的历史提交单,不要使用 r e b a s e \color{red}{rebase} rebase 操作合并 c o m m i t \color{red}{commit} commit 单。

相关推荐
透明的玻璃杯2 小时前
git应用
git
炸炸鱼.3 小时前
Git+Jenkins实战(一):从零搭建自动化发布与回滚系统(附完整代码)
git·jenkins
言6666 小时前
要忽略前端依赖包node_modules的文件在目录下 git暂存区消失
git
胡小禾6 小时前
Git Worktree
git
程序员小羊!7 小时前
18 GIt
git
怣疯knight7 小时前
Git 本地分支关联远程分支 常用命令汇总
git
ANNENBERG7 小时前
git分支开发管理
git
坤坤藤椒牛肉面7 小时前
GIT的使用
git
w3296362717 小时前
使用 OpenCode 在 Windows 上加速安装 Playwright 的完整指南
windows·git
我家媳妇儿萌哒哒1 天前
git:无法推送refs到远端。您可以试着运行“拉取”功能,整合您的更改。
git