在merge PR的過程中计螺,rebase and merge會產(chǎn)生沖突,因此需要補充一下Git rebase的知識點瞧壮。
- Understanding Rebase (And Merge) in Git
- Merging vs. Rebasing
- webstorm 的 Rebase Current onto selected什么操作登馒?
- rebase and merge 一個Pull request做了什么操作?
Understanding Rebase (And Merge) in Git
merge 是Git中最簡單也是最常用的集成change的方法咆槽,但是這并不是唯一的一種方式陈轿。
Rebase是另外一種可選的但是略微高級的集成方式。
合并提交的case
通常情況下秦忿,一個由人類認(rèn)真創(chuàng)建的commit麦射,是一個有意義的單元:它僅僅包含相關(guān)的change并且每個commit都伴隨著一個comment。
有一種merge commit可以讓所有comments丟失:Git自動創(chuàng)建的commit灯谣,并且由Git填充所有的differ change潜秋。沒有語義,沒有主題胎许。當(dāng)然峻呛,這些獨立commits的內(nèi)容是保留的罗售。但是history分成了注釋的,分離的有意義的commit钩述,由于這個原因寨躁,在一次merge commit中不會保留。
這就是為什么有些人不喜歡merge牙勘,喜歡rebase的原因职恳。
Rebase之美
與一籠統(tǒng)把commits塞到一個commit不同,一個rebase會保留原始的commits方面。
項目的歷史是一條單的放钦,直線。沒有任何跡象表明它在某個時候拆分出一個分支來恭金。
在一次rebase后最筒,看起來就像development從來沒有被拆分成不同的分支。
我們來一步一步拆分一個rebase操作蔚叨。方案很簡單:我們想用rebase集成branch-B到branch-A床蜘。
一個rebase之前的方案。
命令很簡單:
git rebase branch-B
首先蔑水,線條開始分支后邢锯,Git將"undo"所有的branch-A上的commits(在共同的祖提交后)。當(dāng)然搀别,它不會丟棄它們丹擎,而是臨時將它們存了起來。
[圖片上傳失敗...(image-cf01ca-1584858732388)]
其次歇父,它會應(yīng)用我們想集成的來自branch-B的commits蒂培。此使,兩個分支是相同的榜苫。
最后护戳,branch-A的新commits重新被應(yīng)用,但是在一個新的位置垂睬,在branch-B的后面媳荒。(they are rebased)。
結(jié)果就是development在一條直線上開發(fā)驹饺。不是一個commit包含了所有的改變钳枕,而是讓原始commit結(jié)構(gòu)保持原樣。
下面嘗試開BranchA赏壹,BranchB兩個分支鱼炒,然后基于webstorm的Version Control,觀察git rebase操作會不會有上述的變化蝌借。
BranchA
BranchB
Rebase BranchA onto branchB
其實就是將branchB的母分支branchA進行了integrate changes昔瞧,也就是把branchB的2次commit俐巴,放在共同的起點與branchA的新commit之間,或者也可以理解成將branchA的新commit硬爆,移動到了branchB的2次commits之后。
rebase的是誰擎鸠,就修改的是誰
onto的是誰缀磕,誰就是被rebase的分支的新commits
其實,rebase只做了一件事:更新base branch劣光!(重點袜蚕!重點!重點>钗小)
而想將誰的更新內(nèi)容作為新的base branch的提交牲剃,就將作為topicBranch。
非常重要的命令雄可。
git checkout baseBranch
git rebase topicBranch
再說的通俗一點凿傅,其實就是:挑了一個branch,把它的特性拿過來数苫,放在我的新特性之前聪舒。
Merging vs. Rebasing
看完上面這篇文章后,并沒有搞清楚rebase做了什么操作虐急,所以還是需要多讀一些文章箱残。
- 對于初學(xué)者來說,git rebase命令就像一個magic voodoo
- merge和rebase都是用來從一個分支到另一個分支integrate changes的止吁,只是方式不同
[圖片上傳失敗...(image-51ce99-1584858732389)]
Merge Option
git checkout feature
git merge master
git merge master feature
會有一個'merge commit', 但是merge是非常安全的被辑,不會像rebase有很多陷阱。
但是若master非尘吹耄活躍盼理,每次merge都會有要給'merge commit',會導(dǎo)致feature的commit history很臟俄删。
[圖片上傳失敗...(image-fa201e-1584858732389)]
Rebase Option
git checkout feature
git rebase master
feature從master tip處開始合并master上的commits
重寫project的history
[圖片上傳失敗...(image-946390-1584858732389)]rebase后榜揖,project的history更加干凈了。沒了多余的'merge commit'抗蠢,并且成了一條線举哟。
rebase 需要遵循Golden Rule of Rebasing,否則會導(dǎo)致災(zāi)難性的合作workflow迅矛。
rebase 會丟失掉merge commit妨猩,導(dǎo)致看不到之后合并到feature的commit。
靈活一點的Rebasing
- 選擇特定的commits移動到新分支秽褒,加一個i選項
- fixup某一個提交
git checkout feature
git rebase -i master
pick 33d5b7a Message for commit #1
pick 9480b3d Message for commit #2
pick 5c67e61 Message for commit #3
pick 33d5b7a Message for commit #1
fixup 9480b3d Message for commit #2
pick 5c67e61 Message for commit #3
[圖片上傳失敗...(image-2711fa-1584858732389)]
Golden Rule of Rebasing
永遠(yuǎn)不要在public 分支上使用git rebase壶硅!
每次使用git rebase前威兜,問自己"有沒有人也正在基于這個branch寫代碼?"若是的話庐椒,就老老實實用merge椒舵,不要嘗試rebase。
若有g(shù)itflow的經(jīng)驗约谈,其實就是當(dāng)你開了一個feature/foo時笔宿,若同事也開了一個feature/bar关贵,而且你們是同時基于develop checkout出來的分支限寞,那么當(dāng)develop有hotfix merge進去時,若你想拉去最新的develop代碼厦酬,就不能用git rebase迈勋,只能用merge炬灭,否則會導(dǎo)致同事的develop分支與我們的develop分支不同,而此時她想再與我們保持同步是很復(fù)雜的靡菇。
Force-Pushing
若想將rebased的master分支推到遠(yuǎn)程倉庫重归,Git 將會阻止你,因為它與遠(yuǎn)程的master分支沖突了厦凤。但是提前,你可以force push。
# 這個命令一定要小心使用
git push --force
- 只有100%確定自己在做什么時再force泳唠,否則會讓團隊的人很困惑
- 若是想將某個feature遠(yuǎn)程分支徹底替換掉狈网,可以這樣做。
下面嘗試開master笨腥,feture兩個分支拓哺,然后基于webstorm的Version Control,觀察git rebase操作會不會有上述的變化脖母。
master
feature
git checkout feature
git rebase master
# resolve conflict1
git rebase --continue
# resolve confict2
git rebase --continue
Rebase feature onto master
webstorm 的 Rebase Current onto selected什么操作士鸥?
可以理解成下圖這樣。
Rebase feature onto master
[圖片上傳失敗...(image-aee717-1584858732389)]
Current在WebStorm中指右下角的branch谆级,selected一般指的original branch烤礁。
rebase and merge 一個Pull request做了什么操作?
相當(dāng)于:
git checkout feature
git rebase master
像下圖這樣:
[圖片上傳失敗...(image-512aa-1584858732389)]
實際工作中的rebase
一次完整的rebase流程
- git checkout feature
- git rebase master
- resolve conflicts
- git add .
- git rebase --continue
如果rebase中途出現(xiàn)問題肥照,可以使用git rebase --abort恢復(fù)脚仔。
git rebase的目的是保持當(dāng)前feature分支與master主分支同步的另一種方式,雖然與merge的效果相同舆绎,但是比merge更加簡潔高效鲤脏。
為什么說rebase比merge更加簡潔高效呢?
實際工作中的一個常見場景:在我們的feature開發(fā)期間,master上可能發(fā)布了很多release猎醇,修復(fù)了很多hotfix窥突。而且可能剛好影響到了我們目前開發(fā)的feature。此時我們需要將feature的代碼與master保持同步硫嘶。
同步有幾種方法:自己寫一遍阻问;merge;rebase沦疾。
- 自己寫一遍
自己寫一遍的方法是最不合理的称近,因為這會造成conflict,也是一種初學(xué)者容易犯的錯誤曹鸠。 - merge
稍微有經(jīng)驗一點的人,可以選擇merge斥铺,但是merge以后彻桃,我們在自己feature上提交的commit會被湮沒在茫茫commit中,很難清晰的從git history中找到晾蜘,這樣我們在開發(fā)過程中就很難清晰地知道上一次commit了哪些邻眷,最后合并到master上以后,如果出現(xiàn)bug追溯歷史commit也很困難剔交。 - rebase
最最明智的開發(fā)者肆饶,會使用rebase的話,解決完沖突之后岖常,就可以將我們feature上的commit全部移動到master的最新commit之后驯镊,這樣我們在開發(fā)過程中,就可以清晰地看到自己在feature上的commit竭鞍,發(fā)布功能之后板惑,也可以按照時間點去review我們的這幾次commit,從而快速找到問題偎快。
期待和大家交流冯乘,共同進步,歡迎大家加入我創(chuàng)建的與前端開發(fā)密切相關(guān)的技術(shù)討論小組:
- SegmentFault技術(shù)圈:ES新規(guī)范語法糖
- SegmentFault專欄:趁你還年輕晒夹,做個優(yōu)秀的前端工程師
- 知乎專欄:趁你還年輕裆馒,做個優(yōu)秀的前端工程師
- Github博客: 趁你還年輕233的個人博客
- 前端開發(fā)QQ群:660634678
微信公眾號: 人獸鬼 / excellent_developers
努力成為優(yōu)秀前端工程師!