Git Rebase-合併分支

學會以後會覺得它很好用。

簡述

在使用 rebase 以前我們先來看一下一般的 merge 是怎麼併的。

假設目前的紀錄長這樣:

example

接著我們在 cat 分支執行:

1
git merge dog // 把 dog 合併到 cat

解除完 conflict(如果有)以後的結果如下:

example-merge-result

好,這就是我們熟知的 merge,但為什麼要特別提這個?這是因為等一下要介紹的 rebase 合併完的結果會跟現在不太一樣。

現在讓我們改用 rebase 來合併剛剛的 catdog 分支(一樣是在 cat 分支):

1
git rebase dog cat

這段指令的意思是 git rebase <基準點> <被複製的人>,不過你應該比較常看到 git rebase dog 的寫法,因為 git 會把 <被複製的人> 自動帶入目前所在的分支。

至於 <基準點><被複製的人> 是什麼意思待會再解釋,我們先看一下 rebase 後的結果會長什麼樣:

example-rebase-result

merge 的時候會自動幫我們產生一個新的 commit 來表示「合併」這件事,可是在 rebase 的時候就沒有這個行為了,看起來就好像直接「把 cat 接到 dog 上面一樣」的感覺。

除了最後的結果長的不太一樣以外,「合併」這件事本身是相同的,所以要用哪一種方式來合併都是可以的。

rebase 背後做了什麼?

前面有提到在使用 rebase 指令時會設定 <基準點><被複製的人> 這兩個不同的「對象」,所以這到底是什麼?

簡單來說,回憶一下剛剛的例子,我們在用 rebase 做合併時大概做了這幾件事:

  1. 複製一份 cat 身上的 commit 紀錄(建立新的 hash 值)
  2. 把複製過來的紀錄「接」到 dog 的最後一筆 commit 上
  3. 完成 rebase

因為會有「複製」這個動作,所以 <被複製的人> 就是在指你要複製哪一個分支的 commit 紀錄?而複製完以後要再「接到某個分支上」,所以 <基準點> 就是在指要被接上去的那個分支是誰?

這個是我自己的理解方式,如果要看更詳細的說明可以看這篇

所以剛剛的範例如果改成:

1
git rebase cat dog

出來的結果就會變成:

example-rebase-swap

因為 <基準點><被複製的人> 交換了,所以出來的結果也會不一樣,所以我覺得在使用 rebase 的時候只要搞清楚這兩個角色就不會有太多疑惑了。

順道一提,這兩個詞只是我自己發明的,如果出去外面這樣跟別人說的話別人可能會滿臉問號。

怎麼取消 rebase 後的結果

一樣是剛剛的範例,假設這是 rebase 後的結果:

example-rebase-result

現在會碰到的問題是,如果想要跳回「還沒有 rebase 前」的狀態該怎麼做?你可能會想說:

啊就直接用 reset HEAD^ --hard 不行嗎?」

答案是不行,這樣子只會回到前一個 commit 紀錄而已:

example-reset

這是因為 rebase 不像 merge 會自動幫我們另外產生一個新的 commit 紀錄,所以你就算想用 reset 回到前一筆紀錄,這筆紀錄也不會是「做 rebase 之前」的那一筆。

這時候有兩種方法:

  1. 用 reflog 找到 rebase 以前的 commit 紀錄
  2. 用 ORIG_HEAD 回到上一個「危險操作」以前的位置

這邊先來看第一種,首先下 git reflog 來查看歷史紀錄:

example-reflog

附註:這邊我有重寫過紀錄,所以才不會有剛剛的 reset 紀錄

紅色框起來的部分都是跟 rebase 相關的操作,所以我們只要回到這之前的紀錄就行了。

撇除掉 rebase 後的最新紀錄是 add cat2(138f72c),這個就是我們要的了,所以可以下:

1
git reset 138f72c --hard

這樣子就能回到 rebase 前的狀態囉:

example-reset-by-reflog

接著是第二種方式,這個只要直接下:

1
git reset ORIG_HEAD --hard

一樣也能回到 rebase 前的狀態:

example-reset-by-reflog

很神奇吧!這是因為 ORIG_HEAD 是 Git 中比較特別的紀錄點,它會自動記住上一次「合併分支」、「Reset」或是「Rebase」這些比較危險的操作,也因為這樣所以才會稱為「危險操作」,所以如果你懶的用 reflog 去查 hash 值的話就可以直接用這個方式來 reset,會更方便一些。

總之這兩種方法都是 OK 的,挑一個你喜歡的來用就行了。

Git Rebase-把多個 commit 合成一個 commit Git-HEAD
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×