1-分離 HEAD
1-1-說明
1-1-1-HEAD 移動
在接觸 git 的更多進階的主題之前,我們先學習用不同的方法在你的 project 中的 commit tree 上面移動。
一旦能夠熟練地在 commit tree 中隨意地移動,你使用其它的 git 指令也會更厲害!
1-1-2-HEAD
我們首先看一下 “HEAD”,HEAD 是一個 reference,它是指向目前所 checkout 的 commit,基本上,其實就是你目前所在的 commit。
在 commit tree 中,HEAD 總是指向最近的一次commit。大部份 git 的指令如果要修改 commit tree 的狀態的話,都會先改變 HEAD 所指向的 commit。
HEAD 通常指向一個 branch 的名稱(比如 bugFix)。當你 commit 的時候,改變了 bugFix 的狀態,這一個變化可以從 HEAD 的改變中看到。
在實際的例子中。我們將會觀察 commit 前後 HEAD 的位置。
1 2 3 4 | git checkout C1; git checkout master; git commit; git checkout C2; |
1-1-3-分離 HEAD
分離 HEAD 就是讓其指向一個 commit 而不是 branch 的名稱。這是指令執行之前的樣子:
HEAD -> master -> C1
1 | git checkout C1 |
1-2-解題
想要完成這一個關卡,從 bugFix 分離出 HEAD 並且讓它指向一個 commit。
通過 hash 值可以指定 commit。每個 commit 的 hash 值顯示在各自的圓圈中。
1 | git checkout C4 // 直接將 HEAD 分離出來 |
2-相對引用(^)
2-1-介紹
2-1-1-相對引用
如果要在 git 中移動,透過指定 commit 的 hash 值的方式會變得比較麻煩。在實際例子中,你的終端機上面不會出現漂亮且具備視覺效果的 commit tree,所以你不得不用 git log 來查詢 hash 值。
另外,hash 值的長度在真實的 git 環境中很長。舉個例子,前一個關卡的介紹中的 commit 的 hash 值是 fed2da64c0efc5293610bdd892f82a58e8cbc5d8。舌頭不要打結了…
幸運的是,git 對於處理 hash 值很有一套。你只需要提供能夠唯一辨識出該 commit 的前幾個字元就可以了。所以,我可以只輸入 fed2 而不是上面的一長串字元。
我說過,透過 hash 值來指定 commit 不是很方便,所以 git 加入了相對引用。這個就很厲害了!
使用相對引用,你可以從一個易於記憶的地方(比如說 branch 名稱 bugFix 或 HEAD)開始工作。
相對引用非常好用,這裡我介紹兩個簡單的用法:
- 使用 ^ 向上移動一個 commit
- 使用 ~<num> 向上移動多個 commit
首先看看插入(^)這一個符號。把這個符號接在某一個 reference 後面,就表示你告訴 git 去找到該 reference 所指向的 commit 的 parent commit。
所以 master^ 相當於 “ master 的 parent commit”。
master^^ 是 master 的 grandparent commit(往前推兩代)
切換到 master的 parent commit
1 | git checkout master^ |
你也可以把 HEAD 當作相對引用。以下指令使用 HEAD 在 commit tree 中向上移動數次。
1 2 3 4 | git checkout C3 git checkout HEAD^ git checkout HEAD^ git checkout HEAD^ |
2-2-解題
要完成這一關,切換到 bugFix 的 parent commit。這會分離出 HEAD。
如果你願意的話,透過直接指定 hash 值的方式也可以過關,但是還是試試看相對引用吧!
1 | git checkout C3 |
3- 相對引用二(~)
3-1-介紹
3-1-1- ~ 符號
假設需要在 commit tree 中向上移動多個 commit。使用太多 ^ 會非常討人厭,所以 Git 也加入了波浪( ~)符號。
波浪符號後面可以選擇一個數字(你也可以不選擇),該數字可以告訴 Git 我要向上移動多少個 commit 。舉個例子
使用指令 git chekcout HEAD~4 ,讓目前的 HEAD 後對四格 (目前的 commit 也要算進一個)。
3-1-2-Branch forcing
你現在是相對引用的高手了,現在用它來實際做點事情。
我使用相對引用最多的就是移動分支。你可以使用 -f 選項直接讓分支指向另一個 commit。舉個例子:
1 2 | git branch -f master HEAD~3 // (強制)移動 master 指向從 HEAD 往上數的第三個 parent commit。 |
3-2-解題
要完成這一關,移動 HEAD,master 和 bugFix 到目標所示的位置。
1 2 3 4 5 | git checkout master git branch -f master HEAD~2 git merge C6 // master 分支上合併到 C6 commit git branch -f bugFix HEAD~4 // 在 master 分支上命令 bugFix 分支退 4 個 commit git checkout C1 // HEAD 直接切到 C1 的 commit 上面 |
1 2 3 | git branch -f master C6 git checkout HEAD~1 git branch -f bugFix HEAD~1 |
可以不用透過 HEAD 切到指定的分支, 透過直接指定分支命與 -f 參數,來操作指定退的格數或是當定的 coomit hash 編號上。
git branch -f master C6
將 master 分支直接指定到 C6 的 HASH 編號上。
git checkout HEAD~1
直接指定 HEAD 退一格,不用帶 -f 參數。
git branch -f bugFix HEAD~1
4-在 git 中取消修改
4-1-介紹
4-1-1-取消 git 的修改
在 git 裡面取消修改的方法很多。和 commit 一樣,在 git 裡面取消修改同時具有底層的部份(暫存一些獨立的文件或者片段)和高層的部份(修改是如何被取消)。我們主要講的重點是後者。
在 git 裡主要用兩種方法來取消修改,一種是 git reset,另外一種是 git revert。讓我們在下一個對話視窗中逐一瞭解它們。
4-1-2-Git Reset
git reset 把分支的參考點退回到上一個 commit 來取消修改。你可以認為這是在”重寫歷史”。git reset 往回移動 branch,原來的 branch 所指向的 commit 好像從來沒有存在過一樣。
使用指令 git reset HEAD~1 ,譠 commit 退一格。
4-1-3-Git Revert
雖然在你的 local branch 中使用 git reset 很方便,但是這種「改寫歷史」的方法對別人的 remote branch 是無效的哦!
為了取消修改並且把這個狀態分享給別人,我們需要使用 git revert。舉個例子
使用指令 git revert HEAD ,在當前的 commit 點另外在長出同樣內容的 commit。
4-2-解題
要完成這一關,分別取消 local branch 和 pushed branch 上的最近的一次 commit。
記住 pushed 是一個 remote branch,local 是一個 local branch,有了這麼明顯的提示應該知道要用哪種方法了吧?
1 2 3 | git reset local^ git checkout pushed git revert pushed |