本文講述瞭如何使用 git rebase -i 及 git cherry-pick 實現程式碼回滾。程式碼回滾屬於高危操作,建議慎用!
為什麼會寫這樣一篇文章?其實是有一段歷史的:在一次迭代中並行開發著 n 個需求,到提測之時各需求的程式碼陸陸續續被合併到了測試分支。生活本來很平靜,但兩天後測試的頭目說“我們組發生了點狀況,本次迭代的需求在規定時間內無法測完,但老闆又強制要求了上線時間,我們把優先順序較低的需求的程式碼從測試分支抽出去吧!”。當時真是心中一萬隻 XXX 飄過...
我們來模擬一下上述場景:迭代中並行開發著 3 個需求 feature1、feature2、feature3,在各自的開發分支上相安無事(假定測試分支為 master)。

其中 feature2 與 feature3 需要修改同一檔案,我們故意製造了一個衝突:

提測時間到了,feature1 的程式碼被合併到了測試分支:

在 feature1 修復了 1 個 bug 後,feature2 也提測了:

而後 feature3 也提測了,在合併 feature3 的程式碼時,剛剛製造的衝突爆發了:

我們需要解決衝突後再合併程式碼:

在 feature3 提測後,我們又修復了幾個 bug:

當然,feature2 雖已提測但並未進入測試,bug 的修復均是針對 feature1 與 feature3 的。
此時,feature2 的測試無法正常進行,需要將程式碼從測試分支上抽出...
以防萬一,先將 feature2 分支備份:
git checkout feature2
git checkout -b feature2-copy
複製程式碼

我們來檢視一下 feature2-copy 分支的提交記錄:
git log
複製程式碼

我們需要回滾最新的 3 個提交(因為 3 個 feature 的開發分支均是從第一個提交的時間點上切出的),當然現實中針對某需求的提交絕不止 3 個。若是將提交逐一 revert 那麼工作量感人,我們何不將 n 個 commit 合併為一個 commit 然後一同 revert 呢?
使用 git rebase -i 來合併 commit,需要拼接回滾至的 commit 的 hashcode:
git rebase -i e08ddaf558b9ad84422db5e4b620dcab97623fde
複製程式碼
而後出現如下對話方塊:

我們需要將最新 2 次提交的 command 更改為 s:

修改後儲存並退出進入如下對話方塊:

我們需要修改最初一次提交的 commit message:

修改後儲存並退出,再次檢視 feature2-copy 分支的提交記錄:

3 次提交被成功合併,可喜可賀!接下來我們需要 revert 被合併的提交:
git revert e544464c3de69adef5ca7556001abebaf40b218b
複製程式碼

儲存並退出,再次檢視 feature2-copy 分支的提交記錄:

此時天真的我認為將 feature2-copy 合併到測試分支即可成功抽去 feature2 的程式碼,其實不然。正確的做法是使用 git cherry-pick 將 feature2-copy 分支上 revert 提交合併到測試分支上:
git checkout master
git cherry-pick b309f7944d2422d8fe647dca61bda518b192628f
複製程式碼
此時,feature2 的程式碼成功從測試分支上抽離。

最後為大家推薦一枚 Git 圖形化客戶端:GitUp
作者:呆戀小喵
我的後花園:sunmengyuan.github.io/garden/
我的 github:github.com/sunmengyuan
原文連結:sunmengyuan.github.io/garden/2017…
