iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 25
1
Software Development

用樂高玩轉 GIT 版本控制系列 第 25

Day 25 - GIT 狀況題 02 建立了分支之後,忘記 checkout 就 commit,該怎麼處理?

前一篇 Day 24 聊到透過幾個解法,把目前所在的分支移動到與自己相同基點的其他分支上。今天的這個題目是在 2019 年 ModernWeb 聽龍哥(高見龍)的演講時聽到的,我覺得很生活化,且在實務上常常會遇到。

在許多開發流程中,都會建議,當有新的需求要修改原始碼時,需要從主分支建立 feature 分支,而後透過 MR 或 PR 機制回到主分支上。而一般情境下,開始實作新的需求之前,會先在目前的主分支上直接思考可能可以怎麼做,而後做一些簡單的測試或調整,也常常在這時間點,忘記還沒開啟分支,就直接修改原始碼,並且順手 commit 目前修改的內容,等到 commit 完才發現還沒建立 feature 分支。也或者是已經先透過 git branch feature_xxx 建立了分支,但卻忘記要 git checkout feature_xxx 直接在主要分支上實作了?

Scenario 02

如上圖,feature 分支還在比較前面的原點(origin/master) commit 上,而原定的主要分支 master 已經超前兩個 commit 了。調整的目標是讓畫面上 master 與 feature 兩個分支的位置互換,且 master 對應 upstream origin/master 的這個設定不變。(成果概略如下圖)(什麼是 upstream 請見 Day 18)

Scenario 02 解決的目標

在這時候可以怎麼處理呢?

解法基本上分為兩類,首先要確認的點,目前已經建立好的 Commit 對應的 HASH Code 是否可以變動?首先是不變動 HASH Code 的解法。

解法一:不變動 HASH Code - Rename Branch:

Day 08 的時候提過對於分支的概念,可以想像「它只是一個可以移動的貼紙,當分支上有新的 Commit 貼紙就貼到新的這個 Commit 上」,基於這個概念,我們可以怎麼做?對已經存在的 master 及 feature 分支修改名稱。怎麼實作呢?

步驟一:

git branch -m master tmp
git branch -m feature master
git branch -m tmp feature

步驟二:

git branch --unset-upstream feature
git branch --set-upstream-to origin/master master

指令 git branch 的參數 -m 主要的功能是修改分支的名稱,所以步驟一的三行指令在做的事情就是使 feature 與 master 兩分支的名稱互換。

但由於 GIT 系統預設的關係,會發現這時候 feature 還保有著原本 upstream 為 origin/master 的設定,這時候需要把 feature 的 upstream 移除,並且為新的 master 設定回 upstream 的設定,這部分也就是步驟二。

如果覺得步驟二這樣設定很麻煩,有一個比較快的方法,在Day 18 有提到,本地分支與遠端的分支怎麼對應,都在 .git/config 這個檔案裡頭可以找到,因此,也只需要把目前設定為 feature 的字眼,改為 master 就可以完成步驟二需要完成的工作了。

修改 config 內的 branch 對應

解法二:不變動 HASH Code - Merge or Rebase feature

上面這個方法似乎有點繁瑣,有沒有再簡單一點的?有,結合 Day 24 的方法,透過 rebase/merge 在同一個分支上有 fast-forward (ff)的機制(什麼是 ff 請見,Day 13),先把 feature 分支變更到目前 master 的位置,而後 switch 到 master,接著 reset master 回 origin/master 的位置。

步驟一:

git checkout feature
git rebase master

步驟二:

git checkout master
git reset origin/master --hard

步驟一,第一行指令是切換到 feature 分支上,第二行指令是以 feature 針對不小心超前的 master 分支作 rebase(也可以用 merge),執行完畢後可以看到 feature 及 master 都指向同一個位置。

可以看到 feature 及 master 都指向同一個位置

步驟二,回到 master 分支,第四行,將 master 分支退回到原始位置,為什麼使用 --hard 呢?因為很明確的,不小心在 master 建立的 commit 都已經因為 feature 分支 rebase master 已經在 feature 分支上可以找到了,因此 master 可以直接回復到最原始的狀態,所有新增個過程都完全不留。(什麼是 git reset --hard 請見 Day 09)

完整的執行過程如下:

完整的執行過程

解法三:會變動 HASH Code - Cherry-Pick master commit

如果在可以允許變動 HASH Code,使用 git cherry-pick 指令,把目前在 master 分支上的 commit 帶回來 feature 分支,會是相對直覺的方法。步驟如下:

步驟一:

git checkout feature
git cherry-pick f17fbe9
git cherry-pick c59f7d7

步驟二:

git checkout master
git reset origin/master --hard

步驟一的部分,是把目前 master 多出的分支步驟取回到 feature 分支來。而兩個 git cherry-pick的指令,也可以合併為(且新指令不管 master 多了幾個步驟,都可以一律使用 ..master 取代):

git cherry-pick ..master

步驟二的部分則是如解法二的步驟二一樣,回到 master 分支重置 master 的位置。

當然,看過Day 24的解法三、解法四,就會知道,其實可以透過 --ff參數,就變成跟解法二的方法一致了,對應的解法修改如下:

步驟一:

git checkout feature
git cherry-pick --ff ..master

步驟二:

git checkout master
git reset origin/master --hard

取代後的完整執行過程如下:

取代後的完整執行過程

總結:

今天的解法我個人後期比較常用的反而是解法二,解法一的流程要修改的東西太多,相對容易發生失誤。一樣的,可能還有其他的解法,如果我有想到會再更新,而如果邦友們有想到不一樣的解法,也歡迎再次的跟我分享。


上一篇
Day 24 - GIT 狀況題 01 要怎麼樣把目前所在的分支標籤,移動到相同基點的其他分支上?
下一篇
Day 26 - GIT 狀況題 03 不小心把還沒合併到主分支的分支刪除了,該怎麼辦?
系列文
用樂高玩轉 GIT 版本控制30

尚未有邦友留言

立即登入留言