你可以執(zhí)行像 git log 1a410e
這樣的命令來查看完整的歷史,但是這樣你就要記得 1a410e
是你最后一次提交,這樣才能在提交歷史中找到這些對象。你需要一個(gè)文件來用一個(gè)簡單的名字來記錄這些 SHA-1 值,這樣你就可以用這些指針而不是原來的 SHA-1 值去檢索了。
在 Git 中,我們稱之為“引用”(references 或者 refs,譯者注)。你可以在 .git/refs
目錄下面找到這些包含 SHA-1 值的文件。在這個(gè)項(xiàng)目里,這個(gè)目錄還沒不包含任何文件,但是包含這樣一個(gè)簡單的結(jié)構(gòu):
$ find .git/refs
.git/refs
.git/refs/heads
.git/refs/tags
$ find .git/refs -type f
$
如果想要?jiǎng)?chuàng)建一個(gè)新的引用幫助你記住最后一次提交,技術(shù)上你可以這樣做:
$ echo "1a410efbd13591db07496601ebc7a059dd55cfe9" > .git/refs/heads/master
現(xiàn)在,你就可以在 Git 命令中使用你剛才創(chuàng)建的引用而不是 SHA-1 值:
$ git log --pretty=oneline master
1a410efbd13591db07496601ebc7a059dd55cfe9 third commit
cac0cab538b970a37ea1e769cbbde608743bc96d second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit
當(dāng)然,我們并不鼓勵(lì)你直接修改這些引用文件。如果你確實(shí)需要更新一個(gè)引用,Git 提供了一個(gè)安全的命令 update-ref
:
$ git update-ref refs/heads/master 1a410efbd13591db07496601ebc7a059dd55cfe9
基本上 Git 中的一個(gè)分支其實(shí)就是一個(gè)指向某個(gè)工作版本一條 HEAD 記錄的指針或引用。你可以用這條命令創(chuàng)建一個(gè)指向第二次提交的分支:
$ git update-ref refs/heads/test cac0ca
這樣你的分支將會(huì)只包含那次提交以及之前的工作:
$ git log --pretty=oneline test
cac0cab538b970a37ea1e769cbbde608743bc96d second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit
現(xiàn)在,你的 Git 數(shù)據(jù)庫應(yīng)該看起來像圖 9-4 一樣。
圖 9-4. 包含分支引用的 Git 目錄對象
每當(dāng)你執(zhí)行 git branch (分支名稱)
這樣的命令,Git 基本上就是執(zhí)行 update-ref
命令,把你現(xiàn)在所在分支中最后一次提交的 SHA-1 值,添加到你要?jiǎng)?chuàng)建的分支的引用。
現(xiàn)在的問題是,當(dāng)你執(zhí)行 git branch (分支名稱)
這條命令的時(shí)候,Git 怎么知道最后一次提交的 SHA-1 值呢?答案就是 HEAD 文件。HEAD 文件是一個(gè)指向你當(dāng)前所在分支的引用標(biāo)識符。這樣的引用標(biāo)識符——它看起來并不像一個(gè)普通的引用——其實(shí)并不包含 SHA-1 值,而是一個(gè)指向另外一個(gè)引用的指針。如果你看一下這個(gè)文件,通常你將會(huì)看到這樣的內(nèi)容:
$ cat .git/HEAD
ref: refs/heads/master
如果你執(zhí)行 git checkout test
,Git 就會(huì)更新這個(gè)文件,看起來像這樣:
$ cat .git/HEAD
ref: refs/heads/test
當(dāng)你再執(zhí)行 git commit
命令,它就創(chuàng)建了一個(gè) commit 對象,把這個(gè) commit 對象的父級設(shè)置為 HEAD 指向的引用的 SHA-1 值。
你也可以手動(dòng)編輯這個(gè)文件,但是同樣有一個(gè)更安全的方法可以這樣做:symbolic-ref
。你可以用下面這條命令讀取 HEAD 的值:
$ git symbolic-ref HEAD
refs/heads/master
你也可以設(shè)置 HEAD 的值:
$ git symbolic-ref HEAD refs/heads/test
$ cat .git/HEAD
ref: refs/heads/test
但是你不能設(shè)置成 refs 以外的形式:
$ git symbolic-ref HEAD test
fatal: Refusing to point HEAD outside of refs/
你剛剛已經(jīng)重溫過了 Git 的三個(gè)主要對象類型,現(xiàn)在這是第四種。Tag 對象非常像一個(gè) commit 對象——包含一個(gè)標(biāo)簽,一組數(shù)據(jù),一個(gè)消息和一個(gè)指針。最主要的區(qū)別就是 Tag 對象指向一個(gè) commit 而不是一個(gè) tree。它就像是一個(gè)分支引用,但是不會(huì)變化——永遠(yuǎn)指向同一個(gè) commit,僅僅是提供一個(gè)更加友好的名字。
正如我們在第二章所討論的,Tag 有兩種類型:annotated 和 lightweight 。你可以類似下面這樣的命令建立一個(gè) lightweight tag:
$ git update-ref refs/tags/v1.0 cac0cab538b970a37ea1e769cbbde608743bc96d
這就是 lightweight tag 的全部 —— 一個(gè)永遠(yuǎn)不會(huì)發(fā)生變化的分支。 annotated tag 要更復(fù)雜一點(diǎn)。如果你創(chuàng)建一個(gè) annotated tag,Git 會(huì)創(chuàng)建一個(gè) tag 對象,然后寫入一個(gè)指向指向它而不是直接指向 commit 的 reference。你可以這樣創(chuàng)建一個(gè) annotated tag(-a
參數(shù)表明這是一個(gè) annotated tag):
$ git tag -a v1.1 1a410efbd13591db07496601ebc7a059dd55cfe9 -m 'test tag'
這是所創(chuàng)建對象的 SHA-1 值:
$ cat .git/refs/tags/v1.1
9585191f37f7b0fb9444f35a9bf50de191beadc2
現(xiàn)在你可以運(yùn)行 cat-file
命令檢查這個(gè) SHA-1 值:
$ 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
值得注意的是這個(gè)對象指向你所標(biāo)記的 commit 對象的 SHA-1 值。同時(shí)需要注意的是它并不是必須要指向一個(gè) commit 對象;你可以標(biāo)記任何 Git 對象。例如,在 Git 的源代碼里,管理者添加了一個(gè) GPG 公鑰(這是一個(gè) blob 對象)對它做了一個(gè)標(biāo)簽。你就可以運(yùn)行:
$ git cat-file blob junio-gpg-pub
來查看 Git 源代碼倉庫中的公鑰. Linux kernel 也有一個(gè)不是指向 commit 對象的 tag —— 第一個(gè) tag 是在導(dǎo)入源代碼的時(shí)候創(chuàng)建的,它指向初始 tree (initial tree,譯者注)。
你將會(huì)看到的第四種 reference 是 remote reference(遠(yuǎn)程引用,譯者注)。如果你添加了一個(gè) remote 然后推送代碼過去,Git 會(huì)把你最后一次推送到這個(gè) remote 的每個(gè)分支的值都記錄在 refs/remotes
目錄下。例如,你可以添加一個(gè)叫做 origin
的 remote 然后把你的 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
這個(gè)文件,你就會(huì)發(fā)現(xiàn) origin
remote 中的 master
分支就是你最后一次和服務(wù)器的通信。
$ cat .git/refs/remotes/origin/master
ca82a6dff817ec66f44342007202690a93763949
Remote 引用和分支主要區(qū)別在于他們是不能被 check out 的。Git 把他們當(dāng)作是標(biāo)記了這些分支在服務(wù)器上最后狀態(tài)的一種書簽。
更多建議: