Git
章節 ▾ 第二版

10.3 Git 內部 - Git 參考

Git 參考

如果您想查看從提交(例如 `1a410e`)可訪問的儲存庫歷史記錄,您可以執行類似 `git log 1a410e` 的命令來顯示該歷史記錄,但您仍然必須記住 `1a410e` 是您想要用作歷史記錄起點的提交。相反,如果您有一個檔案,可以將該 SHA-1 值以一個簡單的名稱儲存,這樣您就可以使用該簡單的名稱而不是原始 SHA-1 值,那就更容易了。

在 Git 中,這些簡單的名稱稱為「參考」(references)或「refs」;您可以在 `.git/refs` 目錄中找到包含這些 SHA-1 值的檔案。在目前的專案中,這個目錄不包含任何檔案,但它確實包含一個簡單的結構。

$ find .git/refs
.git/refs
.git/refs/heads
.git/refs/tags
$ find .git/refs -type f

要建立一個新的參考,以幫助您記住最新的提交位置,您可以在技術上執行如下簡單的操作:

$ echo 1a410efbd13591db07496601ebc7a059dd55cfe9 > .git/refs/heads/master

現在,您可以使用剛剛建立的 head 參考,而不是 Git 命令中的 SHA-1 值。

$ git log --pretty=oneline master
1a410efbd13591db07496601ebc7a059dd55cfe9 Third commit
cac0cab538b970a37ea1e769cbbde608743bc96d Second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d First commit

不建議您直接編輯參考檔案;相反,Git 提供了更安全的 `git update-ref` 命令來執行此操作,如果您想更新參考。

$ git update-ref refs/heads/master 1a410efbd13591db07496601ebc7a059dd55cfe9

這基本上就是 Git 中分支的概念:一個簡單的指標或參考,指向工作線的開頭。要建立回到第二個提交的分支,您可以執行以下操作:

$ git update-ref refs/heads/test cac0ca

您的分支將只包含該提交開始之後的工作。

$ git log --pretty=oneline test
cac0cab538b970a37ea1e769cbbde608743bc96d Second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d First commit

現在,您的 Git 資料庫在概念上看起來像這樣:

Git directory objects with branch head references included
圖 176. 包含分支 head 參考的 Git 目錄物件

當您執行像 git branch <branch> 這樣的指令時,Git 基本上會執行 update-ref 指令,將您目前所在分支的最後一次提交的 SHA-1 值,加入到您想要建立的任何新參考中。

HEAD

現在的問題是,當您執行 git branch <branch> 時,Git 如何知道最後一次提交的 SHA-1 值?答案是 HEAD 檔案。

通常,HEAD 檔案是一個指向您目前所在分支的符號參考。所謂符號參考,是指它不像一般的參考,而是包含指向另一個參考的指標。

然而,在某些罕見的情況下,HEAD 檔案可能包含 Git 物件的 SHA-1 值。當您檢出一個標籤、提交或遠端分支時,就會發生這種情況,這會將您的儲存庫置於「分離 HEAD」狀態。

如果您查看該檔案,通常會看到類似這樣的內容

$ cat .git/HEAD
ref: refs/heads/master

如果您執行 git checkout test,Git 會更新檔案使其看起來像這樣

$ cat .git/HEAD
ref: refs/heads/test

當您執行 git commit 時,它會建立提交物件,並將該提交物件的父物件指定為 HEAD 中參考指向的任何 SHA-1 值。

您也可以手動編輯此檔案,但有一個更安全的指令可以做到這一點:git symbolic-ref。您可以使用此指令讀取 HEAD 的值

$ git symbolic-ref HEAD
refs/heads/master

您也可以使用相同的指令設定 HEAD 的值

$ git symbolic-ref HEAD refs/heads/test
$ cat .git/HEAD
ref: refs/heads/test

您不能在 refs 樣式之外設定符號參考

$ git symbolic-ref HEAD test
fatal: Refusing to point HEAD outside of refs/

標籤

我們剛剛討論完 Git 的三個主要物件類型(blobstreescommits),但還有第四個。tag 物件非常像提交物件 — 它包含標籤者、日期、訊息和指標。主要區別在於標籤物件通常指向提交,而不是樹狀結構。它就像一個分支參考,但它永遠不會移動 — 它始終指向相同的提交,但會給它一個更友好的名稱。

Git 基礎中所討論的,標籤有兩種:附註標籤和輕量標籤。您可以執行類似這樣的指令來建立輕量標籤

$ git update-ref refs/tags/v1.0 cac0cab538b970a37ea1e769cbbde608743bc96d

這就是輕量標籤的全部 — 一個永遠不會移動的參考。但是,附註標籤更複雜。如果您建立一個附註標籤,Git 會建立一個標籤物件,然後寫入一個指向該物件的參考,而不是直接指向提交。您可以透過建立一個附註標籤(使用 -a 選項)來查看此情況

$ git tag -a v1.1 1a410efbd13591db07496601ebc7a059dd55cfe9 -m 'Test tag'

這是它建立的物件 SHA-1 值

$ cat .git/refs/tags/v1.1
9585191f37f7b0fb9444f35a9bf50de191beadc2

現在,對該 SHA-1 值執行 git cat-file -p

$ git cat-file -p 9585191f37f7b0fb9444f35a9bf50de191beadc2
object 1a410efbd13591db07496601ebc7a059dd55cfe9
type commit
tag v1.1
tagger Scott Chacon <schacon@gmail.com> Sat May 23 16:48:58 2009 -0700

Test tag

請注意,該物件條目指向您標記的提交 SHA-1 值。另請注意,它不需要指向提交;您可以標記任何 Git 物件。例如,在 Git 原始碼中,維護者已將其 GPG 公鑰作為 blob 物件新增,然後對其進行標記。您可以在 Git 儲存庫的複製版本中執行此操作來查看公鑰

$ git cat-file blob junio-gpg-pub

Linux 核心儲存庫也有一個非提交指向的標籤物件 — 建立的第一個標籤指向導入原始碼的初始樹狀結構。

遠端

您將看到的第三種類型的參考是遠端參考。如果您新增一個遠端並推送至該遠端,Git 會將您上次推送至該遠端的每個分支的值儲存在 refs/remotes 目錄中。例如,您可以新增一個名為 origin 的遠端,並將您的 master 分支推送至該遠端

$ git remote add origin git@github.com:schacon/simplegit-progit.git
$ git push origin master
Counting objects: 11, done.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (7/7), 716 bytes, done.
Total 7 (delta 2), reused 4 (delta 1)
To git@github.com:schacon/simplegit-progit.git
  a11bef0..ca82a6d  master -> master

然後,您可以透過檢查 refs/remotes/origin/master 檔案,查看您上次與伺服器通訊時 origin 遠端上的 master 分支是什麼

$ cat .git/refs/remotes/origin/master
ca82a6dff817ec66f44342007202690a93763949

遠端參考與分支(refs/heads 參考)的主要區別在於,它們被視為唯讀。您可以 git checkout 到一個遠端參考,但 Git 不會將 HEAD 符號參考到它,因此您永遠不會使用 commit 指令更新它。Git 將它們作為書籤來管理,這些書籤指向這些分支在這些伺服器上的最後已知狀態。

scroll-to-top