你在開發過程中使用Git Rebase還是Git Merge?

華為雲開發者社群發表於2020-09-29
摘要:在git裡面經常的一個爭論是到底用rebase還是用merge?

1. 痛苦嗎?程式碼歷史中的迷失羔羊

我們先來看一個真實的程式碼提交歷史圖形化截圖:

你在開發過程中使用Git Rebase還是Git Merge?

 

圖片源自 https://storage.kraken.io/kk8yWPxzXVfBD3654oMN/c8b97f4dbb5f7d49fc3eb3624eafff79/london-tube-map-commit.png

 

https://dev.to/neshaz/git-merge-vs-git-rebase-5134

不知道大家看到這張圖以後有什麼感受?是不是很無語呢?我是無語凝噎的感受。程式碼歷史到了這個地步,基本上是廢了的!!!

通過本文我們就來談一下程式碼歷史線的問題。這裡涉及到一個程式碼歷史的管理問題,如果你希望擁有比較清晰的程式碼歷史,從而可以很快速地追溯你以前的程式碼記錄的話,你一定要關注這個話題。

如果你作為一個程式設計師用過mercurial,你可能對這個rebase概念已經有所瞭解。目前程式設計師用的最多的source control工具是git。在git裡面經常的一個爭論是到底用rebase還是用merge?

說爭論實際上是不太準確的。因為在實際工作中,這主要有兩種情況,一是根本就不知道rebase,另外一種是根本就不知道怎麼用rebase。

那我們就說一下rebase和merge的區別,在功能上rebase把你當前的修改工作提升到最前沿,
你自己獨有的修改記錄順序不會改變,但是時間主要會基於當前目標分支的時間戳進行調整。

Merge不會改變時間戳。這樣就會導致不同的人在合併自己修改程式碼記錄的時候,會出現相互交錯的情形。本文開篇是一張程式碼提交歷史的截圖,裡面的連線就像電路板一樣複雜。

出現這樣的情況,主要是因為程式設計師不做rebase直接merge造成的。

而類似這樣電路板狀的程式碼提交歷史是沒有意義的,因為太過複雜了。幾乎沒有可讀性。如果你想去檢視某些歷史記錄的時候,很容易被迅速淹沒在這些資訊海洋裡面無法自拔,最後失去自我,迷失了。

2. Git Merge vs. Rebase

小注:雖然已經參考連結中標註,但是有必要再強調一下此節翻譯參考瞭如下連結的英文內容:

https://dev.to/neshaz/git-merge-vs-git-rebase-5134

Git merge 和rebase的目的是一樣的,它們都是將多個分支合併成一個。雖然他們最終的目標是一樣的,但這兩種方法實現的方式是不同的。那麼我們應該用哪個呢?

這裡我們有一個示例倉庫,它有兩個不同的分支:主分支和特性分支。我們想把它們融合在一起。讓我們來看看如何使用這些方法來解決這個問題。

你在開發過程中使用Git Rebase還是Git Merge?

 

圖片源自 https://storage.kraken.io/kk8yWPxzXVfBD3654oMN/fc73a41ce658a6a566e2a54d60534ade/git-flow.png

 

https://dev.to/neshaz/git-merge-vs-git-rebase-5134

Merge

當你執行 git merge 時,你的 HEAD 分支會生成一個新的提交,並保留每個提交歷史的祖先。

你在開發過程中使用Git Rebase還是Git Merge?

 

圖片源自 https://storage.kraken.io/kk8yWPxzXVfBD3654oMN/673b91456bdc6fd454c5ad203f825568/git-merge-2.png

https://dev.to/neshaz/git-merge-vs-git-rebase-5134


Fast forward merge是一種不建立提交的合併型別,會更新分支指標到上一次提交。

Rebase

Rebase是將一個分支的修改重寫到另一個分支上,而不需要建立新的提交。

你在特性分支上的每一個提交,都會在主分支上建立一個新的提交。這看起來就像這些提交一直是寫在主分支之上的一樣。

你在開發過程中使用Git Rebase還是Git Merge?

 

圖片源自 https://storage.kraken.io/kk8yWPxzXVfBD3654oMN/5ade4f7276bc6ad18dad4b6078950ac9/git-rebase.png

https://dev.to/neshaz/git-merge-vs-git-rebase-5134

Merge的優點和缺點

優點

  • 使用簡單,易於理解。
  • 保持源分支的原始上下文。
  • 源分支上的提交與其他分支的提交是分開的。
  • 可以保留提交歷史。

缺點

圖片源自 https://storage.kraken.io/kk8yWPxzXVfBD3654oMN/c8b97f4dbb5f7d49fc3eb3624eafff79/london-tube-map-commit.png

https://dev.to/neshaz/git-merge-vs-git-rebase-5134

 

Rebase的優點和缺點

優點

  • 程式碼歷史是簡化的、線性的、可讀的。
  • 與許多獨立的特性分支的提交歷史相比,操作單個提交歷史更容易。
  • 乾淨、清晰的提交資訊可以更好地跟蹤一個bug或何時引入的某個功能。可以避免眾多的單行提交汙染歷史。

缺點

  • 會更改歷史提交時間,可能會丟失上下文。

比起Merge,你需要更加小心的使用Rebase。

應該用Merge還是Rebase?

當你的團隊對於rebase不熟悉時,那麼git merge就是你的正確選擇。

  • Merge允許儲存任何給定功能的提交歷史,而不必擔心覆蓋提交和改變歷史。
  • 它可以避免不必要的 git revert或reset。

另一方面,如果你更看重乾淨、線性的程式碼歷史,那麼git rebase是最合適的。這種方式可以避免不必要的提交,並保持更集中和線性的變化!

這裡要注意的是,如果你不正確地重寫了歷史,可能會導致嚴重的問題,所以在使用Rebase時請確保知道你在做什麼。

3. 一杯水與一桶水

先說一下一杯水和一桶水的關係,這個關係可以用來描述老師向學生傳授知識的情形。主要意思是說老師要是給學生一杯水的話,這個老師必須要有一桶水才行。

其實對於我們軟體行業來說,這個道理也是適用的。

關於本文的聚焦點程式碼歷史,我們想給外部呈現的是清晰乾淨的程式碼歷史記錄。要到的這個目標,我們需要做很多的工作,這項工作相較於乾淨的程式碼歷史就是一桶水與一杯水的關係。

這也是我們經常說的,對自己狠一點,讓別人舒服一點。對自己狠一點不是一句空話,實際上是讓自己絞盡腦汁的去想,如何把這個事情做好?把自己放在對方的角度上去看我們的輸出結果。我們問自己,我作為這些程式碼的維護者和接收者,是不是可以接受這樣混亂的程式碼歷史記錄,答案當然是否定的。

明白了這一點,在我們做程式碼歷史管理的時候,再苦再累也是值得的。

一些有多年工作經驗的程式設計師,他們可能用過很多程式碼管理的工具,這些程式碼管理工具在使用的時候經常用的一個操作就是merge。進入到git時代以後,這些程式設計師也保留了這樣的習慣,直接就merge。

我跟一些程式設計師聊過,他們甚至都沒有意識到有rebase這個操作。有的則覺得rebase太麻煩了,用了幾次就放棄了。

這絕對是人之常情。

當我們習慣了用一種方式做事的時候,我們做得越久感覺越安全,因為它是行之有效的,能夠解決問題的。當有另外一種更好的方式,但是卻與以前的方式有很大差異的時候,我們就會有本能的排斥心理。這是源於我們對未知領域的一種恐懼感。

離開舒適區以後,我們大多數人都會有一種不適應,有的甚至會產生很強烈的失落感。

但是當我們迴歸本心的時候,我們會發現我們所付出的一切,經受的痛苦都是值得的。因為我們的初心就是讓使用者滿意。程式碼歷史的使用者就是我們這些程式設計師。

4. 如何正確做rebase?

要點備註:

Rebase相關的要點有這幾個:

  1. 在自己的分支上做Rebase;
  2. 要Rebase正確的目標分支,注意這個目標分支不是你的遠端分支,這個地方經常有人犯錯;
  3. Rebase要常做,以避免出現衝突,或者衝突的難度增加;
  4. 在合入程式碼之前,一定要最後做一次Rebase再Merge;
  5. 最好用Squash Merge, 新增正確的提交訊息;
  6. 不要在主分支上做Rebase;
  7. 儘量不要force push;

在主分支上應該rebase嗎? 怎麼去做rebase?

首先,我要強調一下,在主分支上不要做rebase。這是因為如果你在主分支上做了rebase,如果你是第1次push可能沒有問題,但是如果別的人也做了一個rebase,這個時候就導致你的主分支上有兩個不同的head,這個時候如果想再push的話就存在問題了。

如果一切可控的話,你可以非常粗暴的使用強制push。但是如果團隊成員比較多,會導致這樣的操作會沖掉其他已經進來的提交。

除非萬不得已,我們堅決不能在主分支上去做rebase。

接下來說一個正確使用rebase的場景。在接到一個任務以後,我們會在主分支上最新的節點處提交上建立一個新的分支。在新的分支上,我們會不斷的進行新的提交,直到完成這個分支任務。

到這個時候,我們想建立一個merge request或者pull request,在此之前,我們首先要做的就是rebase,rebase選的目標分支是我們的主分支。

完成這次rebase操作以後,我們就可以建立mr或者pr了。在審查過程中可能有很多修改意見,修改完成以後需要先
rebase再push。如此反覆幾次,mr或者pr審批通過。此時要做一次squash merge把數次提交打包合成一個到主分支上。

以上是我對在正常工作流程中如何使用rebase進行了一個現實案例的描述講解,希望大家去體驗一下,告訴我體會,請留言說說你的想法。

參考文獻

 

https://dev.to/neshaz/git-merge-vs-git-rebase-5134

https://www.perforce.com/blog/vcs/git-rebase-vs-merge-which-better

https://product.hubspot.com/blog/git-and-github-tutorial-for-beginners

https://git-scm.com/docs/gittutorial

 

 

 

點選關注,第一時間瞭解華為雲新鮮技術~

相關文章