← 上一章:【常見問題】合併過的分支要留著嗎? 下一章:另一種合併方式(使用 rebase) →


【狀況題】不小心把還沒合併的分支砍掉了,救得回來嗎?

上個章節「【常見問題】合併過的分支要留著嗎?」提到合併過的分支如果想留就留、想刪就刪,Git 的分支並不是複製檔案到某個目錄,所以不會因為刪掉分支檔案就不見。

但如果刪的是還沒合併的分支就不一樣了,先想像一下這個畫面:

unmerged branch

cat 分支是從 master 分支出去的,目前領先 master 分支兩次 Commit,而且也還沒有合併。這時候如果試著刪掉 cat 分支,它會提醒你:

$ git branch -d cat
error: The branch 'cat' is not fully merged.
If you are sure you want to delete it, run 'git branch -D cat'.

「嘿!這個分支還沒全部合併喔」,雖然 Git 這麼貼心的提醒你,你還是依舊把它砍了:

$ git branch -D cat
Deleted branch cat (was b174a5a).

請先記一下這個訊息「Deleted branch cat (was b174a5a).」,待會可能會用到它。這時候的樣子會像這樣:

unmerged branch

等等,我不是砍掉 cat 分支了嗎?怎麼東西還在?再次跟大家說明一下分支的觀念:

分支只是一個指向某個 Commit 的指標,刪除這個指標並不會造成那些 Commit 消失。

所以,刪掉分支,那些 Commit 還是在,只是因為你可能不知道或沒記下那些 Commit 的 SHA-1 值,所以不容易再拿來利用。現在原本領先 master 分支的那兩個 Commit 就跟空氣一樣,你看不到空氣,但空氣是存在的。既然它還存在,那就把它「接回來」吧:

$ git branch new_cat b174a5a

這個指令的意思是「請幫我建立一個叫做 new_cat 的分支,讓它指向 b174a5a 這個 Commit」,就是再去拿一張新的貼紙貼回去的意思啦。看一下現在的分支:

$ git branch
* master
  new_cat

切換過去試試看:

$ git checkout new_cat
Switched to branch 'new_cat'

確認一下檔案列表:

$ ls -al
total 16
drwxr-xr-x   9 eddie  wheel   306 Aug 19 04:14 .
drwxrwxrwt  95 root   wheel  3230 Aug 19 04:06 ..
drwxr-xr-x  16 eddie  wheel   544 Aug 19 04:14 .git
-rw-r--r--   1 eddie  wheel     0 Aug 19 04:14 cat1.html
-rw-r--r--   1 eddie  wheel     0 Aug 19 04:14 cat2.html
drwxr-xr-x   3 eddie  wheel   102 Aug 17 15:06 config
-rw-r--r--   1 eddie  wheel     0 Aug 18 03:27 hello.html
-rw-r--r--   1 eddie  wheel   161 Aug 18 04:24 index.html
-rw-r--r--   1 eddie  wheel    11 Aug 17 14:56 welcome.html

cat1.htmlcat2.html 都回來了!

使用 SourceTree 也可以做這件事,點擊上面選單的「Branch」按鈕後會看到這個對話框:

unmerged branch

在「New Branch」欄位填上「new_cat」或是任何你喜歡的名字,但 Commit 選擇「Specified commit」,並把原本舊的 cat 分支指向的 Commit 的 SHA-1 值 b174a5a 填上去,按下「Create Branch」後:

unmerged branch

原本被砍掉的 cat 分支,就以 new_cat 的姿態轉生復活了!

我沒把剛剛刪掉的那個 cat 分支的 SHA-1 記下來怎麼辦?查得到嗎?

還是可以的,你可以從 git reflog 指令去翻翻看,Reflog 預設會保留 30 天,所以 30 天內應該都還找得到。Reflog 的使用方式,可參閱「【狀況題】不小心使用 hard 模式 Reset 了某個 Commit,救得回來嗎?」章節介紹。

【觀念】其實所謂的「合併分支」,合併的並不是「分支」…

如果你對 Git 的分支的觀念是正確的,你應該可以猜到知道下面這個指令在做什麼:

$ git merge b174a5a
Updating e12d8ef..b174a5a
Fast-forward
 cat1.html | 0
 cat2.html | 0
 2 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 cat1.html
 create mode 100644 cat2.html

咦?這訊息不是在合併分支的時候跳出來的訊息嗎?是的,所謂的「合併分支」,其實是合併「分支指向的那個 Commit」。分支只是一張貼紙,它是沒辦法被合併的,只是我們會用「合併分支」這個說法,畢竟它比較「合併 Commit」來得容易想像。

重要觀念!

分支只是一個指向某個 Commit 的指標。


← 上一章:【常見問題】合併過的分支要留著嗎? 下一章:另一種合併方式(使用 rebase) →

Comments