我們在 git-21 救回分支 一文中已經介紹過如何救回分支的方法。
這次我們要來個分解動作,主要是想介紹一個 detached
「斷頭」的狀態讓大家認識。
我們已經知道 HEAD 通常會指向一個分支,而分支會指向一個 commit 這樣。
但如果有一個 commit 沒有分支指向它,它就沒有分支,也就是呈現 `` 斷頭狀態。
現在我們在 master 刪除 logo 分支,然後用 reflog 找到最後切過去的 logo commit 切回去看看。
$ git branch
kevinlin
logo
* master
$ git branch -d logo
Deleted branch logo (was fb031d9).
$ git branch
kevinlin
* master
$ git reflog -3
b3b1b97 (HEAD -> master, origin/master, origin/HEAD) HEAD@{0}: checkout: moving
from logo to master
fb031d9 (origin/logo) HEAD@{1}: checkout: moving from master to logo
b3b1b97 (HEAD -> master, origin/master, origin/HEAD) HEAD@{2}: checkout: moving
from logo to master
# 看起來是第二個
$ git checkout fb031d9
# 之前我們用 checkout 來切換分支,現在是直接切換到某個 commit
Note: switching to 'fb031d9'.
# 切到這個 commit 的警告
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.
# 在這個斷頭狀態下,你可以像平常一樣提交,當然你也可以切換到其他分支而放棄這裡
# 提醒一下,在斷頭的 commit 比較不容易被找到,除非是 reflog
# 同時,在這裡做的動作不會影響到任何分支
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:
git switch -c <new-branch-name>
# 你可以創建一個分支來指向這個提交,使它脫離斷頭的狀態
# 新版的切換都會用 switch 舊版的是 checkout
# 同時我們也學到 checkout -b 相當於 switch -c 這些在 [後悔藥有得買1](https://www.nvda.org.tw/discussion/ui=100200tm=1969753631) 曾經提過。
# 我們在之前
Or undo this operation with:
git switch -
# 或者是你也可以下指令來回到之前還沒斷頭的最後狀態
Turn off this advice by setting config variable advice.detachedHead to false
# 如果你覺得上面這些提示很煩人,可以去設定裡把 advice.detachedHead 設定成 false
HEAD is now at fb031d9 1.在派文管理將已派文單位改成表格方式呈現 2.在派文管理之已
派文單位可以取消派文
# 好吧,我儘量翻譯了,實際上這一句才是最重要的
# 不過我不建議新手關掉提示設定,因為有可能會忘記指令或一下子很慌張之類的。
看一下狀態:
$ git status
HEAD detached at fb031d9
nothing to commit, working tree clean
# 真的是斷頭中了
或許有伙伴會問,那用 checkout 跟 reset 來切 commit 有什麼不同?
大家要注意,這是不同的概念, reset 是會移動現在分支裡的 HEAD 到其他的 commit
你做的任何動作都是在這個分支底下的行為。但 checkout 比較像是把整個分支切到某個 commit 上面去。
像我們切換的 fb031d9
實際上 master, origin/logo 等都有這個提交存在,
所以用 reset 不會斷頭,但 checkout 過去時,因為本地的 logo 最後一個 HEAD 是指像它,可是 logo 已經被我們刪掉了,
使用 reflog 可以看到,遠端的 origin/logo 雖然也指向這個 commit,但本地沒這個分支,就會顯示斷頭了。
那我們繼續討論,使用 switch 跟 checkout 來切 commit 有什麼不同?
switch 是針對分支,如果是下 switch fb... 那串 commit id 它會以為你要切到這個分支,但實際上你沒有這個分支。
不過你可以使用 switch -d fb 那串來切到這個斷頭的 commit 上面,因此 switch 還是可以完全取代 checkout 指令。
那要處理斷頭就很簡單了,看是要開個分支指向它還是跑錯地方想回家都可以,
這部分之前的文章提過,這邊就不說了。
而斷頭發生的另外時機就是處在 rebase 當中。
最後,補上這些關於斷頭的文章。