同事出了一題 Git 隨堂測驗:有 Git 歷程如下,feature 與 master 分支的合併位置有誤(下圖藍紫線交會處,Commit b9933b90),想拆掉重做,請問單兵如何處置?

第一次處理正式環境的取消合併,加上實際案例還涉及 pull、rebase,狀況又再複雜一些,讓我有點手忙腳亂。所幸最終還是把問題解決,再累積一些實戰經驗。

取消合併的需求可分成兩種情境:保留曾經合併的歷程 vs 將合併軌跡徹底抹去。

若要保留合併記錄,只將合併進來的內容還原回去,可使用 git revert commit-id -m 1 or 2 or 3...,revert 會產生一個反向 Commit,把原本新增的檔案刪除、刪除的檔案加回去、改掉的內容還原,但因合併 Commit 會有兩個以上的 Parent,需透過 -m 指定保留哪一條 Parent 的內容。

如何知道該填 -m 1 還是 -m 2?Git 線圖的直線(藍線)是 Parent 1、併入的支線(紫線)是 Parent 2,或用 git show commit-id 看 Merge 列出的先後順序,第一個是 Parent 1,第二個是 Parent 2。

git revert 後,原本的合併 Commit 仍會存在,但會增加一個新的 Commit:

在本案例中,git revert -m 1 b9933b90 代表要保留 master 分支的內容,故會移除 b.txt;git revert -m 2 b9933b90 則會保留 feature 分支的內容,故會刪掉 c.txt 及 d.txt:(下圖中我先 git revert -m 1 觀察結果,之後 git reset --hard 取消 Revert 動作,再改試 git revert -m 2 觀察二者差異)

如果想讓合併記錄徹底消失,改寫歷史這種事當然要交給 rebase 處理了。git rebase -i 的標準程序會忽略合併性質 Commit,主線支線的 Commit 將混在一起成為一條直線。

例如:用 git rebase -i 24266aed 重整 add d.txt 之後的 Commit,Commit 清單不會有合併 Commit (b9933b90),而是顯示其所包含的 d323c2fb Commit - add b.txt。

若不更動 Commit 項目, Rebase 後會合併線會消失,原本的合併 Commit 則被 add b.txt 取代:

知道這個原理,要取消 feature 併入動作,我們可將 d323c2fb Commit 改為 drop,就能恢復成 feature 沒併入的狀態:

不過,如果 feature 有數十個 Commit,要一一 drop 有點麻煩,git rebase 有個 --rebase-merges 參數(或簡寫成 -r),可納入合併性質 Commit:

merge -C b9933b9 merge # merge 改成 drop b9933b9 也能達成移去合併 Commit 的效果。

學會這些技巧,下回遇到取消合併的需求就不會心慌囉~

Tips of how to revert or remove merge commit in Git.


Comments

Be the first to post a comment

Post a comment