剛開始接觸Git時,只會一些常規操做命令:pull、add、commit、push。畢業參加工做之後,在公司的大規模合做中,這時就迫切須要對git進行再瞭解。而後就係統地學習了git。終於對這些經常使用的命令知其然,知其因此然了,同時,也學習掌握了一些高級命令。其中rebase命令,讓我以爲發現了git的新大陸。特此記錄下相關知識,以作記錄,也能夠與你們相互學習交流。git
rebase,直接翻譯過來就是變基,而這個命令就是這麼人如其名。經過rebase命令,咱們能夠改變一串commits的基點(父commit)。首先咱們先來操做一遍這個命令,看看效果就知道這個命令是幹啥的了。shell
假設咱們的git結構是這樣子的。咱們在commit3這個地方開出了一個分支branch1,而後在branch1分支上開發並提交了兩個commit(6和7)。同時其餘分支合併到master分支致使master分支多了兩個提交(4和5)。安全
這時咱們執行如下命令: (注: 此時的活動分支是branch1)post
(branch1) git rebase master學習
執行完命令後的git結構以下:翻譯
咱們能夠看到,在使用rebase命令以前,branch1和master的交叉點是commit3,這也是branch1的"基點"。經過執行git rebase
命令後,branch1的"基點"就變成了5。從而改變了branch與master的交叉點,如今就是commit5。3d
rebase的工做原理是:Git會讓咱們想要移動的提交序列(commit6和commit7)在目標分支(master)上按照相同的順序從新再現一遍。這就至關於咱們爲各個原提交作了個副本,它們擁有相同的修改集、同一個做者、日期以及註釋信息。因此執行變基的相關commit是被複制了一份,上圖也作了標識,而原先在branch1的commit6和commit7仍是在歷史版本中,咱們能夠經過commit的sha-1序列號來找到它們,只有在用gc命令執行垃圾回收以後(這個命令git會自動執行,以清理版本庫),它們纔會真正從版本庫中消失。日誌
rebase的執行步驟以下:code
經過上面的演示已經原理講解,你們應該對rebase有了一個基本的瞭解了。下面說說何時使用它。cdn
當咱們在功能分支上開發完一個功能時,咱們須要將其合併到主分支上(master),繼續拿上面的那個例子:
以前咱們的作法是使用merge命令:(branch1) git checkout master
(master) git merge branch1
執行完上述命令後,git結構以下:
合併之後會產生一個新的提交節點(commit7)。這樣就產生了交叉,出現了"鑽石鏈"。讓master分支看起來很亂,也不易維護和管理。
下面看看使用rebase命令的效果。執行如下命令:
(branch1) git rebase master
注:rebase命令是在活動分支執行,而merge命令須要切換到你要合併的分支。因此rebase命令在branch1分支下執行,而merge命令在master分支下執行。這也是二者不一樣點之一
執行完上述命令,效果以下
這是branch1尚未合併到master。還需切換回master分支,執行merge命令。執行如下命令:
(branch1) git checkout master
(master) git merge branch1
至此,合併操做正式完成,看下效果:
上面的merge是快進合併(fast-faward),不會產生新的提交。若是須要產生新的提交(爲了更好的記錄追蹤),可使用--no-ff選項,在新版git中支持,舊版不必定支持:
git merge --no-ff branch1
commit6和commit7後續會被清理掉。這樣master分支就是一條線,清晰也易於維護和管理。
rebase命令還有一些可選項,利用這些可選項,咱們進行更復雜的操做。下面主要介紹兩個--onto和--interactive。
使用--onto移植提交
在以下的git結構中,咱們但願能將branch1分支和branch2分支同時合併到master。這是咱們能夠先將branch1分支中master沒有的提交(commit6和commit7)合併到branch2,再經過上面的方法將branch2合併到master。這就是移植提交。能夠將commit6和commit7合併到branch2中。
git checkout branch1
git rebase master --onto branch2 上面命令的意思是:將branch1分支中master分支沒有的提交拷貝到branch2,執行後的結果以下:
這樣就能夠將branch1中的提交移植到branch2中。
使用--interactive進行更多操做
給rebase加上--interactive選項,就變成了交互式變基,就是在變基(複製提交)過程當中,會中途中止,而後給咱們一些選擇命令,讓咱們進行不一樣的操做。
舉個例子,咱們在feature分支開發一個功能,這其中進行了屢次提交,產生多個commit。但咱們但願當該分支合併到master時,只產生一個commit,這時就可使用--interactive選項了,下面咱們模擬操做下:
注: 在本地進行rebase以前,建議先pull一下,讓遠端和本地代碼保持一致,由於rebase以後,會改變本地的commit結構,那時若是要同步遠端的話,須要強制推,先pull,再rebase,而後再使用
git push --force-with-lease
進行強制本地覆蓋遠端,就會比較安全且沒問題。若是這裏看不懂,先往下看。
git checkout -b feature
提交了三個分支。再看下master分支狀況:
master最新提交是"Merge branch 'test1'"
接下來,咱們開始進行合併操做:
git checkout feature
git rebase master -i
執行該命令後,變基操做會進入交互狀態:
咱們能夠看到,上面列出了須要變基的全部提交,順序從上之下,也是提交從前到後,先提交的commit顯示在上面。接下來,就是交互式變基提供的7個命令:
git add . => git commit --amend
進行從新提交。提交完後使用git rebase --continue
繼續變基。若是你想修改某個提交,可使用該方法在瞭解了這些命令後,繼續咱們剛剛的任務,上面已經提到過,咱們使用sqash命令合併提交,並從新編輯提交信息。
按字母i鍵進入編輯,由於是合併到前面的提交,咱們把後面兩個提交的命令改成squash,讓這三個提交合併成一個,按ESC進入命令模式,再按ZZ保存。變基繼續進入編輯提交信息頁面 它會列表每一個提交的以前的提交信息,咱們從新編輯保存退出,變基就會繼續完成。沒有衝突就會變基完成,若是有衝突,解決完衝突後,執行git add . => git rebase --continue
繼續變基便可。
變基完成並無合併到master。
注:變基後,feature分支的本地倉庫就發生了改變,三個commit合併成了一個。若是你以前將本地分支提交到遠端過,就是遠端的feature分支仍是有三個提交。這時若是你將本地分支提交到遠端,再經過open merge request 合併到master分支的話,你就要注意了。不能執行git pull命令。要使用git push --force-with-lease。強制將本地覆蓋遠端,這樣,本地和遠端的分支就同步了。
這裏的強制提交有兩個參數,--force和--force-with-lease。這兩個具體使用和介紹,建議你們Google下,詳細瞭解後再使用。比較功能比較強大。
傳送門(爲何不用--force而用--force-with-lease)
在實際開發中,通常都是同個Create Merge Request 的方式來合併到master,這樣能夠進行代碼審覈。這樣,咱們就須要將本地分支push到遠端再發起合併。到這步變基完成以後,正如上面所說,遠端倉庫和本地是不一樣的了,這就須要你執行上面的操做,將遠端覆蓋掉,而後再發起合併。
git push --force-with-lease
若是你能夠在本地合併到master的話,那操做就更簡單了。
git checkout master
git merge feature
此時,任務完成,可是仍是要提醒一下,若是你以前有提交到這幾個commit到遠端,那邊遠端feature分支和本地的就不一樣了,如何想同步,就必須強制push了。接下來咱們看看master日誌
git log --graph
只有一個提交。若是在feature開發過程當中master有新的提交。也不會出現交叉,就不演示了。
rebase仍是一個比較強大的命令,有些人由於太強大而懼怕使用,生怕出現什麼問題,當你真正瞭解了這些命令的原理之後,你就會以爲沒有什麼能夠懼怕的,由於它都在你的掌握之中。掌握rebase -i 這個命令,我相信對git的瞭解和使用會上一個階梯,真的比較強大和好用,掌握它,用好它,會幫助咱們提升工做效率。
就這樣了吧!歡迎留言交流。