Git原理解析

前言

近幾年技術(shù)發(fā)展十分迅猛,讓部分同學(xué)養(yǎng)成了一種學(xué)習(xí)知識停留在表面,只會調(diào)用一些指令的習(xí)慣。我們時常有一種“我會用這個技術(shù)、這個框架”的錯覺,等到真正遇到問題,才發(fā)現(xiàn)事情沒有那么簡單。

而Git也是一個大部分人都知道如何去使用它,知道有哪些命令,卻只有少部分人知道具體原理的東西。了解一些底層的東西,可以更好的幫你理清思路,知道你真正在操作什么,不會迷失在Git大量的指令和參數(shù)上面。

Git是怎么儲存信息的

這里會用一個簡單的例子讓大家直觀感受一下git是怎么儲存信息的。

首先我們先創(chuàng)建兩個文件

$ git init
$ echo '111' > a.txt
$ echo '222' > b.txt
$ git add *.txt

Git會將整個數(shù)據(jù)庫儲存在.git/目錄下,如果你此時去查看.git/objects目錄,你會發(fā)現(xiàn)倉庫里面多了兩個object。

$ tree .git/objects
.git/objects
├── 58
│   └── c9bdf9d017fcd178dc8c073cbfcbb7ff240d6c
├── c2
│   └── 00906efd24ec5e783bee7f23b5d7c941b0c12c
├── info
└── pack

好奇的我們來看一下里面存的是什么東西

$ cat .git/objects/58/c9bdf9d017fcd178dc8c073cbfcbb7ff240d6c
xKOR0a044K%

怎么是一串亂碼?這是因為Git將信息壓縮成二進(jìn)制文件。但是不用擔(dān)心,因為Git也提供了一個能夠幫助你探索它的api git cat-file [-t] [-p], -t可以查看object的類型,-p可以查看object儲存的具體內(nèi)容。

$ git cat-file -t 58c9
blob
$ git cat-file -p 58c9
111

可以發(fā)現(xiàn)這個object是一個blob類型的節(jié)點(diǎn),他的內(nèi)容是111,也就是說這個object儲存著a.txt文件的內(nèi)容。

這里我們遇到第一種Git object,blob類型,它只儲存的是一個文件的內(nèi)容,不包括文件名等其他信息。然后將這些信息經(jīng)過SHA1哈希算法得到對應(yīng)的哈希值
58c9bdf9d017fcd178dc8c073cbfcbb7ff240d6c,作為這個object在Git倉庫中的唯一身份證。也就是說,我們此時的Git倉庫是這樣子的:

image.png

我們繼續(xù)探索,我們創(chuàng)建一個commit。

$ git commit -am '[+] init'
$ tree .git/objects
.git/objects
├── 0c
│   └── 96bfc59d0f02317d002ebbf8318f46c7e47ab2
├── 4c
│   └── aaa1a9ae0b274fba9e3675f9ef071616e5b209

我們會發(fā)現(xiàn)當(dāng)我們commit完成之后,Git倉庫里面多出來兩個object。同樣使用cat-file命令,我們看看它們分別是什么類型以及具體的內(nèi)容是什么。

$ git cat-file -t 4caaa1
tree
$ git cat-file -p 4caaa1
100644 blob 58c9bdf9d017fcd178dc8c0...     a.txt
100644 blob c200906efd24ec5e783bee7...    b.txt

這里我們遇到了第二種Git object類型——tree,它將當(dāng)前的目錄結(jié)構(gòu)打了一個快照。從它儲存的內(nèi)容來看可以發(fā)現(xiàn)它儲存了一個目錄結(jié)構(gòu)(類似于文件夾),以及每一個文件(或者子文件夾)的權(quán)限、類型、對應(yīng)的身份證(SHA1值)、以及文件名。
此時的Git倉庫是這樣的:


image.png
$ git cat-file -t 0c96bf
commit
$ git cat-file -p 0c96bf
tree 4caaa1a9ae0b274fba9e3675f9ef071616e5b209
author lzane 李澤帆  1573302343 +0800
committer lzane 李澤帆  1573302343 +0800
[+] init

接著我們發(fā)現(xiàn)了第三種Git object類型——commit,它儲存的是一個提交的信息,包括對應(yīng)目錄結(jié)構(gòu)的快照tree的哈希值,上一個提交的哈希值(這里由于是第一個提交,所以沒有父節(jié)點(diǎn)。在一個merge提交中還會出現(xiàn)多個父節(jié)點(diǎn)),提交的作者以及提交的具體時間,最后是該提交的信息。

此時我們?nèi)タ碐it倉庫是這樣的:

image.png

到這里我們就知道Git是怎么儲存一個提交的信息的了,那有同學(xué)就會問,我們平常接觸的分支信息儲存在哪里呢?

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

$ cat .git/refs/heads/master
0c96bfc59d0f02317d002ebbf8318f46c7e47ab2

在Git倉庫里面,HEAD、分支、普通的Tag可以簡單的理解成是一個指針,指向?qū)?yīng)commit的SHA1值。

image.png

其實還有第四種Git object,類型是tag,在添加含附注的tag(git tag -a)的時候會新建,這里不詳細(xì)介紹,有興趣的朋友按照上文中的方法可以深入探究。

至此我們知道了Git是什么儲存一個文件的內(nèi)容、目錄結(jié)構(gòu)、commit信息和分支的。其本質(zhì)上是一個key-value的數(shù)據(jù)庫加上默克爾樹形成的有向無環(huán)圖(DAG)。這里可以蹭一下區(qū)塊鏈的熱度,區(qū)塊鏈的數(shù)據(jù)結(jié)構(gòu)也使用了默克爾樹。

Git的三個分區(qū)

接下來我們來看一下Git的三個分區(qū)(工作目錄、Index 索引區(qū)域、Git倉庫),以及Git變更記錄是怎么形成的。了解這三個分區(qū)和Git鏈的內(nèi)部原理之后可以對Git的眾多指令有一個“可視化”的理解,不會再經(jīng)常搞混。

接著上面的例子,目前的倉庫狀態(tài)如下:

image.png

這里有三個區(qū)域,他們所儲存的信息分別是:

  • 工作目錄 ( working directory ):操作系統(tǒng)上的文件,所有代碼開發(fā)編輯都在這上面完成。
  • 索引( index or staging area ):可以理解為一個暫存區(qū)域,這里面的代碼會在下一次commit被提交到Git倉庫。
  • Git倉庫( git repository ):由Git object記錄著每一次提交的快照,以及鏈?zhǔn)浇Y(jié)構(gòu)記錄的提交變更歷史。

我們來看一下更新一個文件的內(nèi)容這個過程會發(fā)生什么事。

v2-23bbe72110019b5dd538d61a11874cd5_b.gif

運(yùn)行echo "333" > a.txt將a.txt的內(nèi)容從111修改成333,此時如上圖可以看到,此時索引區(qū)域和git倉庫沒有任何變化。

1.gif

運(yùn)行g(shù)it add a.txt將a.txt加入到索引區(qū)域,此時如上圖所示,git在倉庫里面新建了一個blob object,儲存了新的文件內(nèi)容。并且更新了索引將a.txt指向了新建的blob object。

2.gif

運(yùn)行g(shù)it commit -m 'update'提交這次修改。如上圖所示

Git首先根據(jù)當(dāng)前的索引生產(chǎn)一個tree object,充當(dāng)新提交的一個快照。
創(chuàng)建一個新的commit object,將這次commit的信息儲存起來,并且parent指向上一個commit,組成一條鏈記錄變更歷史。
將master分支的指針移到新的commit結(jié)點(diǎn)。
至此我們知道了Git的三個分區(qū)分別是什么以及他們的作用,以及歷史鏈?zhǔn)窃趺幢唤⑵饋淼??;旧螱it的大部分指令就是在操作這三個分區(qū)以及這條鏈。可以嘗試的思考一下git的各種命令,試一下你能不能夠在上圖將它們“可視化”出來,這個很重要,建議嘗試一下。

(轉(zhuǎn)載自公眾號:騰訊技術(shù)工程)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容