gitlab上程式碼回滾把自己坑了後, 陷入思考?"bug是誰"?

lulu_up發表於2021-12-26

gitlab上程式碼回滾把自己坑了後, 陷入思考?"bug是誰"?

少年, 你點選過gitlab下圖中的金燦燦按鈕麼? 本篇文章將告訴你如何正確使用這個按鈕。

image.png

一、 背景

     原計劃xx號下午3點我開發的功能要上線, 下午2點將開發分支合併入master分支準備跑上線流水線, 但是不巧這一天server同學遇到了點問題, 導致上線時間延期了, 與此同時前端還有其他分支今天要上線, 已經準備合併入master分支, 當時我要做的就是快速將master回滾。

     我提交的"mr"資訊裡面有"revert"按鈕, 一看就知道這個按鈕負責回滾程式碼, 鬼使神差的就點選了這個按鈕, 當然啦程式碼被成功回滾並且也沒有影響後續同學的上線, 但故事並沒有這麼簡單。

     當n天后我負責的程式碼計劃再次上線時, git merge branchmasetrmerge我的分支竟然失效了, 我的程式碼中新增的部分無法合併入master, 當時情況緊急眉頭都皺成了一個"川"字, 焦急獸進化(?)鋼鐵焦急獸。

image.png

二、 強推灰飛煙滅

     當時現場求助了同組的其他同學, 將本地我的分支git merge master, 此時我的分支就是最新的, 再去gitlab上關閉master的保護機制, 強行將分支內容推到master上進行覆蓋, 再將master的保護機制重新開啟。

     這一套操作當然存在問題, 強推master可還行? 並且這種操作需要相關人員的稽核, "費力+有風險"。

     當一切塵埃落定了也該開始思考了, 那麼到底為什麼會出現程式碼無法合併入master, 到底是哪一步出了問題, 當時我的gitlab使用的語言是中文, 按鈕只顯示"還原"兩個字, 我趕快將語言切換至英語, 此時按鈕的文案變成了"revert", 我就從嫌疑人"revert"開始調查吧, 看看他與不在場的"reset"有什麼關聯。

三、靜下來學習reset與revert的區別

revert

     移除某個commit記錄, 並且生成一條新的commit記錄。

     假設當前的分支狀態是下圖:

image.png

     執行

git revert -n gt56th

git add .

git commit -m'feat: rm a'

image.png

reset

     移動HEAD到某個commit上, 這個commit之後的commit全部捨棄, 並且你本地的程式碼是沒有變化的。

     假設當前的分支狀態是下圖
image.png

     執行git reset gt56th

image.png

四、解釋為何程式碼合不進去

     通過對比我們就可以知道為什麼, 那天下午我無法把程式碼合併入master分支的原因了。

     由上面的步驟圖可知, revert後的程式碼裡是明確記錄了刪除目標commit也就是commit idgt56th的這條資料, 那麼我們再將含有commit idgt56th的提交mergemaster分支時, git的演算法會判斷出這個commit已被移除, 所以git會認為我分支的程式碼落後於master, master裡面移除了這條commit的程式碼才是最新的。

     git這樣判斷是沒問題的, 我們多人開發的時候, 假設'a'與'b'一起開發一個專案, 'a'刪除了a.js檔案並且mergemaster, 第二天'b'改動了其他地方也mergemaster, 此時就算b的程式碼上沒有移除a.js, merge後也不會在master分支上增加a.js檔案。

五、預設revert此事有蹊蹺

     我們來聊聊既然gitlab預設使用revert功能來回退程式碼, 也就是說官方認為這種回滾方式是最棒的, 那麼它棒在哪裡?

第一: 連續性

     就算是回退操作, 也算是對master的正常操作, 但是直接reset會導致時間線的缺失, 讓我們不知道中間發生了什麼, 長期來看這樣不利於解決問題。

第二: 中途有人拉程式碼

     'a'的程式碼push到了master上, 2個小時後a將master程式碼reset掉, 看似一切正常, 但是殊不知'b'剛剛pullmaster的程式碼到本地, 此時就埋下了隱患, 因為如果'b'進行master的合併操作, 會將'a'之前刪掉的程式碼再次釋出到master分支, 導致程式碼的錯誤上線。

第三: 方便回滾

     比如說我們的gitlab是預設merge完畢就刪除源分支的, 此時我們可以直接拉取master的最新程式碼, 因為可以在git log裡面找到所有的commit這樣就不怕玩壞了分支程式碼找不到了。

六、reset 裡的大學問

     講了不少revert的好處與壞處改說說reset了:

     假設我當前專案裡有 a.jsb.jsc.js三個檔案, a.jsgit commit -m'', b.jsgit add, c.js沒有被git監控:
image.png

image.png

git reset --hard CommitId (暴力刪除)

     這個寫法直接將HEAD回退到目標分支, 並且刪除所有當前分支之後編寫的程式碼, 也就是說會將你的程式碼清除哦。

     這個方法適合完全捨棄某些程式碼的場景, 因為你在git log命令裡面都無法查到被刪除的commit記錄了。

image.png

image.png

git reset --soft CommitId (舒服的?)

     這個寫法直接將HEAD回退到目標分支, 並且保留你在目標commit之後的修改, 這些修改都在暫存區, 我們可以繼續開發相關的功能, 最後統一 git add. && git commit -m '' 一次即可。

     這種方式讓我想到了我們可以平時在自己電腦上提交多個commit, 但是push之前我們可以先回退, 然後把commit合一再提交。

image.png

image.png

git reset --mixed CommitId (預設的, 當我們不寫引數就是這個指令)

     將目標提交之後的程式碼還原成未被監控的狀態, 也就是你的程式碼需要git add .一下才可以進行管理, 這個招式相當於重置了提交態, 但是也有一些小小問題, 比如我們有一些沒有被git add的檔案會與其他檔案不好分割開, 給我的感覺就是向我們當前的程式碼裡面塞入很多新的程式碼, 使用git status 檢視的話就全是紅色的。

image.png

image.png

七、流程梳理得出方案

     已經瞭解了上述的知識點, 那麼可以推匯出一套比較可靠的回滾流程了, 當我們要將已經mergemaster的程式碼暫時回滾, 並且後續還會上線這些程式碼時, 先點選gitlab上的revert按鈕, 再將自己本地的程式碼git reset 線上commit版本這樣就可以將這些程式碼變成新的commit, 這樣就可以再次申請mergemaster也不會合並不上了。

八、問題的出現與思索

     剛出現這個問題的時候, 習慣性的認為gitlab出問題了, git的某些演算法出問題了, 但是通過系統性的分析才明白, 出問題的是自己的操作。
image.png

     將gitlab平臺設定成了中文, 導致某些英文可以表達的含義無法表達, 這也是個問題點, 寫程式碼最好能更清楚的知道程式碼的本意, 而不是翻譯過後的意思。

image.png

end

     這次就是這樣, 希望與你一起進步。

相關文章