Git 中的關鍵字、符號和基本組成
本章節初學者請直接跳過以後再回來看,快點學會實際指令才是真的。
基本
- HEAD:目前工作的 commit 位置
^
:前一個提交,~n
:前 n 個提交--
:檔案與函式選項的分界線- blob, tree, commit, tag, refs:Git 的基本單位
範例:
git reset --hard HEAD^ # 回到前一個提交
git reset --hard HEAD^^^ # 回到前三個提交
git reset --hard HEAD~3 # 回到前三個提交
git checkout --options -- file # 分界線
入門
@{n}
:代表分支或引用的歷史位置,用於 reflog+
:在變更的文件中,代表新增的行-
:在變更的文件中,代表刪除的行@@
:用於顯示差異的上下文行號,出現在git diff
的輸出中...
:用於比較兩個分支間的共同祖先
範例1:
$ git reflog
e3f9a68 HEAD@{0}: commit message A
a7b8d9c HEAD@{1}: commit message B
之後可以使用 git reset --hard HEAD@1 還原。
範例2:
$ git show
diff --git a/src/css/custom.css b/src/css/custom.css
index 58e6b10..4fab7e0 100644
--- a/src/css/custom.css
+++ b/src/css/custom.css
@@ -4,6 +4,10 @@
* work well for content-centric websites.
*/
+blockquote {
+ border-left-width: 4.5px;
+}
+
--- +++
:代表提交的前後檔案@@ -4,6 +4,10 @@
:hunk 標記
-4,6 表示原文件中從第 4 行開始,有 6 行內容被變更或刪除。
+4,10 表示在新文件中從第 4 行開始,添加了 10 行內容。
中階
Git 是快照系統不是差異系統,只是具備顯示差異的功能,並且將差異作為壓縮儲存空間的手段。
Git 是分散式系統,每個人都有一份完全相同的鏡像,遠端儲存庫只是同步手段而不是集中管理版本。
Git 是分散式鏡像系統,所以你的 reflog 記錄不會被推送到遠端,你應該沒聽過 reflog 衝突這種東西吧?所以這篇文章錯了。
進階
<<<<<
,=====
,>>>>>
:標記合併衝突的區域
<<<<< HEAD
目前的檔案內容
=====
修改的檔案內容
>>>>> hash
合併衝突的區域在 git rebase 中會有點反直覺。舉例來說,當我們位於 feat 分支使用 git rebase main
的衝突中,上面是 main,下面才是 feat,原因是 rebase 的 main 是原有的 base,feat 才是要被放進來的提交,所以才會違反直覺,但邏輯是正確的。
解決合併衝突的方式就是把 <<<<<
, =====
, >>>>>
清除掉就好了,看你要留下哪邊或是兩者都要,完整流程是當你使用 <指令>
(如 merge/rebase/cherry-pick)遇到衝突時,先使用
git status
找到未合併的路徑 Unmerged paths- 編輯該文件選擇你要哪個版本
git add
預存後使用<指令>
--continue,再進行下一個合併衝突解析- 使用 --abort 還原成使用
<指令>
之前的狀態,使用 --quit 不還原強制退出,請謹慎使用 --quit
更進階:blob, tree, tag, commit, refs
扣掉 refs 其他四個是 Git 的基本構成,不重要,對於使用沒有任何幫助。
檔案在 Git 中是一個 blob 物件
- blob 物件僅包含檔案的內容,不包含檔案名稱或任何其他元數據
- tree 記錄檔案位置和目錄結構,記錄 blob 和其他子 tree
- tag 物件用於標記特定的 commit
- commit 物件主要功能是記錄元資料,例如作者、編碼、tree、hash、前一個 commit 的 hash、提交訊息等等
- refs 用來指向特定 hash 的人類可讀名稱,如
refs/heads/main
指向 main 分支的最新提交,或者標籤,或者遠端分支。
把所有單位串連起來,commit 指向 tree,tree 指向 sub-tree 和 blob。這樣短短幾行已經是網路上的一整篇文章了,到底為什麼要寫那麼長,我看了很久才理解,理解完感受到這個知識一點也不重要。如果還是看不懂可以閱讀加速几十倍 git clone 速度的 --depth 1,它的后遗症怎么解决?,雖然不是專門在講 Git 結構但是比網路上那些文筆糟糕的文章清楚多了。
如果你喜歡語言模型列表式的說明,會變成這樣:
-
Blob (二進位大型物件)
- 只儲存檔案的實際內容。不包含檔名或其他中繼資料
- 可以理解為檔案的純內容快照
-
Tree (樹狀結構)
- 記錄整個目錄結構,包含檔案位置資訊
- 指向所屬的 blob 物件和指向其他子目錄的 tree 物件
- 類似檔案系統的目錄結構
-
Tag Object (標籤物件)
- 用來標記特定的 commit
- 通常用於版本發布
-
Commit Object (提交物件)
- 指向一個 tree 物件,這個 tree 物件再指向其他 sub-tree 和 blob,最終形成一個完整的版本快照
-
Refs (參照)
- 唯一用途就是提供人類可讀的名稱,並指向 commit hash,不是必要組成結構
- 常見的例子:
refs/heads/main
指向 main 分支最新的 commit- 標籤名稱指向特定的標籤物件
- 遠端分支的參照
物件之間的關係是:
commit → tree → (sub-trees + blobs)
這樣的結構讓 Git 能夠有效地追蹤和管理程式碼的版本變化。