Learn Git in 30 days——第 11 天:認識 Git 物件的一般參照與符號參照

寫的非常好的一個Git系列文章,強烈推薦

原文鏈接:https://github.com/doggy8088/Learn-Git-in-30-days/tree/master/zh-cn

在認識了 Git 物件的「絕對名稱」後,接下來就要介紹 Git 版控過程中最常用到的「參照名稱」。

認識物件的參照名稱

參照名稱 (ref) 簡單來說就是 Git 物件的一個「指標」,或是相對於「絕對名稱」的另一個「好記名稱」,用一個預先定義或你自行定義的名稱來代表某一個 Git 物件。

在我們之前學到的「分支名稱」或我們曾經用過的 HEAD (代表最新版本),或是我們之後會學到的「標籤名稱」,這些都是「參照名稱」,總之就是爲了讓你好記而已。

我們以「分支名稱」爲例,來說明一下「參照名稱」的實體結構爲何。以下圖爲例,我們通過 git branch 取得所有分支名稱,你可以看到我們目前有三個分支,然而這三個分支的名稱其實就是一個「參照名稱」,這代表這三個「參照名稱」分別對應到 Git 物件倉庫中的三個 commit 物件。在下圖中你也可以看出這些分支的參照名稱其實就是一個文件而已,所有「本地分支」的參照名稱皆位於 .git\refs\heads 目錄下:

image

接着我再以下圖來證明這個文件是如何跟「絕對名稱」做連結。我先通過 git branch 取得所有分支名稱,並發現目前「工作目錄」是指向 newbranch1 這個分支。此時我們通過 git log --pretty=oneline 即可取得該分支的所有版本記錄。預設這些分支的「參照名稱」會指向分支的「最新版」,我們只要打開 .git\refs\heads\newbranch1 文件的內容,就可以看出這是一個純文字檔而已,而且是指向版本歷史記錄中的「最新版」。最後再以 git cat-file -p 0bd0 取得該 commit 物件的內容,以及用 git show 0bd0 取得該版本的變更記錄,藉此證明這些文件就是「參照名稱」的主要用途。

image

我們再通過指令看看使用「絕對名稱」與「參照名稱」讀取特定 commit 物件的內容,證明這兩個指令執行的結果是相同的:

image

在大多數的情況下,「參照名稱」通常都會指向一個 commit 物件,但並非必要,你也可以指向其他 Git 物件類型,像是 blob 物件、tree 物件、tag 物件等等。

關於 .git/refs/ 目錄

從上述範例其實已經能看出,所有的「參照名稱」都是個文件,而且一律放在 git/refs/ 目錄下。而 Git 的參照名稱所放置的目錄位置,主要有三個:

  • 本地分支:.git/refs/heads/
  • 遠端分支:.git/refs/remotes/
  • 標  籤:.git/refs/tags/

再舉個簡單例子,如果你建立一個分支名稱爲 f2e,這時你會知道本地分支的「參照名稱」會建立 .git/refs/heads/f2e 文件,如下圖示:

image

事實上,這個 f2e 的「全名」應該叫做 refs/heads/f2e 纔對,只是 Git 允許你輸入簡寫,方便你快速輸入參照名稱而已。如下圖示,這三種使用「參照名稱」的方式都是可行的:

image

不過當你輸入參照名稱的「簡稱」時,預設 Git 會依照以下順序搜尋適當的參照名稱,只要找到對應的文件,就會立刻回傳該文件內容的「物件絕對名稱」:

  • .git/<參照簡稱>
  • .git/refs/<參照簡稱>
  • .git/refs/tags/<參照簡稱;標籤名稱>
  • .git/refs/heads/<參照簡稱;本地分支名稱>
  • .git/refs/remotes/<參照簡稱>
  • .git/refs/remotes/<參照簡稱;遠端分支名稱>/HEAD

例如,當你輸入 git cat-file -p f2e 指令的話,那麼 Git 就會用以下順序找到相對的「參照名稱檔」,取出該文件的內容 (即 Git 物件的絕對名稱):

  • .git/f2e --> 找不到此文件
  • .git/refs/f2e --> 找不到此文件
  • .git/refs/tags/f2e --> 找不到此文件
  • .git/refs/heads/f2e --> 找到了參照名稱,以下就不繼續搜尋
  • .git/refs/remotes/f2e
  • .git/refs/remotes/f2e/HEAD

認識物件的符號參照名稱 (symref)

符號參照名稱 (symref) 其實也是參照名稱 (ref) 的一種,只是內容不同而已。我們從下圖應可看出其內容的差異,「符號參照」會指向另一個「參照名稱」,並且內容以 ref: 開頭:

image

在 Git 工具中,預設會維護一些特別的符號參照,方便我們快速取得常用的 commit 物件,且這些物件預設都會儲存在 .git/ 目錄下。這些符號參考有以下四個:

  • HEAD
    • 永遠會指向「工作目錄」中所設定的「分支」當中的「最新版」。
    • 所以當你在這個分支執行 git commit 後,這個 HEAD 符號參照也會更新成該分支最新版的那個 commit 物件。
  • ORIG_HEAD
    • 簡單來說就是 HEAD 這個 commit 物件的「前一版」,經常用來複原上一次的版本變更。
  • FETCH_HEAD
    • 使用遠端倉庫時,可能會使用 git fetch 指令取回所有遠端倉庫的物件。這個 FETCH_HEAD 符號參考則會記錄遠端倉庫中每個分支的 HEAD (最新版) 的「絕對名稱」。
  • MERGE_HEAD
    • 當你執行合併工作時 (關於合併的議題會在日後的文章中會提到),「合併來源」的 commit 物件絕對名稱會被記錄在 MERGE_HEAD 這個符號參照中。

一般參照與符號參照的使用方式

我們知道「參照名稱」有特殊的目的,通常用於「本地分支」、「遠端分支」與「標籤」等情境下,但事實上你可以建立任意數量的「自訂參照名稱」,只要通過 git update-ref 就可以自由建立「一般參照」。

我企圖建立一個名爲 InitialCommit 的一般參照,並指向 Git 倉庫中的第一個版本,請參見如下圖的指令執行順序,得知一般參照的建立方式:

image

建立完成後,預設文件會放在 .git 資料夾下,且此時用「絕對名稱」與「參照名稱」都能存取特定 Git 物件的內容:

image

注:請記得,參照名稱可以指向任意 Git 物件,並沒有限定非要 commit 物件不可。

若要建立較爲正式的參照名稱,最好加上 refs/ 開頭,例如:git update-ref refs/InitialCommit [object_id]

若要刪除一般參照,則可以使用 -d 選項。如下圖示:

image

顯示所有參照的方式,則可以使用 git show-ref 指令,如下圖示:

image

若要建立與刪除「符號參照」,可以參考如下圖 git symbolic-ref 的用法。請自行看圖說故事,理解之後,你真的會發現 Git 對於參照的用法非常靈活且強大。還有,執行 git show-ref 只會顯示在 .git\refs 目錄下的那些參照,而且不管是「一般參照」或「符號參照」都一樣:

image

本文稍早提到你可以建立參照到以下目錄:

  • .git/<參照簡稱>
  • .git/refs/<參照簡稱>
  • .git/refs/tags/<參照簡稱;標籤名稱>
  • .git/refs/heads/<參照簡稱;本地分支名稱>
  • .git/refs/remotes/<參照簡稱>
  • .git/refs/remotes/<參照簡稱;遠端分支名稱>/HEAD

自訂參照通常會自行建立在前兩個路徑下,以免分不清跟我們使用「本地分支」、「遠端分支」與「標籤」的使用方式。不過,你的確可以利用 git update-ref 建立任何自訂參照,若把自訂參照建立在 refs/heads/Will 的話,也等同於建立了一個名爲 Will 的分支,而 Git 真的就是這麼單純,當你越來越瞭解 Git 的內部結構,也會更加喜歡上 Git 的各種特性。

今日小結

我們知道「參照名稱 (ref)」 簡單來說就是 Git 物件的一個「指標」,用來指向特定 Git 物件,所以你可以把「參照名稱」想像成 Git 物件絕對名稱的別名 (Alias),用來幫助記憶。在 Git 裏,有許多機制可以幫你控制項目,例如「分支」、「標籤」等等,這些機制骨子裏其實就是靠「參照」完成的。

Git 參照名稱又有區分「一般參照」與「符號參照」,兩者的用途一模一樣,只在於內容不太一樣。「符號參照」會指向另一個「一般參照」,而「一般參照」則是指向一個 Git 物件的「絕對名稱」。

我重新整理一下本日學到的 Git 指令與參數:

  • git branch
  • git log --pretty=oneline
  • git log --oneline
  • git cat-file -p [ref or object_id]
  • git show [ref or object_id]
  • git update-ref
  • git symbolic-ref
  • git show-ref
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章