rebase — Git中一個強大的忍者

0 前言


剛開始接觸Git時,只會一些常規操做命令:pull、add、commit、push。畢業參加工做之後,在公司的大規模合做中,這時就迫切須要對git進行再瞭解。而後就係統地學習了git。終於對這些經常使用的命令知其然,知其因此然了,同時,也學習掌握了一些高級命令。其中rebase命令,讓我以爲發現了git的新大陸。特此記錄下相關知識,以作記錄,也能夠與你們相互學習交流。git

1 what is rebase


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

  1. 肯定涉及到哪些提交:確認活動分支(branch1)哪些提交不在目標分支上(master),這些提交(commit6和commit7)就是要進行變基的提交。
  2. 確認新的基點:新的基點就是目標分支的最新提交,這裏是commit5。
  3. 複製提交:將須要變基的提交一次複製一份並建立新的提交(commit複製6和commit複製7),這裏是按順序來的
  4. 將活動分支重置: 活動分支被移動到上述複製提交的頂部,在這裏是commit複製7。

經過上面的演示已經原理講解,你們應該對rebase有了一個基本的瞭解了。下面說說何時使用它。cdn

2 何時使用rebase


  1. 淨化歷史,這也是使用rebase的最重要的緣由,使用rebase變基後在合併代碼,就會使得咱們的主幹分支(master)不會出現交叉狀況,就是一條線往下走,這樣就易於維護和管理。
  2. 移植分支,能夠把一個分支上的一些提交移植到另外一個分支上
  3. 經過rebase的高級用法,交互式變基,你能夠對須要移動的分支(好比上面的commit6和commit7)進行修改、合併等等。

3 如何用rebase


  • 合併開發分支到master,淨化歷史

當咱們在功能分支上開發完一個功能時,咱們須要將其合併到主分支上(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分支就是一條線,清晰也易於維護和管理。

4 rebase的高級用法


rebase命令還有一些可選項,利用這些可選項,咱們進行更復雜的操做。下面主要介紹兩個--onto和--interactive。

使用--onto移植提交

在以下的git結構中,咱們但願能將branch1分支和branch2分支同時合併到master。這是咱們能夠先將branch1分支中master沒有的提交(commit6和commit7)合併到branch2,再經過上面的方法將branch2合併到master。這就是移植提交。能夠將commit6和commit7合併到branch2中。

  1. 首先將活動分支切爲branch1

git checkout branch1

  1. 執行移植操做

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進行強制本地覆蓋遠端,就會比較安全且沒問題。若是這裏看不懂,先往下看。

  1. 首先從master分支開出一個新的功能分支feature

git checkout -b feature

  1. 模擬開發,進行屢次提交,這裏模擬了三次提交
    咱們看看feature分支日誌狀況

提交了三個分支。再看下master分支狀況:

master最新提交是"Merge branch 'test1'"

接下來,咱們開始進行合併操做:

  1. 切換活動分支爲feature

git checkout feature

  1. 執行交互式變基 -i 是--interactive的縮寫

git rebase master -i

執行該命令後,變基操做會進入交互狀態:

咱們能夠看到,上面列出了須要變基的全部提交,順序從上之下,也是提交從前到後,先提交的commit顯示在上面。接下來,就是交互式變基提供的7個命令:

  • pick 也是默認,就是使用該commit,將其複製過去,正常變基
  • reword 使用該提交,可是能夠修改該提交的提交信息,當時用該命令是,接下來就會進入一個頁面,讓咱們寫信的提交信息。若是咱們想修改那個commit的提交信息時,可使用這個方法
  • edit 使用該提交,而且變基中斷,這時咱們能夠修改工做區文件,修改完之後git add . => git commit --amend進行從新提交。提交完後使用git rebase --continue繼續變基。若是你想修改某個提交,可使用該方法
  • squash 合併提交,它會合併到前面的提交中,而後讓咱們從新編輯提交信息,這也是咱們要實現的。
  • fixup 也是合併提交,可是沒有然咱們從新編輯提交信息,而是丟棄這些提交的提交信息
  • drop 丟棄該提交,也就是該提交不會複製過去。
  • exec 執行shell命令,貌似不知道有什麼用

在瞭解了這些命令後,繼續咱們剛剛的任務,上面已經提到過,咱們使用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的話,那操做就更簡單了。

  1. 切換到master

git checkout master

  1. 進行合併操做

git merge feature

此時,任務完成,可是仍是要提醒一下,若是你以前有提交到這幾個commit到遠端,那邊遠端feature分支和本地的就不一樣了,如何想同步,就必須強制push了。接下來咱們看看master日誌

git log --graph

只有一個提交。若是在feature開發過程當中master有新的提交。也不會出現交叉,就不演示了。

5 總結


rebase仍是一個比較強大的命令,有些人由於太強大而懼怕使用,生怕出現什麼問題,當你真正瞭解了這些命令的原理之後,你就會以爲沒有什麼能夠懼怕的,由於它都在你的掌握之中。掌握rebase -i 這個命令,我相信對git的瞭解和使用會上一個階梯,真的比較強大和好用,掌握它,用好它,會幫助咱們提升工做效率。

就這樣了吧!歡迎留言交流。

相關文章
相關標籤/搜索