Git 斷頭了!怎麼辦?
前情提要
某天,我的 git graph 長這樣:
$ git log --oneline --graph --decorate
* d1017cd (HEAD -> master, origin/master) Delete content in temp.txt
* 7d729ae Add content to temp.txt
* 0ac097d Add temp.txt
原本我在 master 分支上的第三個 commit,我想回到第二個 commit 的時間點拿過去的東西,因此我執行了,
$ git checkout 7d729ae
當我拿完東西,我回到原本的第三個 commit,
$ git checkout d1017cd
接著我開心地繼續寫新東西,寫完,commit!
$ git commit -m "Add temp.py"
commit 完,push!
git push
燈冷~ push 失敗!還出現怪怪訊息
fatal: You are not currently on a branch.
To push the history leading to the current (detached HEAD)
state now, use
git push origin HEAD:<name-of-remote-branch>
討論
原因是,一旦 HEAD 離開分支尾端回到先前狀態時,git 會預設 user 打算離開目前分支,並開一條新的分支從舊的 commit 點分岔出來繼續開發。但是偏偏 git 並不會自己定義新的分支,導致 HEAD 沒有指向任何分支的窘境。這就叫 detached HEAD,斷頭啦!就算重新 checkout 回最後一個 commit,斷頭的狀況還是存在。
解決方法(一)
一旦回到舊時間點拿完東西,在產生 detached HEAD 之後,記得要隨即 chechout 回原本分支
$ git checkout master
如此一來斷頭狀態就解除了,可以再繼續開發下去。
解決方法(二)
若忘記 checkout 回原本分支就繼續往下走,狀態會變成:
$ git log --oneline --graph --decorate
* d9837b5 (HEAD) Add temp.py
* d1017cd (origin/master, master) Delete content in temp.txt
* 7d729ae Add content to temp.txt
* 0ac097d Add temp.txt
觀察 HEAD 指向的地方,在原本 master 的位置分岔出一條未定義的分支。要讓這條分支能落在 master 上,首先,給不小心岔出來的路徑配上一個正式分支,我暫且把它命名為 oops,
$ git branch oops d9837b5
再走到 oops 的位置,
$ git checkout oops
執行 rebase 指令,
$ git rebase master
rebase 指令能夠把 oops 接到 master 之後,如下:
$ git log --oneline --graph --decorate
* d9837b5 (HEAD -> oops) Add temp.py
* d1017cd (origin/master, master) Delete content in temp.txt
* 7d729ae Add content to temp.txt
* 0ac097d Add temp.txt
接著回到 master,
$ git checkout master
執行 merge 指令,
$ git merge oops
merge 指令能讓 master 走到跟新分支一樣的位置,如下:
$ git log --oneline --graph --decorate
* d9837b5 (HEAD -> master, oops) Add temp.py
* d1017cd (origin/master) Delete content in temp.txt
* 7d729ae Add content to temp.txt
* 0ac097d Add temp.txt
如此一來,斷頭之後的工作都成功轉移到 master 上。那麼分支 oops 已經不需要了,把它刪了吧~
$ git branch -d oops
此時狀態看起來乾乾淨淨,就好像什麼事也沒發生一樣!
$ git log --oneline --graph --decorate
* d9837b5 (HEAD -> master) Add temp.py
* d1017cd (origin/master) Delete content in temp.txt
* 7d729ae Add content to temp.txt
* 0ac097d Add temp.txt
趕緊 push 到遠端,
$ git push
大功告成!
$ git log --oneline --graph --decorate
* d9837b5 (HEAD -> master, origin/master) Add temp.py
* d1017cd Delete content in temp.txt
* 7d729ae Add content to temp.txt
* 0ac097d Add temp.txt