共计 3526 个字符,预计需要花费 9 分钟才能阅读完成。
有幻想,有干货,微信搜寻 【大迁世界】 关注这个在凌晨还在刷碗的刷碗智。
本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试残缺考点、材料以及我的系列文章。
Hi!大家好,我是小智!用 Git 做版本控管应该是大部分工程师每天都会碰到的工作流程之一,但我在应用上不外乎就是 push
、pull
、merge
、checkout
或 log
等几个指令,更深刻一点就一问三不知了 😂,在面试时被问到了这个问题:「你晓得 Git 的 merge 和 rebase 有什麽不同吗?」
听完后我间接困惑,对我来说 rebase 就是用来整顿 commit 的工具,竟然还能够和 merge 做比拟?
git-rebase
先来说说平时我会用 rebase 这个指令来干嘛,如果我新增了一个单元测试,而后 commit
,这时候 log
就会多一条 commit
的纪录:
然而在 commit 完才发现,我少写了另一个测试案例,因而在补上之后,我又 commit 了一次:
这时记录中会多出另外一条 commit
,不过对我来说,这两个 commit
在做的其实是同一件事,于是我在 push 到 remote 之前,就会想要先整顿一下 commit,把这两条记录合并起来。
要把这两条记录合并起来有两个办法,第一个是 reset
到增加第一个测试案例之前,而后间接做一次 commit
。第二个办法就是用 rebase
来解决!
首先让咱们看看目前的 log:
我的目标是把 9dc67ff
和 87af945
整顿成一个,所以要调整的 commit 是从 init, 也就是 commit id 为 7eb57cb
之后的所有 commit,搭配上 rebase
指令的话就是:
git rebase -i 7eb57cb
输出完后就会跳到 vim 的编辑画面:
画面上会看到 7eb57cb
后的所有 commit(目前就只有 9dc67ff
和 87af945
),接着把 9dc67ff
的 pick
改成 squash
,示意把它与前一个 commit 做合并。先点一下 i 后开始用 vim 编辑内容:
编辑完后,能够点 esc 再输出 :wq
做保留,如果只是好奇进来玩看看,不想保留的话就输出 :q!
。完结下面的流程后,再查看一次 log,会发现两条 commit 变成一笔了。保留完会跳到 commit message 的画面,这边能够让你输出合并后的 commit message,但我就不改了,一样间接保留:
完结上方的流程后,再查看一次 log,会发现两笔 commit 变成一笔了:
先 nice,上述的操作为 rebase 的 interactive mode,在 git rebase 后输出的 -i 其实就是 interactive
的缩写。
git-merge
大家应该对 merge 指令都十分相熟,因为在做新性能的时候,通常都会拉一个分支进来,实现后再 merge
回 master 或 develop 等次要分支。操作流程如下:
在 merge 的时候会有两种状况,第一种是 fast-forward
,会把被合并分支的 HEAD 的 reference 移到要合併分支内最新的 commit 上,上方操作的 merge 后果就是 fast-forward
,master 的 HEAD 被移到 string-library 的最新 commit,画成图的话就是这样子:
然而如果在执行 merge 的时候产生抵触,那分支的合并行为就会和 fast-forward 有点不同了。举例来说,我别离在 master 和 string-library 的同一个文件增加内容,那当我执行 merge 的时候就会要求先修复抵触:
修复完后,再执行 commit 实现合并,而这一次合并时,会再多一个 commit 是无关 merge 了 string-library 分支的纪录:
这个状况画成图就会像这样子:
git-rebase 与 git-merge 的差别
看完上方对 rebase
和 merge
的介绍后,你兴许会想说:
「咦?那这两个不是齐全不同的货色吗?」
对的,本来我也是这麽认为,始终到我去看了 git-rebase 的文档,才发现原来我始终误会它了。在 git book 的 rebase 篇章,第一段就阐明了,在 Git 里有两种办法能够用来整合两个分支,而这两个在上方都有提到,别离为 merge
和 rebase
:
从上方的 merge 例子曾经晓得了,merge 在合并的时候会有 fast-forward
,和抵触时用一个 commit 记录合并变更的两种情景。而 rebase 的整合形式十分乏味,按照对于 rebase 的另一段阐明,它能够「把某个分支中所有 commit 的过程,以另一个分支的 commit 为根底重播一遍」:
这是什麽意思呢?首先让咱们回到上述的例子,并在 master 分支上用 reset
,让 master 的版本回到合并 string-library 之前:
当初咱们要用 rebase 指令,将 string-library 所有的 commit 批改,以 master 的 commit 为根底跑一次。应用 rebase 合并的第一步,要先切到想重播 commit 的分支:
git checkout string-library
而后再输出 git rebase
指令,并于前方指定要在哪个分支上重播:
git rebase master
执行后果:
在 rebase 重播 commit 的过程中,和 merge 类似的中央在于,如果有抵触的话还是须要解决,但在解决后,并不是应用 commit 指令进行合并,而是要输出 git rebase –continue,让 rebase 能够持续重播接下来的 commit:
重播实现时,会显示目前重播到哪个 commit,以 string-library
来说就是最新的 add string unit test D
。这时候的分支关系,画成图就会变成:
上图在通过 rebase 之后,string-library
里 07e38fb 批改,会以 master 的 commit 为基底再重播一次。
须要留神的是,重播后的 commit id 会和本来的不一样,这等于齐全改写了分支内所有的 commit 历史纪录。
另外,执行完 rebase 后,string-library
其实还没有被合并回 master 分支上,因而还是要再切回 master 执行 merge,以实现合併:
因为曾经先用 rebase 在重播时解决完 commit 的抵触了,所以当初 merge 就会间接走 fast-forward 合并,也不会另外多一个 merge 的 commit 纪录。
应用 git-rebase 合併的优缺点
长处
- 不会在合併时产生多馀的 commit。
- 能够在重播的时候以 commit 为单位解决抵触。
- 合併时会依分支的 commit 排列,可能比较清楚的 review issue 或 feature 解决的过程。如果应用 merge,在合併后就会按照工夫程序交叉排列两个分支的 commit。
- 在奉献开源我的项目的时候,如果在 push 前先做 rebase,那作者就可能间接以 fast-forward 的形式合并,不须要再另外解抵触。
毛病
最大的毛病就是上方提到的,应用 rebase 会批改 commit 的历史纪录,如果在本人的 local 整顿 commit 或是分支那还好,但如果不小心去异动到 remote 的分支,而后又更不小心用了 git push -f
,那可能就会被共事厌恶,或被投稿到纯靠北工程师 😂。
该用 git-rebase 或 git-merge?
在查了一些材料后,发现 rebase 和 merge 都各有拥护者,我先论述他们的想法,再主观提一下本人的观点。
git-merge 派
反对 git-merge
派的工程师们认为,版本纪录有价值的中央就在于我的项目的 commit,也就是这个我的项目的「历史实际上产生过哪些事件」,如果你去批改了这些历史纪录那就很不好。因而即便不同分支的内容在 merge 后都混在一起,但这些内容依然阐明了这个我的项目的历史。
git-rebase 派
反对 git-rebase
派的工程师则感觉,commit 是在说这个我的项目的「演进过程」,产生了什麽事件才是重要的,即便批改了 commit 的历史,然而产生的事件仍然没有扭转,既然能够用更分明简洁的纪录供前人浏览,那就应该要这麽做。
集体主观观点
我集体还是会应用 git-rebase 来批改 commit,让历史纪录更为简略好浏览,但应用上仅限于 push 到 remote 之前,如果明天曾经把纪录 push 到 remote,那即便多乱我也不会去批改它们,毕竟 remote 的纪录就是大家共有的,不随便批改,也是尊重团队内的其余成员。
代码部署后可能存在的 BUG 没法实时晓得,预先为了解决这些 BUG,花了大量的工夫进行 log 调试,这边顺便给大家举荐一个好用的 BUG 监控工具 Fundebug。
作者:神 Q 超人 > 起源:medium
原文:https://medium.com/starbugs/g…