git rebase的時候捅婁子了,怎麼辦?線上等……

TechFlow2019發表於2020-11-06

大家在使用git的過程當中有闖過禍嗎?

我闖過,我闖的第一個禍就是使用git rebase造成的,雖然後來最終還是解決了,但是還是給我嚇得不輕。當時的事情是這樣的。

我們來看下這張圖:

簡單解釋一下這張圖當中的內容,C1節點是所有分支的最小公共祖先。可以理解成是最早的master版本,之後我們checkout出來了兩個分支,分別是bugFix和feature。其中feature是我們新開發的分支,而bugFix是修復bug的分支。

當我們把bugFix了之後就趕緊merge master釋出了,當我們釋出了之後發現bugFix當中有一點小問題。比如說把不應該提交的檔案提交了上來,再加上我們不是用rebase的形式合併的,所以看起來commit記錄有一點點亂。於是我決定使用rebase修復一下提交記錄,搞完了之後使用git push -f強行更新了遠端分支

因為我們之前已經push過了,想要用新的commit記錄覆蓋掉舊的就必須要使用-f強行推送。這些操作都是常規的操作,但是我無意之間犯了一個大問題,差點導致了後面的悲劇。

我先賣個關子,大家先用幾秒鐘時間想一下,這裡藏著的問題是什麼?

rebase的禁忌

這裡藏著的問題就是feature分支,我們從圖中可以看到feature分支是merge了C5節點的。但是當我們rebase push -f了之後,C5節點其實就不存在了。我們把圖畫出來給大家看一下就明白了,這個是rebase之前的依賴樹:

我們rebase之後依賴樹變成了這樣:

由於feature之前曾經merge過master並且依賴了C5節點,而master在rebase強行push之後整個鏈路當中已經沒有C5節點了。也就是說feature分支依賴了一個已經不存在的節點,這個時候還不算太遭,因為feature分支還沒有更新,如果feature分支pull一下,那麼整個分支會變成這樣:

也就是說同樣的程式碼在feature分支當中儲存了兩個版本,並且如果feature合併進master之後,會發現之前push -f強行拋棄的那些提交又被合併了進來,並且整個commit的log會變得非常非常混亂,難以看懂。

如果這些分支都是自己的,那麼自己捏了鼻子也就算了,如果這些分支是團隊當中其他人的,那麼捅個簍子基本上是避免不了的。如果組裡有一個Git大佬知道這種情況該怎麼解決還好,否則的話,想要完全復原非常困難,很有可能一通操作完全不知道偏差到哪裡去了,也不知道如何找回來。

我當時還好,捅婁子的時候已經學過了這種情況應該怎麼處理,雖然還是沒能避免踩坑,但好在及時從坑裡出來了。在我們來看脫坑的方法之前,先來思考一個問題,對於rebase造成混亂的根源究竟是什麼,我們應該怎麼避免?

解決rebase的只有rebase

為什麼我們剛才在C8節點一旦pull就會導致本地的錯亂呢?因為我們之前也介紹過,當我們執行pull的時候,其實是執行了git fetch和git merge兩個步驟。所以相當於我們把master分支的改動又merge了一次,我們本地依賴了rebase之前的改動,這樣一merge自然就把兩個版本的改動merge在一起了。

要解決這個問題,我們就不能在C8節點的時候進行pull操作,因為pull操作包含merge,merge會導致錯誤。要解決這個問題其實也不難,我們可以rebase到master上。當我們執行rebase的時候,git會找出我們當前分支獨有而master分支上沒有的改動,將這些改動提取出來應用在master上得到一個新的結果。

這樣我們的記錄當中就不會把C2和C5帶進來了。

發散思考

我們貫通思考一下上面的過程,會得到一個什麼結論?

其實結論很簡單,就是rebase雖然很好用也很方便,但是它也有適用的條件,其中最大的條件就是如果還有其他分支依賴了當前分支,我們這時候不可以使用rebase,否則一定會引起錯亂。

那引起錯亂的原因又是什麼呢?本質上是我們rebase的時候修改了commit的記錄,關於這一點不同的人有不同的觀點。有一派人認為git的提交記錄是不可以篡改的,它存在的意義就是記錄repo當中所有發生過的改動。如果使用rebase等操作進行了篡改,那麼我們就不能很好地追溯之前的改動和版本了。還有一派人不這麼看,他們覺得如果記錄的改動非常混亂非常不方便使用者閱讀,這時候使用一些方法對它進行修整就是非常有必要的事情。工具發明出來就是為了使用的。

這兩派爭論不休,不同的人有不同的看法,可以說是一個價值觀問題也不為過。在這個問題上我個人更加偏向後者, 既然有這麼好用的工具,自然應該使用的。使用不是濫用,我們需要遵守一定的規範,這樣才能保證不會捅出簍子來。比如一定不可以在下游還有其他依賴的情況下使用rebase,否則幾乎可以肯定是一定會捅婁子的。

今天的文章就到這裡,衷心祝願大家每天都有所收穫。如果還喜歡今天的內容的話,請來一個三連支援吧~(點贊、關注、轉發

原文連結,求個關注

本文使用 mdnice 排版

相關文章