您好,登錄后才能下訂單哦!
這篇文章主要介紹“Git的原理是什么”,在日常操作中,相信很多人在Git的原理是什么問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Git的原理是什么”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
說起Git,相信大家都很熟悉了,畢竟作為程序猿,每天的業(yè)余時間除了吃飯睡覺就是逛一下全世界最大的開(tong)源(xing)代(jiao)碼(you)網站GitHub了。在那里Git是每個人所要具備的最基本的技能。今天我們不聊Git的基本應用,來聊一聊Git的原理。<!-- more -->
Git給自己的定義是一套內存尋址文件系統(tǒng),當你在一個目錄下執(zhí)行git init命令時,會生成一個.git目錄,它的目錄結構是這樣的:
.git/
├── branches
├── config
├── description
├── HEAD
├── hooks
│ ├── applypatch-msg.sample
│ ├── commit-msg.sample
│ ├── post-update.sample
│ ├── pre-applypatch.sample
│ ├── pre-commit.sample
│ ├── prepare-commit-msg.sample
│ ├── pre-push.sample
│ ├── pre-rebase.sample
│ └── update.sample
├── info
│ └── exclude
├── objects
│ ├── info
│ └── pack
└── refs
├── heads
└── tags
其中branches目錄已經不再使用,description文件僅供GitWeb程序使用,config文件保存了項目的配置。
需要我們重點關注的是HEAD和index文件以及objects和refs目錄。其中index中保存了暫存區(qū)的一些信息,這里不做過多介紹。
這個目錄是用來存儲Git對象的(包括tree對象、commit對象和blob對象),對于一個初始的Git倉庫,objects目錄下只有info和pack兩個子目錄,并沒有常規(guī)文件。隨著項目的進行,我們創(chuàng)建的文件,以及一些操作記錄,都會作為Git對象被存儲在這個目錄下。
在該目錄下,所有對象都會生成一個文件,并且有對應的SHA-1校驗和,Git會創(chuàng)建以校驗和前兩位為名稱的子目錄,并以剩下的38位為名稱來保存文件。
接下來讓我們一起看一下當我們進行一次提交時,Git具體做了哪些事情。
$ echo 'test content'>test.txt
$ git add .
執(zhí)行上述命令后,objects目錄結構如下:
.git/objects/
├── d6
│ └── 70460b4b4aece5915caf5c68d12f560a9fe3e4
├── info
└── pack
這里多了一個文件夾,如上面所述,這個就是Git為我們創(chuàng)建的一個對象,我們可以使用底層命令來看一下這個對象的類型以及它存儲的是什么。
$ git cat-file -t d670460b4b4aece5915caf5c68d12f560a9fe3e4
blob
$ git cat-file -p d670460b4b4aece5915caf5c68d12f560a9fe3e4
test content
可以看到,這是一個blob對象,存儲內容就是我們剛剛創(chuàng)建的文件的內容。接下來繼續(xù)執(zhí)行提交操作。
$ git commit -m 'test message'
[master (root-commit) 2b00dca] test message
1 file changed, 1 insertion(+)
create mode 100644 test.txt
$ tree .git/objects/
.git/objects/
├── 2b
│ └── 00dcae50af70bb5722033b3fe75281206c74da
├── 80
│ └── 865964295ae2f11d27383e5f9c0b58a8ef21da
├── d6
│ └── 70460b4b4aece5915caf5c68d12f560a9fe3e4
├── info
└── pack
此時objects目錄下又多了兩個對象。再用cat-file命令來查看一下這兩個文件。
$ git cat-file -t 2b00dcae50af70bb5722033b3fe75281206c74da
commit
$ git cat-file -p 2b00dcae50af70bb5722033b3fe75281206c74da
tree 80865964295ae2f11d27383e5f9c0b58a8ef21da
author jackeyzhe <jackeyzhe59@163.com> 1534670725 +0800
committer jackeyzhe <jackeyzhe59@163.com> 1534670725 +0800
test message
$ git cat-file -t 80865964295ae2f11d27383e5f9c0b58a8ef21da
tree
$ git cat-file -p 80865964295ae2f11d27383e5f9c0b58a8ef21da
100644 blob d670460b4b4aece5915caf5c68d12f560a9fe3e4 test.txt
可以看到一個是commit對象,一個是tree對象。commit對象通常包括4部分內容:
工作目錄快照的Hash,即tree的值
提交的說明信息
提交者的信息
父提交的Hash值
由于我是第一次提交,所以這里沒有父提交的Hash值。
tree對象可以理解為UNIX文件系統(tǒng)中的目錄,保存了工作目錄的tree對象和blob對象的信息。接下來我們再來看一下Git是如何進行版本控制的。
echo 'version1'>version.txt
$ git add .
$ git commit -m 'first version'
[master 702193d] first version
1 file changed, 1 insertion(+)
create mode 100644 version.txt
$ echo 'version2'>version.txt
$ git add .
$ git commit -m 'second version'
[master 5333a75] second version
1 file changed, 1 insertion(+), 1 deletion(-)
$ tree .git/objects/
.git/objects/
├── 1f
│ └── a5aab2a3cf025d06479b9eab9a7f66f60dbfc1
├── 29
│ └── 13bfa5cf9fb6f893bec60ac11d86129d56fcbe
├── 2b
│ └── 00dcae50af70bb5722033b3fe75281206c74da
├── 53
│ └── 33a759c4bdcdc6095b4caac19743d9445ca516
├── 5b
│ └── dcfc19f119febc749eef9a9551bc335cb965e2
├── 70
│ └── 2193d62ffd797155e4e21eede20897890da12a
├── 80
│ └── 865964295ae2f11d27383e5f9c0b58a8ef21da
├── d6
│ └── 70460b4b4aece5915caf5c68d12f560a9fe3e4
├── df
│ └── 7af2c382e49245443687973ceb711b2b74cb4a
├── info
└── pack
$ git cat-file -p 1fa5aab2a3cf025d06479b9eab9a7f66f60dbfc1
100644 blob d670460b4b4aece5915caf5c68d12f560a9fe3e4 test.txt
100644 blob 5bdcfc19f119febc749eef9a9551bc335cb965e2 version.txt
$ git cat-file -p 2913bfa5cf9fb6f893bec60ac11d86129d56fcbe
100644 blob d670460b4b4aece5915caf5c68d12f560a9fe3e4 test.txt
100644 blob df7af2c382e49245443687973ceb711b2b74cb4a version.txt
Git將沒有改變的文件的Hash值直接存入tree對象,對于有修改的文件,則會生成一個新的對象,將新的對象存入tree對象。我們再來看一下commit對象的信息。
$ git cat-file -p 5333a759c4bdcdc6095b4caac19743d9445ca516
tree 2913bfa5cf9fb6f893bec60ac11d86129d56fcbe
parent 702193d62ffd797155e4e21eede20897890da12a
author jackeyzhe <jackeyzhe59@163.com> 1534672270 +0800
committer jackeyzhe <jackeyzhe59@163.com> 1534672270 +0800
second version
$ git cat-file -p 702193d62ffd797155e4e21eede20897890da12a
tree 1fa5aab2a3cf025d06479b9eab9a7f66f60dbfc1
parent 2b00dcae50af70bb5722033b3fe75281206c74da
author jackeyzhe <jackeyzhe59@163.com> 1534672248 +0800
committer jackeyzhe <jackeyzhe59@163.com> 1534672248 +0800
first version
此時的commit對象已經有parent信息了,這樣我們就可以順著parent一步步往回進行版本回退了。不過這樣是比較麻煩的,我們一般習慣用的是git log查看提交記錄。
在介紹refs目錄之前,我們還是先來看一下該目錄結構
$ tree .git/refs/
.git/refs/
├── heads
│ └── master
└── tags
2 directories, 1 file
$ cat .git/refs/heads/master
5333a759c4bdcdc6095b4caac19743d9445ca516
在一個剛剛被初始化的Git倉庫中,refs目錄下只有heads和tags兩個子目錄,由于我們剛剛有過提交操作,所以git為我們自動生成了一個名為master的引用。master的內容是最后一次提交對象的Hash值??吹竭@里大家一定在想,如果我們對每次提交都創(chuàng)建一個這樣的引用,不就不需要記住每次提交的Hash值了,只要看看引用的值,復制過來就可以退回到對應版本了。沒錯,這樣是可以方便的退回,但是這樣做的意義不大,因為我們并不需要頻繁的退回,特別是比較古老的版本,退回的概率更是趨近于0。Git用這個引用做了更有意義的事,那就是分支。
當我新建一個分支時,git就會在.git/refs/heads目錄下新建一個文件。當然新建的引用還是指向當前工作目錄的最后一次提交,一般情況下我們不會主動去修改這些引用文件,不過如果一定要修改,Git為我們提供了一個update-ref命令。可以改變引用的值,使其指向不同的commit對象。
tags目錄下的文件存儲的是標簽對應的commit,當為某次提交打上一個tag時,tags目錄下就會被創(chuàng)建出一個命名為tag名的文件,值是此次提交的Hash值。
新建分支的時候,Git是怎么知道我們當前是在哪個分支的,Git又是如何實現分支切換的呢?答案就在HEAD這個文件中。
$ cat .git/HEAD
ref: refs/heads/master
$ git checkout test
Switched to branch 'test'
$ cat .git/HEAD
ref: refs/heads/test
很明顯,HEAD文件存儲的就是我們當前分支的引用,當我們切換分支后再次進行提交操作時,Git就會讀取HEAD對應引用的值,作為此次commit的parent。我們也可以通過symbolic-ref命令手動設置HEAD的值,但是不能設置refs以外的形式。
到這里我們在文章開頭所說的重點關注的目錄和文件都介紹完畢了。但是作為一個文件系統(tǒng),還存在一個問題,那就是空間。前文介紹過,當文件修改后進行提交時,Git會創(chuàng)建一份新的快照。這樣長久下去,必定會占用很大的存儲空間。而比較古老的版本的價值已經不大,所以要想辦法清理出足夠的空間供用戶使用。
好消息是,Git擁有自己的gc(垃圾回收)方法。當倉庫中有太多松散對象時,Git會調用git gc命令(當然我們也可以手動調用這個命令),將這些對象進行打包。打包后會出現兩個新文件:一個idx索引文件和一個pack文件。索引文件包含了packfile的偏移信息,可以快速定位到文件。打包后,每個文件最新的版本的對象存的是完整的文件內容。而之前的版本只保存差異。這樣就達到了壓縮空間的目的。
到此,關于“Git的原理是什么”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續(xù)學習更多相關知識,請繼續(xù)關注億速云網站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。