• 展開
    湖北國聯(lián)計(jì)算機(jī)科技有限公司
  • 首頁HOME
  • 公司簡介INTRODUCTION
  • 安全防御DEFENSE
  • 軟件開發(fā)SOFTWARE
  • 物聯(lián)網(wǎng)IOT
  • 運(yùn)行維護(hù)SRE
  • 成功案例CASE
  • 聯(lián)系我們CONTACT
  • Software Event |業(yè)界動態(tài)

    這才是真正的Git——Git內(nèi)部原理揭秘!
    來源:湖北國菱計(jì)算機(jī)科技有限公司-荊州網(wǎng)站建設(shè)-荊州軟件開發(fā)-政府網(wǎng)站建設(shè)公司 時(shí)間:2020-09-17


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

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

    Git是怎么儲存信息的

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

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

    1. $ git init

    2. $ echo '111'> a.txt

    3. $ echo '222'> b.txt

    4. $ git add *.txt

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

    1. $ tree .git/objects

    2. .git/objects

    3. ├──58

    4. │└── c9bdf9d017fcd178dc8c073cbfcbb7ff240d6c

    5. ├── c2

    6. │└──00906efd24ec5e783bee7f23b5d7c941b0c12c

    7. ├── info

    8. └── pack

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

    1. $ cat .git/objects/58/c9bdf9d017fcd178dc8c073cbfcbb7ff240d6c

    2. xKOR0a044K%

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

    1. $ git cat-file -t 58c9

    2. blob

    3. $ git cat-file -p 58c9

    4. 111

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

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

    也就是說,我們此時(shí)的Git倉庫是這樣子的:

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

    1. $ git commit -am '[+] init'

    2. $ tree .git/objects

    3. .git/objects

    4. ├──0c

    5. │└──96bfc59d0f02317d002ebbf8318f46c7e47ab2

    6. ├──4c

    7. │└── aaa1a9ae0b274fba9e3675f9ef071616e5b209

    8. ...

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

    1. $ git cat-file -t 4caaa1

    2. tree

    3. $ git cat-file -p 4caaa1

    4. 100644 blob 58c9bdf9d017fcd178dc8c0...     a.txt

    5. 100644 blob c200906efd24ec5e783bee7...    b.txt

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

    此時(shí)的Git倉庫是這樣的:

    1. $ git cat-file -t 0c96bf

    2. commit

    3. $ git cat-file -p 0c96bf

    4. tree 4caaa1a9ae0b274fba9e3675f9ef071616e5b209

    5. author lzane 李澤帆1573302343+0800

    6. committer lzane 李澤帆1573302343+0800

    7. [+] init

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

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

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

    1. $ cat .git/HEAD

    2. ref: refs/heads/master


    3. $ cat .git/refs/heads/master

    4. 0c96bfc59d0f02317d002ebbf8318f46c7e47ab2

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

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

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

    Git的三個(gè)分區(qū)

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

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

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

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



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



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



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

    至此我們知道了Git的三個(gè)分區(qū)分別是什么以及他們的作用,以及歷史鏈?zhǔn)窃趺幢唤⑵饋淼??;旧螱it的大部分指令就是在操作這三個(gè)分區(qū)以及這條鏈??梢試L試的思考一下git的各種命令,試一下你能不能夠在上圖將它們“可視化”出來,這個(gè)很重要,建議嘗試一下。

    如果不能很好的將日常使用的指令“可視化”出來,推薦閱讀 圖解Git

    一些有趣的問題

    有興趣的同學(xué)可以繼續(xù)閱讀,這部分不是文章的主要內(nèi)容

    問題1:為什么要把文件的權(quán)限和文件名儲存在tree object里面而不是blob object呢?

    想象一下修改一個(gè)文件的命名。

    如果將文件名保存在blob里面,那么Git只能多復(fù)制一份原始內(nèi)容形成一個(gè)新的blob object。而Git的實(shí)現(xiàn)方法只需要?jiǎng)?chuàng)建一個(gè)新的tree object將對應(yīng)的文件名更改成新的即可,原本的blob object可以復(fù)用,節(jié)約了空間。

    問題2:每次commit,Git儲存的是全新的文件快照還是儲存文件的變更部分?

    由上面的例子我們可以看到,Git儲存的是全新的文件快照,而不是文件的變更記錄。也就是說,就算你只是在文件中添加一行,Git也會新建一個(gè)全新的blob object。那這樣子是不是很浪費(fèi)空間呢?

    這其實(shí)是Git在空間和時(shí)間上的一個(gè)取舍,思考一下你要checkout一個(gè)commit,或?qū)Ρ葍蓚€(gè)commit之間的差異。如果Git儲存的是問卷的變更部分,那么為了拿到一個(gè)commit的內(nèi)容,Git都只能從第一個(gè)commit開始,然后一直計(jì)算變更,直到目標(biāo)commit,這會花費(fèi)很長時(shí)間。而相反,Git采用的儲存全新文件快照的方法能使這個(gè)操作變得很快,直接從快照里面拿取內(nèi)容就行了。

    當(dāng)然,在涉及網(wǎng)絡(luò)傳輸或者Git倉庫真的體積很大的時(shí)候,Git會有垃圾回收機(jī)制gc,不僅會清除無用的object,還會把已有的相似object打包壓縮。

    問題3:Git怎么保證歷史記錄不可篡改?

    通過SHA1哈希算法和哈系樹來保證。假設(shè)你偷偷修改了歷史變更記錄上一個(gè)文件的內(nèi)容,那么這個(gè)問卷的blob object的SHA1哈希值就變了,與之相關(guān)的tree object的SHA1也需要改變,commit的SHA1也要變,這個(gè)commit之后的所有commit SHA1值也要跟著改變。又由于Git是分布式系統(tǒng),即所有人都有一份完整歷史的Git倉庫,所以所有人都能很輕松的發(fā)現(xiàn)存在問題。


    荊州地區(qū)政府網(wǎng)站建設(shè) 解決方案 專業(yè)團(tuán)隊(duì) 騰訊第三方平臺 地址:湖北省荊州市沙市區(qū)荊沙大道楚天都市佳園一期C區(qū)29棟112       地址:湖北省松滋市新江口街道才知文化廣場1幢1146-1151室     郵編:434200 聯(lián)系電話:0716-6666211     網(wǎng)站編輯部郵箱:business@gl-ns.com 鄂公網(wǎng)安備 42100202000212號 備案號:鄂ICP備2021015094號-1     企業(yè)名稱:湖北國菱計(jì)算機(jī)科技有限公司
    亚洲色精品Aⅴ一区区三区,少妇中文高清av无码,久久精品这里只有精品99品,无码乱人伦中文视频 99福利资源久久福利资源 国产精品白浆无码流出嗯啊豆