Git 內(nèi)部原理之 Git 引用

這篇文章本應(yīng)該在6月份就完成,拖了4個(gè)月之后拆祈,終于鼓起勇氣撿起來(lái)恨闪,實(shí)在慚愧。堅(jiān)持寫(xiě)文章就像長(zhǎng)跑放坏,途中跑起來(lái)基本是靠慣性咙咽,如果停下來(lái)再起跑就很累很困難。

閑話(huà)不多說(shuō)淤年,本篇繼續(xù)承接前文講一講Git內(nèi)部原理钧敞,本篇的主題是Git引用的原理蜡豹。

首先來(lái)搞清楚什么是Git引用,前文講了Git提交對(duì)象的哈希犁享、存儲(chǔ)原理余素,理論上我們只要知道該對(duì)象的hash值,就能往前推出整個(gè)提交歷史炊昆,例如:

$ git log --pretty=oneline 3ac728ac62f0a7b5ac201fd3ed1f69165df8be31

3ac728ac62f0a7b5ac201fd3ed1f69165df8be31 third commit

d4d2c6cffb408d978cb6f1eb6cfc70e977378a5c second commit

db1d6f137952f2b24e3c85724ebd7528587a067a first commit

現(xiàn)在問(wèn)題來(lái)了桨吊,提交對(duì)象的這40位hash值不好記憶,Git引用相當(dāng)于給40位hash值取一個(gè)別名凤巨,便于識(shí)別和讀取视乐。Git引用對(duì)象都存儲(chǔ)在.git/refs目錄下,該目錄下有3個(gè)子文件夾heads敢茁、tags和remotes佑淀,分別對(duì)應(yīng)于HEAD引用、標(biāo)簽引用和遠(yuǎn)程引用彰檬,下面分別講一講每種引用的原理伸刃。

HEAD引用

HEAD引用是用來(lái)指向每個(gè)分支的最后一次提交對(duì)象,這樣切換到一個(gè)分支之后逢倍,才能知道分支的“尾巴”在哪里捧颅。HEAD引用存儲(chǔ)在.git/refs/heads目錄下,有多少個(gè)分支较雕,就有相應(yīng)的同名HEAD引用對(duì)象碉哑。例如代碼庫(kù)里面有master和test兩個(gè)分支,那么.git/refs/heads目錄下就存在master和test兩個(gè)文件亮蒋,分別記錄了分支的最后一次提交扣典。

HEAD引用的內(nèi)容就是提交對(duì)象的hash值,理論上我們可以手動(dòng)地構(gòu)造一個(gè)HEAD引用:

$ echo "3ac728ac62f0a7b5ac201fd3ed1f69165df8be31" > .git/refs/heads/master

Git提供了一個(gè)專(zhuān)有命令update-ref慎玖,用來(lái)查看和修改Git引用對(duì)象贮尖,當(dāng)然也包括HEAD引用:

$ git update-ref refs/heads/master 3ac728ac62f0a7b5ac201fd3ed1f69165df8be31

$ git update-ref refs/heads/master

3ac728ac62f0a7b5ac201fd3ed1f69165df8be31

上面的命令我們將master分支的HEAD指向了3ac728ac62f0a7b5ac201fd3ed1f69165df8be31,現(xiàn)在用git log查看下master的提交歷史趁怔,可以發(fā)現(xiàn)最后一次提交就是所更新的hash值:

$ git log --pretty=oneline master

3ac728ac62f0a7b5ac201fd3ed1f69165df8be31 (HEAD -> master) third commit

d4d2c6cffb408d978cb6f1eb6cfc70e977378a5c second commit

db1d6f137952f2b24e3c85724ebd7528587a067a first commit

同理远舅,可以使用同樣的方法更新test分支的HEAD:

$ git update-ref refs/heads/test d4d2c6cffb408d978cb6f1eb6cfc70e977378a5c

$ git log --pretty=oneline test

d4d2c6cffb408d978cb6f1eb6cfc70e977378a5c (test) second commit

db1d6f137952f2b24e3c85724ebd7528587a067a first commit

.git/refs/heads目錄下存儲(chǔ)了每個(gè)分支的HEAD,那怎么知道代碼庫(kù)當(dāng)前處于哪個(gè)分支呢痕钢?這就需要一個(gè)代碼庫(kù)級(jí)別的HEAD引用图柏。.git/HEAD這個(gè)文件就是整個(gè)代碼庫(kù)級(jí)別的HEAD引用。我們先查看一下.git/HEAD文件的內(nèi)容:

$ cat .git/HEAD

ref: refs/heads/master

我們發(fā)現(xiàn).git/HEAD文件的內(nèi)容不是40位hash值任连,而像是指向.git/refs/heads/master蚤吹。嘗試切換到test:

$ git checkout test

$ cat .git/HEAD

ref: refs/heads/test

切換分支后,.git/HEAD文件的內(nèi)容也跟著指向.git/refs/heads/test。.git/HEAD也是HEAD引用對(duì)象裁着,與一般引用不同的是繁涂,它是“符號(hào)引用”。符號(hào)引用類(lèi)似于文件的快捷方式二驰,鏈接到要引用的對(duì)象上扔罪。

Git提供專(zhuān)門(mén)的命令git symbolic-ref,用來(lái)查看和更新符號(hào)引用:

$ git symbolic-ref HEAD refs/heads/master

$ git symbolic-ref HEAD refs/heads/test

至此,我們分析了兩種HEAD引用,一種是分支級(jí)別的HEAD引用婴梧,用來(lái)記錄各分支的最后一次提交,存儲(chǔ)在.git/refs/heads目錄下全肮,使用git update-ref來(lái)維護(hù);一種是代碼庫(kù)級(jí)別的HEAD引用棘捣,用來(lái)記錄代碼庫(kù)所處的分支辜腺,存儲(chǔ)在.git/HEAD文件,使用git symbolic-ref來(lái)維護(hù)乍恐。

標(biāo)簽引用

標(biāo)簽引用评疗,顧名思義就是給Git對(duì)象打標(biāo)簽,便于記憶茵烈。例如百匆,我們可以將某個(gè)提交對(duì)象打v1.0標(biāo)簽,表示是1.0版本瞧毙。標(biāo)簽引用都存儲(chǔ)在.git/refs/tags里面。

標(biāo)簽引用和HEAD引用本質(zhì)是Git引用對(duì)象寄症,同樣使用git update-ref來(lái)查看和修改:

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

$ cat .git/refs/tags/v1.0

d4d2c6cffb408d978cb6f1eb6cfc70e977378a5c

還有一種標(biāo)簽引用稱(chēng)為“附注引用”宙彪,可以為標(biāo)簽添加說(shuō)明信息。上面的標(biāo)簽引用打了一個(gè)v1.0的標(biāo)簽表示發(fā)布1.0版本有巧,有時(shí)候發(fā)布軟件的時(shí)候除了版本號(hào)信息释漆,還要寫(xiě)更新說(shuō)明。附注引用就是用來(lái)實(shí)現(xiàn)打標(biāo)簽的同時(shí)篮迎,也可以附帶說(shuō)明信息男图。

附注引用是怎么實(shí)現(xiàn)的呢?與常規(guī)標(biāo)簽引用不同的是甜橱,它不直接指向提交對(duì)象逊笆,而是新建一個(gè)Git對(duì)象存儲(chǔ)到.git/objects中,用來(lái)記錄附注信息岂傲,然后附注標(biāo)簽指向這個(gè)Git對(duì)象难裆。

使用git tag建立一個(gè)附注標(biāo)簽:

$ git tag -a v1.1 3ac728ac62f0a7b5ac201fd3ed1f69165df8be31 -m "test tag"

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

8be4d8e4e8e80711dd7bae304ccfa63b35a6eb8c

使用git cat-file來(lái)查看附注標(biāo)簽所指向的Git對(duì)象:

$ git cat-file -p 8be4d8e4e8e80711dd7bae304ccfa63b35a6eb8c

object 3ac728ac62f0a7b5ac201fd3ed1f69165df8be31

type commit

tag v1.1

tagger jingsam <jing-sam@qq.com> 1529481368 +0800


test tag

可以看到,上面的Git對(duì)象存儲(chǔ)了我們填寫(xiě)的附注信息。

總之乃戈,普通的標(biāo)簽引用和附注引用同樣都是存儲(chǔ)的是40位hash值褂痰,指向一個(gè)Git對(duì)象,所不同的是普通的標(biāo)簽引用是直接指向提交對(duì)象症虑,而附注標(biāo)簽是指向一個(gè)附注對(duì)象缩歪,附注對(duì)象再指向具體的提交對(duì)象。

另外谍憔,本質(zhì)上標(biāo)簽引用并不是只可以指向提交對(duì)象匪蝙,實(shí)際上可以指向任何Git對(duì)象,即可以給任何Git對(duì)象打標(biāo)簽韵卤。

遠(yuǎn)程引用

遠(yuǎn)程引用骗污,類(lèi)似于.git/refs/heads中存儲(chǔ)的本地倉(cāng)庫(kù)各分支的最后一次提交,在.git/refs/remotes是用來(lái)記錄多個(gè)遠(yuǎn)程倉(cāng)庫(kù)各分支的最后一次提交沈条。

我們可以使用git remote來(lái)管理遠(yuǎn)程分支:

$ git remote add origin git@github.com:jingsam/git-test.git

上面添加了一個(gè)origin遠(yuǎn)程分支需忿,接下來(lái)我們把本地倉(cāng)庫(kù)的master推送到遠(yuǎn)程倉(cāng)庫(kù)上:

$ git push origin master

Counting objects: 9, done.

Delta compression using up to 4 threads.

Compressing objects: 100% (5/5), done.

Writing objects: 100% (9/9), 720 bytes | 360.00 KiB/s, done.

Total 9 (delta 0), reused 0 (delta 0)

To github.com:jingsam/git-test.git

?* [new branch]? ? ? master -> master

這時(shí)候在.git/refs/remotes中的遠(yuǎn)程引用就會(huì)更新:

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

3ac728ac62f0a7b5ac201fd3ed1f69165df8be31

和本地倉(cāng)庫(kù)的master比較一下,發(fā)現(xiàn)是一模一樣的蜡歹,表示遠(yuǎn)程分支和本地分支是同步的:

$ cat .git/refs/heads/master

3ac728ac62f0a7b5ac201fd3ed1f69165df8be31

由于遠(yuǎn)程引用也是Git引用對(duì)象屋厘,所以理論上也可以使用git update-ref來(lái)手動(dòng)維護(hù)。但是月而,我們需要先把代碼與遠(yuǎn)程倉(cāng)庫(kù)進(jìn)行同步汗洒,在遠(yuǎn)程倉(cāng)庫(kù)中找到對(duì)應(yīng)分支的HEAD,然后使用git update-ref進(jìn)行更新父款,過(guò)程比較麻煩溢谤。而我們?cè)趫?zhí)行g(shù)it pull或git push這樣的高層命令的時(shí)候,遠(yuǎn)程引用會(huì)自動(dòng)更新憨攒。

總結(jié)

到這里世杀,三種Git引用都已分析完畢「渭總的來(lái)說(shuō)瞻坝,三種Git引用都統(tǒng)一存儲(chǔ)到.git/refs目錄下,Git引用中的內(nèi)容都是40位的hash值杏瞻,指向某個(gè)Git對(duì)象所刀,這個(gè)對(duì)象可以是任意的Git對(duì)象,可以是數(shù)據(jù)對(duì)象捞挥、樹(shù)對(duì)象浮创、提交對(duì)象。三種Git引用都可以使用git update-ref來(lái)手動(dòng)維護(hù)砌函。

三種Git引用對(duì)象所不同的是蒸矛,分別存儲(chǔ)于.git/refs/heads、.git/refs/tags、.git/refs/remotes,存儲(chǔ)的文件夾不同雏掠,賦予了引用對(duì)象不同的功能斩祭。HEAD引用用來(lái)記錄本地分支的最后一次提交,標(biāo)簽引用用來(lái)給任意Git對(duì)象打標(biāo)簽乡话,遠(yuǎn)程引用正式用來(lái)記錄遠(yuǎn)程分支的最后一次提交摧玫。

擴(kuò)展閱讀

話(huà)說(shuō) SVN 與 GIT 的區(qū)別

Git 內(nèi)部原理之 Git 對(duì)象哈希

Git常用命令速查表(收藏大全)

來(lái)源:http://jingsam.github.io/2018/10/12/git-reference.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市绑青,隨后出現(xiàn)的幾起案子诬像,更是在濱河造成了極大的恐慌,老刑警劉巖闸婴,帶你破解...
    沈念sama閱讀 218,607評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件坏挠,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡邪乍,警方通過(guò)查閱死者的電腦和手機(jī)降狠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)庇楞,“玉大人榜配,你說(shuō)我怎么就攤上這事÷郎危” “怎么了蛋褥?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,960評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)睛驳。 經(jīng)常有香客問(wèn)我烙心,道長(zhǎng),這世上最難降的妖魔是什么乏沸? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,750評(píng)論 1 294
  • 正文 為了忘掉前任淫茵,我火速辦了婚禮,結(jié)果婚禮上屎蜓,老公的妹妹穿的比我還像新娘痘昌。我一直安慰自己钥勋,他們只是感情好炬转,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,764評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著算灸,像睡著了一般扼劈。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上菲驴,一...
    開(kāi)封第一講書(shū)人閱讀 51,604評(píng)論 1 305
  • 那天荐吵,我揣著相機(jī)與錄音,去河邊找鬼。 笑死先煎,一個(gè)胖子當(dāng)著我的面吹牛贼涩,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播薯蝎,決...
    沈念sama閱讀 40,347評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼遥倦,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了占锯?” 一聲冷哼從身側(cè)響起袒哥,我...
    開(kāi)封第一講書(shū)人閱讀 39,253評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎消略,沒(méi)想到半個(gè)月后堡称,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,702評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡艺演,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,893評(píng)論 3 336
  • 正文 我和宋清朗相戀三年却紧,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片钞艇。...
    茶點(diǎn)故事閱讀 40,015評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡啄寡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出哩照,到底是詐尸還是另有隱情挺物,我是刑警寧澤,帶...
    沈念sama閱讀 35,734評(píng)論 5 346
  • 正文 年R本政府宣布飘弧,位于F島的核電站识藤,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏次伶。R本人自食惡果不足惜痴昧,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,352評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望冠王。 院中可真熱鬧赶撰,春花似錦、人聲如沸柱彻。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,934評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)哟楷。三九已至瘤载,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間卖擅,已是汗流浹背鸣奔。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,052評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工墨技, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人挎狸。 一個(gè)月前我還...
    沈念sama閱讀 48,216評(píng)論 3 371
  • 正文 我出身青樓扣汪,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親锨匆。 傳聞我的和親對(duì)象是個(gè)殘疾皇子私痹,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,969評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • Git 基礎(chǔ) 基本原理 客戶(hù)端并不是只提取最新版本的文件快照,而是把代碼倉(cāng)庫(kù)完整的鏡像下來(lái)统刮。這樣一來(lái)紊遵,任何一處協(xié)同...
    __silhouette閱讀 15,887評(píng)論 5 147
  • Git 命令行學(xué)習(xí)筆記 Git 基礎(chǔ) 基本原理 客戶(hù)端并不是只提取最新版本的文件快照,而是把代碼倉(cāng)庫(kù)完整的鏡像下來(lái)...
    sunnyghx閱讀 3,921評(píng)論 0 11
  • 零秒思考 閱讀侥蒙,寫(xiě)作是培養(yǎng)邏輯思維能力的正道暗膜,但是要想短時(shí)間有一定的收獲,需要一些相當(dāng)有技巧的辦法鞭衩,最近看了一本叫...
    Gunther閱讀 368評(píng)論 1 5
  • 位運(yùn)算與位枚舉
    翻這個(gè)墻閱讀 270評(píng)論 0 0
  • 忍住学搜,挺住论衍! 做兹鹋濉! 無(wú)論再苦坯台,都不哭炬丸! 度心,心度蜒蕾! 撐壮砭妗! 血淚巰祝咪啡,成模糊首启! 短處,長(zhǎng)處撤摸! 交出毅桃! 銘記來(lái)路...
    淺秋遺夢(mèng)閱讀 529評(píng)論 0 0