闲谈 git merge 与 git rebase 的区别

前言

相信大部分使用 Git 的朋友都会碰见相同的疑问,而且也从网上搜索了很多资料。那么,为何我还要写这篇文章呢?由于我想尝试从本身的角度解释这个问题,若是能给到你们灵光一闪的感悟,便善莫大焉啦。估计点进来的朋友也对 merge 和 rebase 有了必定了解,因此我也就不浪费篇幅再去详细介绍 merge 和 rebase,让咱们直入主题吧。html

merge 与 rebase 的区别

merge(如下说明都基于 merge 的默认操做)

如今假设咱们有一个主分支 master 及一个开发分支 deve,仓库历史就像这样:git

初始仓库历史

如今若是在 master 分支上 git merge deve:Git 会自动根据两个分支的共同祖先即 e381a81 这个 commit 和两个分支的最新提交即 8ab7cff696398a 进行一个三方合并,而后将合并中修改的内容生成一个新的 commit,即下图的 78941cbhexo

merge 合并图

rebase

rebase 是什么状况呢?仍是一个初始的仓库历史图:fetch

rebase初始仓库历史

若是是在 master 分支上 git rebase deve:Git 会从两个分支的共同祖先 3311ba0 开始提取 master 分支(当前所在分支)上的修改,即 85841bea016f64e53ec51,再将 master 分支指向 deve 的最新提交(目标分支)即 35b6708 处,而后将刚刚提取的修改依次应用到这个最新提交后面。操做会舍弃 master 分支上提取的 commit,同时不会像 merge 同样生成一个合并修改内容的 commit,至关于把 master 分支(当前所在分支)上的修改在 deve 分支(目标分支)上原样复制了一遍,操做完成后的版本历史就像这样:spa

rebase 合并图

能够看见 master 分支从 deve 分支最新提交 35b6708 开始依次提交了本身的三个 commit(因为是提取修改后从新依次提交,故 commit 的 hash 码与上面的85841bea016f64e53ec51 不一样)。code

rebase -i

rebase 操做加上 -i 选项能够更直观的看见被提取的 commit 信息。htm

仍然在 master 分支上 rebase deve 分支,不过此次要加上 -i 选项,即 git rebase -i deve,而后咱们能够获得这样一个文本信息框blog

rebase -i信息

  • A 区域内的信息说明了此次 rebase 操做提取了哪些 commit 记录(f9a7673edb2ba2),会链接到目标分支的哪一个 commit (9c86a5c)后面。能够根据 B 区域中的命令说明修改 pick 为其余命令,对该次提取出来的 commit 作额外的操做ip

  • B 区域内说明了本次 rebase 操做能够选用的命令开发

  • 经过 :wq 保存退出后,就会按照刚刚在 A 区域内设定的命令处理 commit 并 rebase。

冲突处理策略的不一样

  • merge 碰见冲突后会直接中止,等待手动解决冲突并从新提交 commit 后,才能再次 merge

  • rebase 碰见冲突后会暂停当前操做,开发者能够选择手动解决冲突,而后 git rebase --continue 继续,或者 --skip 跳过(注意此操做中当前分支的修改会直接覆盖目标分支的冲突部分),亦或者 --abort 直接中止该次 rebase 操做

总结:选择 merge 仍是 rebase?

  • merge 是一个合并操做,会将两个分支的修改合并在一块儿,默认操做的状况下会提交合并中修改的内容

  • merge 的提交历史忠实地记录了实际发生过什么,关注点在真实的提交历史上面

  • rebase 并无进行合并操做,只是提取了当前分支的修改,将其复制在了目标分支的最新提交后面

  • rebase 的提交历史反映了项目过程当中发生了什么,关注点在开发过程上面

  • merge 与 rebase 都是很是强大的分支整合命令,没有优劣之分,使用哪个应由项目和团队的开发需求决定

  • merge 和 rebase 还有不少强大的选项,可使用 git help <command> 查看

最后:一些注意点

  • 使用 merge 时应考虑采用默认操做,仍是 --no-ff--ff-only 的方式

  • rebase 操做会丢弃当前分支已提交的 commit,故不要在已经 push 到远程,和其余人正在协做开发的分支上执行 rebase 操做

  • 与远程仓库同步时,使用 pull 命令默认进行了 git fetch + git merge 两个操做,能够经过加上 --rebase 命令将 fetch 后的 merge 操做改成 rebase 操做,或者仅仅 'git fetch remoteName',而后才思考采起哪一种整合策略 git merge(or rebase) origin/master

  • 开发与 commit 时注意本身此时在哪一个分支上

  • 当有修改未 commit 时,不能进行 rebase 操做,此时能够考虑先用 git stash 命令暂存

参考

相关文章
相关标签/搜索