本文使用「署名 4.0 國際 (CC BY 4.0)」 許可協議,歡迎轉載、或從新修改使用,但須要註明來源。前端
做者: 百應前端團隊 @零卡vue
文中部分素材來源網絡,若有侵權,請聯繫刪除。git
你們都知道 git merge 能夠快速方便的合併兩個分支,你們在各自的分支上開發代碼,開發完成以後再合併到主幹分支,這樣雖然保證了你們的代碼不會陷入混亂,可是會形成一個問題,就是在合併一個並無上下游關係的分支時,git 會自動幫咱們生成一個 merge commit。記錄合併記錄雖然沒什麼問題,可是當咱們在頻繁合併的時候,merge commit 一多就會變的很是混亂了,舉個栗子(如下例子均爲同一個 master
分支):shell
相信當你看到這個提交記錄的時候,表情必定是這樣的:markdown
(這TM都是些啥??????)網絡
心情必定是這樣的:app
能夠看出單純使用 merge 方法,不只提交記錄不清晰,甚至連 commit 時間都是混亂的。因此,爲了解決這個使人頭大的狀況,咱們就須要用到 git rebase 了,使用了 git rebase 以後,提交記錄就會變成這樣:async
是否是瞬間感受就清晰多了!全部的改動記錄都能清晰的排列起來,閱讀的時候一眼就看的出來何時作了什麼東西,心情萬分舒暢。工具
在介紹 rebase 以前,須要提早說明,rebase 是一個很是強大的功能,也正是由於它的強大,因此使用起來也有必定的隱患,一旦使用很差可能會對團隊的代碼形成很是大的問題。因此在使用前必定要了解其中的原理並當心謹慎的使用。oop
rebase 的功能能夠簡要的概述爲對某一條線性提交分支上的記錄進行編輯、刪除、複製、粘貼、合併。合理使用 rebase 可使團隊的提交記錄變的很是乾淨整潔。
注意:如非無可奈何不要經過 rebase 對任何已經提交到公共主幹分支上的提交記錄進行 commit!
假設咱們在開發的時候同時拉出來兩個分支並行開發,而後有一條已經合併到主幹分支 main
了,像這樣:
這個時候咱們想要把主幹分支 main
的代碼再合併到當前開發分支 test-1
,而後再進行提交,若是使用merge 會是這樣:
若是當前分支有不少的子分支,到最後合併的時候就會出現像一開始那張圖同樣爆炸的狀況。
而若是使用 git rebase main
(或者 git pull --rebase origin main
)合併 main
分支,提交記錄就會變成這樣:
清晰明瞭。
注:使用rebase合併主幹分支時,當前分支所作的修改永遠會被認爲是最新的,因此會致使在提交記錄上就算 test-1
分支一開始的提交時間在 test-2
以前,可是 rebase 以後 commit 記錄也是最新的,這也是rebase的初衷之一,更清晰的顯示出來在何時提交到主幹的什麼功能(由於按照提交時間來看,test-1
分支的功能是在 test-2
分支功能合併到主幹 main
分支後添加的)。⚠️ 正是由於它改變了歷史,因此咱們更應該謹慎使用 。
固然,若是該分支是測試環境或者預發環境分支,則通常須要使用git merge
來合併。由於在這兩個分支上會存在多個分支可是並無合併到主幹的修改。
再看一種狀況:
如圖所示,test-1-1
分支實際上是從 test-1
分支的 commit-1-3
節點拉取出來的,而此時 test-1
分支並無合併到主幹 main
分支,可是 main
分支上的功能要提早合併到test-1-1
分支上,合併完成以後將 test-1-1
與 test-1
獨立,變成兩個互不相干的分支,這種狀況下可使用 git rebase --onto main test-1 test-1-1
能夠看到這種狀況下 test-1-1
與 test-1
已經互相獨立互不相干了,並且 test-1-1
的記錄線已經跟 main
在同一條線上了 *( *不過在正常開發狀況下應該避免這種狀況發生,由於test-1-1
中已經包含了一部分的 test-1
變動,因此當 test-1
分支再合併主幹的時候,可能會有許多衝突 ) 。
咱們在使用 git rebase
或 git pull --rebase
合併的時候可能會有許多衝突
在發生衝突時,git rebase
將中止在第一個有問題提交,並在樹上留下衝突標記。咱們可使用git diff
定位標記(<<<<<<),並進行編輯以解決衝突。
對於編輯的每一個文件,須要告訴 Git 衝突已解決,一般使用git add <filename>
手動解決衝突並更新到對應的索引,
以後,咱們能夠手動進行下一步進程 git rebase --continue
咱們也能夠手動撤銷rebase git rebase --abort
rebase 最經典的功能,就是編輯 commit。好比在 pull requests(gitlab爲merge request)中須要修改代碼的時候,須要把修改的內容合併到已經提交的commit上。
這裏咱們可使用 git rebase -i [startpoint] [endpoint]
來編輯提交記錄,其中-i
的意思是--interactive
交互的意思,即彈出交互式頁面供使用者編輯。[startpoint]
和[endpoint]
指的是編輯的開始和結束節點(不包含[startpoint]
節點,範圍邏輯是[startpoint] < commits <= [endpoint]
),若是不指定[endpoint]
則結束節點會指向HEAD
所對應的節點(通常使用的時候也不指定結束節點...)。
舉個栗子:
此時咱們想編輯test-1
分支的最新三條歷史記錄,咱們可使用前面所說的
git rebase -i 39ce617
或者是 git rebase -i HEAD~3
,咱們會看到以下頁面:
指令說明:
p 或 pick 使用該commit,不作修改(默認指令)
r 或 reword 使用該commit,可是修改它的commit信息
e 或 edit 使用該commit,可是要停下來修改(commit信息和提交內容)
s 或 squash 使用該commit,可是將此條commit融入以前的commit
f 或 fixup 跟squash一致,跟前一條commit合併,可是丟棄該commit的日誌消息
x 或 exec 運行shell命令(該行的其他部分)
b 或 break 到此爲止(稍後繼續使用 'git rebase --continue' 進行rebase)
d 或 drop 丟棄該commit
l 或 label 使用label標記當前HEAD
t 或 reset 將HEAD重置到label標記
m 或 merge [-C <commit> | -c <commit>] <label> [# <oneline>]
使用原始合併提交的消息(或單行,若是未指定原始合併提交)建立合併提交。
使用 -c <commit> 改寫提交消息。
複製代碼
在該頁面點擊i
鍵進入編輯頁面,便可在指令模塊編輯,編輯完成後點擊esc
而後輸入:wq
保存並退出進入下一步操做。
通常來講,除默認的pick
以外,最經常使用的就是reword
、edit
、squash
、fixup
這幾個命令了,這裏就只詳細的講解以上命令。
若是咱們想要修改 commit-1-5
這條commit的提交信息,只需在該條以前寫明 r
或 reword
方法:
保存退出以後進入commit編輯頁面:
修改並保存以後,在提交記錄裏能夠看到本地 commit-1-5
記錄已經被修改爲了 commit-1-5-reword
,若是後面還有分支存在修改,則使用 git rebase --continue
命令進行以後的修改,待全部commit都修改完成以後再使用 git push -f
或 git push --force
強制推送代碼覆蓋遠端後,遠端的提交記錄就變成了:
能夠看到提交記錄已經被修改了。
使用該方法以後,咱們就能夠修改想要修改的內容,修改完並執行 git add
以後,就能夠調用
git commit --amend
來修改commit的記錄內容,這裏能夠看到edit以後修改的文件是 README.md,
而後修改 commit 方式跟 reword
一致,待全部 commit 都修改完成以後,使用 git push -f
強推至遠程即可以實現記錄內容的編輯修改了。
字面意思,使用 squash
是將記錄壓縮到一塊兒,通常用於一個大功能開發完成後合併提交到主幹分支上使用,這裏咱們能夠用 vue 的提交記錄舉例:
能夠看的出來 fix(types): async Component types (#11906)
記錄下合併了許多子記錄,這樣也能夠清晰的代表一個迭代的功能及開發提交記錄。
fixup
也是將代碼進行保留併合併到上一條提交記錄,惟一的區別就在於 fixup
的記錄被刪除,此方法適用於咱們在 MR 時候的 comment 修改。
注:若是咱們在 rebase 的過程當中由於一些緣由退出了終端中斷了 rebase,咱們能夠回來繼續使用git rebase --edit-todo
進行繼續編輯。
其餘功能用的比較少,就很少作贅述,感興趣的能夠閱讀相關文章。
exec: paul-samuels.com/blog/2020/1…
label & reset: stackoverflow.com/questions/6…
以上就是rebase的一些基本知識了,但願這篇文章能給你們一些幫助。
Settings/General/Merge requests