鍍金池/ 教程/ Java/ Git 引用
腳本 GitHub
Git 鉤子
分支與合并
撤消操作
5.4 總結(jié)
Git 對象
變基
Bash 中的 Git
補丁
Git 引用
項目分享與更新
總結(jié)
GitWeb
Visual Studio 中的 Git
外部系統(tǒng)
替換
Zsh 中的 Git
Git 命令
打包
使用強制策略的一個例子
總結(jié)
簽署工作
分支開發(fā)工作流
遠(yuǎn)程分支
總結(jié)
安裝 Git
Powershell 中的 Git
快照基礎(chǔ)
管理組織
Git 與其他系統(tǒng)
在服務(wù)器上搭建 Git
GitHub
Git 別名
憑證存儲
維護與數(shù)據(jù)恢復(fù)
包文件
子模塊
將 Git 嵌入你的應(yīng)用
獲取幫助
對項目做出貢獻
Git 分支
使用 Git 調(diào)試
Libgit2
Git 基礎(chǔ)
郵件
Git 內(nèi)部原理
維護項目
調(diào)試
向一個項目貢獻
總結(jié)
維護項目
命令行
分布式 Git
總結(jié)
JGit
儲藏與清理
管理
獲取與創(chuàng)建項目
總結(jié)
Rerere
Git 簡史
Smart HTTP
總結(jié)
Eclipse 中的 Git
總結(jié)
引用規(guī)格
傳輸協(xié)議
查看提交歷史
自定義 Git
底層命令
Git 守護進程
搜索
Git 基礎(chǔ)
Git 工具
關(guān)于版本控制
環(huán)境變量
其它環(huán)境中的 Git
高級合并
服務(wù)器上的 Git
第三方托管的選擇
遷移到 Git
遠(yuǎn)程倉庫的使用
GitLab
生成 SSH 公鑰
分支的新建與合并
配置服務(wù)器
交互式暫存
重寫歷史
重置揭密
Git 屬性
總結(jié)
初次運行 Git 前的配置
記錄每次更新到倉庫
總結(jié)
分支管理
打標(biāo)簽
檢查與比較

Git 引用

我們可以借助類似于 git log 1a410e 這樣的命令來瀏覽完整的提交歷史,但為了能遍歷那段歷史從而找到所有相關(guān)對象,你仍須記住 1a410e 是最后一個提交。 我們需要一個文件來保存 SHA-1 值,并給文件起一個簡單的名字,然后用這個名字指針來替代原始的 SHA-1 值。

在 Git 里,這樣的文件被稱為“引用(references,或縮寫為 refs)”;你可以在 .git/refs 目錄下找到這類含有 SHA-1 值的文件。 在目前的項目中,這個目錄沒有包含任何文件,但它包含了一個簡單的目錄結(jié)構(gòu):

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

若要創(chuàng)建一個新引用來幫助記憶最新提交所在的位置,從技術(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

我們不提倡直接編輯引用文件。 如果想更新某個引用,Git 提供了一個更加安全的命令 update-ref 來完成此事:

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

這基本就是 Git 分支的本質(zhì):一個指向某一系列提交之首的指針或引用。 若想在第二個提交上創(chuàng)建一個分支,可以這么做:

$ git update-ref refs/heads/test cac0ca

這個分支將只包含從第二個提交開始往前追溯的記錄:

$ git log --pretty=oneline test
cac0cab538b970a37ea1e769cbbde608743bc96d second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit

至此,我們的 Git 數(shù)據(jù)庫從概念上看起來像這樣:

http://wiki.jikexueyuan.com/project/pro-git-two/images/185.png" alt="" />

Figure 10-4. 包含分支引用的 Git 目錄對象。 當(dāng)運行類似于 git branch (branchname) 這樣的命令時,Git 實際上會運行 update-ref 命令,取得當(dāng)前所在分支最新提交對應(yīng)的 SHA-1 值,并將其加入你想要創(chuàng)建的任何新引用中。

HEAD 引用

現(xiàn)在的問題是,當(dāng)你執(zhí)行 git branch (branchname) 時,Git 如何知道最新提交的 SHA-1 值呢? 答案是 HEAD 文件。

HEAD 文件是一個符號引用(symbolic reference),指向目前所在的分支。 所謂符號引用,意味著它并不像普通引用那樣包含一個 SHA-1 值——它是一個指向其他引用的指針。 如果查看 HEAD 文件的內(nèi)容,一般而言我們看到的類似這樣:

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

如果執(zhí)行 git checkout test,Git 會像這樣更新 HEAD 文件:

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

當(dāng)我們執(zhí)行 git commit 時,該命令會創(chuàng)建一個提交對象,并用 HEAD 文件中那個引用所指向的 SHA-1 值設(shè)置其父提交字段。

你也可以手動編輯該文件,然而同樣存在一個更安全的命令來完成此事:symbolic-ref。 可以借助此命令來查看 HEAD 引用對應(yīng)的值:

$ git symbolic-ref HEAD
refs/heads/master

同樣可以設(shè)置 HEAD 引用的值:

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

不能把符號引用設(shè)置為一個不符合引用格式的值:

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

標(biāo)簽引用

前文我們剛討論過 Git 的三種主要對象類型,事實上還有第四種。 標(biāo)簽對象(tag object)非常類似于一個提交對象——它包含一個標(biāo)簽創(chuàng)建者信息、一個日期、一段注釋信息,以及一個指針。 主要的區(qū)別在于,標(biāo)簽對象通常指向一個提交對象,而不是一個樹對象。 它像是一個永不移動的分支引用——永遠(yuǎn)指向同一個提交對象,只不過給這個提交對象加上一個更友好的名字罷了。

正如 Git 基礎(chǔ) 中所討論的那樣,存在兩種類型的標(biāo)簽:附注標(biāo)簽和輕量標(biāo)簽。 可以像這樣創(chuàng)建一個輕量標(biāo)簽:

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

這就是輕量標(biāo)簽的全部內(nèi)容——一個固定的引用。 然而,一個附注標(biāo)簽則更復(fù)雜一些。 若要創(chuàng)建一個附注標(biāo)簽,Git 會創(chuàng)建一個標(biāo)簽對象,并記錄一個引用來指向該標(biāo)簽對象,而不是直接指向提交對象。 可以通過創(chuàng)建一個附注標(biāo)簽來驗證這個過程(-a 選項指定了要創(chuàng)建的是一個附注標(biāo)簽):

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

下面是上述過程所建標(biāo)簽對象的 SHA-1 值:

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

現(xiàn)在對該 SHA-1 值運行 cat-file 命令:

$ 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

我們注意到,object 條目指向我們打了標(biāo)簽的那個提交對象的 SHA-1 值。 另外要注意的是,標(biāo)簽對象并非必須指向某個提交對象;你可以對任意類型的 Git 對象打標(biāo)簽。 例如,在 Git 源碼中,項目維護者將他們的 GPG 公鑰添加為一個數(shù)據(jù)對象,然后對這個對象打了一個標(biāo)簽。 可以克隆一個 Git 版本庫,然后通過執(zhí)行下面的命令來在這個版本庫中查看上述公鑰:

$ git cat-file blob junio-gpg-pub

Linux 內(nèi)核版本庫同樣有一個不指向提交對象的標(biāo)簽對象——首個被創(chuàng)建的標(biāo)簽對象所指向的是最初被引入版本庫的那份內(nèi)核源碼所對應(yīng)的樹對象。

遠(yuǎn)程引用

我們將看到的第三種引用類型是遠(yuǎn)程引用(remote reference)。 如果你添加了一個遠(yuǎn)程版本庫并對其執(zhí)行過推送操作,Git 會記錄下最近一次推送操作時每一個分支所對應(yīng)的值,并保存在 refs/remotes 目錄下。 例如,你可以添加一個叫做 origin 的遠(yuǎn)程版本庫,然后把 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 文件,可以發(fā)現(xiàn) origin 遠(yuǎn)程版本庫的 master 分支所對應(yīng)的 SHA-1 值,就是最近一次與服務(wù)器通信時本地 master 分支所對應(yīng)的 SHA-1 值:

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

遠(yuǎn)程引用和分支(位于 refs/heads 目錄下的引用)之間最主要的區(qū)別在于,遠(yuǎn)程引用是只讀的。 雖然可以 git checkout 到某個遠(yuǎn)程引用,但是 Git 并不會將 HEAD 引用指向該遠(yuǎn)程引用。因此,你永遠(yuǎn)不能通過 commit 命令來更新遠(yuǎn)程引用。 Git 將這些遠(yuǎn)程引用作為記錄遠(yuǎn)程服務(wù)器上各分支最后已知位置狀態(tài)的書簽來管理。

上一篇:子模塊下一篇:Git 內(nèi)部原理