Swift学习16.1:git merge和git rebase的区别?
概述
首先我们要知道,git merge
和 git rebase
做的事情其实是一样的,它们被设计用来 将一个分支的更改 并入 另一个分支
,只不过是方式有些不同
merge
我们知道,将 master
分支合并到 feature
分支最简单的办法就是用下面的两个命令:
1 | // 切换到当前 feature 分支 |
或者,你也可以用一行命令实现上面的功能
1 | git merge master feature |
feature
分支中心的合并提交(merge commit)将两个分支的历史连在了一起,你会得到下面的分支结构:
merge
好处在于它是一个 安全的操作
,现有的分支不会被更改,避免了 rebase
潜在的缺点;另一方面,意味着每次合并上游更改时,feature
分支都会引入一个外来的合并提交,如果 master 很活跃,或多或少会污染你的分支历史
什么是rebase?
rebase
在git中是一个非常有魅力的命令,使用得当会极大提高自己的工作效率;相反,如果乱用,会给团队中其他人带来麻烦。它的作用简要概括为:可以对某一段线性提交历史进行编辑、删除、复制、粘贴;因此,合理使用 rebase
命令可以使我们的提交历史干净、简洁!
不要通过rebase对任何已经提交到公共仓库中的commit进行修改(你自己一个人玩的分支除外)
rebase作用?
作为 merge
的 替代选择
,你可以用下面的命令 将 feature 分支并入 master 分支
1 | git checkout feature |
上面的命令会把整个 feature
分支 移动
到 master
分支的 后面
,有效的把所有 master
分支上新的提交 并入
过来。如下图:
由上图可以看出,先是逐个应用了 master
分支的更改,然后以 master
分支最后的提交作为 基点
,再逐个应用 feature
的每个更改
注:
如果rebase
过程中产生冲突,需要手动解决冲突,使用git addn .、git rebase --continue
来解决冲突,完成rebase
如果不想要某次rebase
的结果,使用git rebase --skip
来跳过这次rebase
合并多个 commit 为一个完整 commit?
当我们在本地仓库中提交了多次,在我们把本地提交 push
到公共仓库中之前,为了让提交记录更简洁明了,我们希望把分支下 B、C、D三个提交记录合并
为一个完整的提交,然后再 push
到公共仓库。
现在我们模拟一个环境,在 master
分支上只有一次 commit
提交 A
,在 zj_feature
分支上添加了 四次 commit
提交 A B C D
:
1 | // 提交到暂缓区 |
当我们提交了四次之后:
1 | // 查看提交日志 |
我们的目标是把 最后三个 B C D
提交合并为一个提交,这里我们使用命令:
1 | git rebase -i [startpoint] [endpoint] |
其中 -i
的意思是 --interactive
,即弹出交互式的界面让用户编辑完成合并操作,[startpoint] [endpoint]
指定了一个编辑区间,如果不指定 [endpoint]
,则该区间的终点默认是当前分支 HEAD
所指向的 commit
(注:该区间指定的是一个 前开后闭
的区间)。
在查看 git log
日志后,我们运行以下命令:
1 | // commit 前7位 |
或
1 | git rebase -i HEAD~3 |
然后我们会看到如下界面:
上面未被注释的部分列出的是我们本次 rebase 操作包含的所有提交,下面注释部分是 git 为我们提供的命令说明。买一个 commit id 前面的 pick 表示指令类型,git 为我们提供了以下几个命令:
1 | p:pick 保留该 commit |
根据我们的需求,我们将 commit
内容编辑如下:
1 | pick 06d4d03 add v2 |
然后是注释修改界面:
编辑完保存即可完成commit的合并了,我们用 git log 查看一下合并的记录:
将某一段commit粘贴到另一个分支上
当我们项目中存在多个分支,有时候我们需要将某一个分支中的一段提交同时应用到其他分支中,就像下图:
在实际模拟中,我们创建了 master
和 zj_feature
两个分支,我们在 zj_feature
分支上提交了 B、C、D、E、F
五次,如下图:
master分支:
zj_feature分支:
我们希望将 zj_feature
分支中的 C~E
部分 复制
到 master
分支中,这时我们就可以通过 rebase
命令来实现(如果只是复制某一两个提交到其他分支,建议使用更简单的命令: git cherry-pick
)。
我们使用命令的形式为:
1 | git rebase [startpoint] [endpoint] --onto [branchName] |
其中 [startpoint] [endpoint]
仍然和上一个命令一样指定了一个编辑区间(前开后闭
),--onto
的意思是要 将该指定的提交复制到哪个分支上
。
1 | // B-29541ef,E-1a2f8ab |
注:因为
[startpoint] [endpoint]
指定的是一个前开后闭
的区间,为了让这个区间包含C
提交,我们将区间起始点向后退了一步。
我们发现报错:
补充知识点:
$ git rebase –abort
会放弃合并,回到 rebase 操作之前的状态,之前的提交不会丢弃
$ git rebase –skip
会讲引起冲突的 commits 丢弃掉
$ git rebase –continue
合并冲突,结合git add 文件
命令一起用与修复冲突,提示开发者,一步一步地有没有解决冲突
出现上述的报错执行下面的命令:
1 | mac@bogon RebaseDemo % git add . |
运行完成后查看当前分支的日志:
可以看到,C~E
部分的提交内容 已经复制
到了 G
的后面了,大功告成?NO!我们看一下当前分支的状态:
当前 HEAD
处于游离状态,实际上,此时所有分支的状态应该是这样:
所以,虽然此时 HEAD
所指向的内容正是我们所需要的,但是 master
分支是没有任何变化的,git
只是将 C~E
部分的提交内容复制一份粘贴到了 master
所指向的提交后面,我们需要做的就是将 master
所指向的 提交id
设置为当前 HEAD
所指向的提交 id
就可以了,即:
1 | mac@bogon RebaseDemo % git checkout master |
此时我们查看一下当前分支和log日志:
此时我们才大功告成!
如果操作失误,回退到某个版本
1 | git reset --hard 1a2f8ab |
总结
如果你想要一个
干净的、线性的提交历史,并且没有合并提交
,你应该使用git rebase
如果你想要
保存项目完整的历史
,并且避免重写公共分支上的 commit
,你应该使用git merge
- Post title:Swift学习16.1:git merge和git rebase的区别?
- Post author:张建
- Create time:2023-05-09 11:36:26
- Post link:https://redefine.ohevan.com/2023/05/09/Swift/Swift学习16.1:git-merge和git-rebase的区别?/
- Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.