git原理探索

概念

GIT是什麼?簡單來說它就是管理和維護代碼的軟件,它是由linux之父Linus大神花了兩個星期開發的,最初是爲了給linux內核開發社區提供源碼管理,其實在GIT之前linux開源社區的代碼管理都是通過bitkeeper版本控制系統來管理的(bitkeeper是由BitMover公司開發,它是一家商業公司),直到2005年,BitMover公司停止了跟linux開源社區的合作關係,也就是因爲這個原因,git誕生了。
 
GITHUB、GITLAB、GITEE是什麼?個人理解啊,首先它們是一個託管平臺(一個共享倉庫),其次它們也是一個跟我們本地一樣的git版本庫,這個怎麼理解?Linus設計初衷就是要做一個分佈式版本控制系統,並且去中心化,也就是每個安裝GIT的電腦都是一個完整的版本庫,可以相互推送。那麼這樣就會存在一個問題,畢竟我們的PC電腦不是服務器,所以GITHUB、GITEE、GITLAB誕生了,當然這些託管平臺針對GIT管理只能說是它們一小部分功能,它們主要還是以論壇社交的方式在服務。
 
GIT工作流程,GIT工作流程三大核心,工作區、暫存區(索引區)、版本庫,看圖。
 
上圖是我自己畫的一張簡圖,大概反映了GIT工作流程以及涉及到的4種文件狀態,有兩個地方需要注意一下,圖裏面的漸變箭頭和最下面那個箭頭,1. 漸變箭頭表示該文件已經添加到了暫存區,但是又被修改了,導致了工作區和暫存區狀態不一致,2. 最下面那個箭頭表示,文件從unmodified狀態又回到了untracked狀態,一般情況下不會有這兩種狀態的變更,極端情況下,比如撤銷回退操作,這些操作後面都會說,概念就介紹到這吧。
 
準備工作

我這邊準備的GIT環境比較簡單,三個本地倉庫文件夾,也就是三個本地文件夾,一個模擬遠程倉庫,兩個模擬本地倉庫,看圖。
 
 
server模擬共享倉庫,並且初始化一個Test.Service的倉庫,user01、user02模擬兩個pc客戶端,通過git clone 命令從server共享庫裏面克隆Test.Service服務,就是這麼簡單幹脆。
 
GIT目錄結構

所有準備工作已完成,倉庫也已完成初始化操作,下面通過tree命令看看GIT目錄結構及作用。
 
$ tree .git/
.git/
|-- COMMIT_EDITMSG
|-- FETCH_HEAD
|-- HEAD
|-- config
|-- description
|-- hooks
|-- index
|-- info
|   `-- exclude
|-- logs
|   |-- HEAD
|   `-- refs
|       |-- heads
|       |   `-- master
|       `-- remotes
|           `-- origin
|               `-- master
|-- objects
|   |-- 44
|   |   `-- de11e3e3bbe90467ce478b79e821014c87aecd
|   |-- 6a
|   |   `-- bc29053633bce78260d5ac85a7f44b63b5d44e
|   |-- 86
|   |   `-- b5874bc0612638b63e760d5b47bcf43a529bb1
|   |-- info
|   `-- pack
`-- refs
    |-- heads
    |   `-- master
    |-- remotes
    |   `-- origin
    |       `-- master
    `-- tags
18 directories, 15 files
 
如上圖,這是user02GIT倉庫的目錄結構,在調用tree命令之前,我用user02提交了一個文件,所以有些目錄裏面也就有了內容,初始化狀態這些目錄結構裏面是沒有內容的,hooks文件夾裏面本來是有一些sample文件,今天暫時不會涉及到hook內容,所以全部刪掉了,接下來我們一起看看這些目錄文件的作用。
 
HEAD:它是一個文件,存儲我們當前的工作分支,以及當前分支指向的最新commit提交,我們直接通過cat命令看看裏面的內容,看代碼,
 
$ cat .git/HEAD; 
cat .git/refs/heads/master; 
git cat-file -p 6abc
 
ref: refs/heads/master
6abc29053633bce78260d5ac85a7f44b63b5d44e
tree 44de11e3e3bbe90467ce478b79e821014c87aecd
author xxx <[email protected]> 1648389719 +0800
committer xxx <[email protected]> 1648389719 +0800
user02 1st
 
以上代碼我是三個命令一起執行了,cat .git/HEAD; 輸出了ref: refs/heads/master,表示當前工作分支是master,cat .git/refs/heads/master; 輸出了內容爲6abc2,這是一串sha1的hash值,表示當前master的最新提交索引在6abc這個文件裏面,git cat-file -p 6abc命令查看最新提交內容,這裏面涉及到了幾個文件對象,稍後再說。
 
FETCH_HEAD:這個文件在倉庫初始化狀態是沒有的,當我們執行git fetch或者git pull命令之後產生的,它裏面存儲了遠程庫所有分支最新提交的sha1索引,並且當前工作分支排在最前面,它有什麼作用呢?這裏有個小細節,git pull命令實際是兩個命令的組合,當我們執行git pull的時候,會先執行git fetch,fetch之後也就產生了這個文件或者說更新了這個文件,並且把遠程信息拉取到了本地,此時還沒有合併,接着執行git merge合併,其實就是給merge提供對象。
 
$ cat .git/FETCH_HEAD
6abc29053633bce78260d5ac85a7f44b63b5d44e                branch 'master' of  file:///h:/git/server/Test.Service/
 
$ git cat-file -p 6abc
tree 44de11e3e3bbe90467ce478b79e821014c87aecd
author xxx <[email protected]> 1648389719 +0800
committer xxx <[email protected]> 1648389719 +0800
user02 1st
 
命令一,查看fetch head內容,當前只有一個master分支,所以只有一行輸出,如果有多個分支會有多條記錄,61bc表示遠程master的最新提交,命令二查看遠程master最新提交對象,它同樣是個索引,它是個tree對象,對象這部分在objects目錄的時候再說。
 
config:配置文件,主要存儲的是本地配置信息,最只管的就是,我們在公司提交代碼到服務器,顯示的作者信息就是來自於這個配置文件,如果本地配置文件我們沒有設置信息,如用戶郵箱啥的,git會從全局配置信息獲取,全局配置信息我就不貼了,命令很簡單,$ git config --global -l
 
$ cat .git/config
[core]
        repositoryformatversion = 0
        filemode = false
        bare = false
        logallrefupdates = true
        symlinks = false
        ignorecase = true
[user]
        name = xxx
[remote "origin"]
        url = file:///h:/git/server/Test.Service/.git
        fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
        remote = origin
        merge = refs/heads/master 
 
index:暫存區的索引文件,它裏面存儲了文件名、目錄以及它們的內容索引地址,它關聯了工作區和倉庫區,這個怎麼理解?我現在工作區新添加了一個文件,執行git status,git終端輸出文件未跟蹤,當我執行git add命令之後再次執行status,它又提示我staged,所有這些都是通過索引區的這個index文件完成,我們通過命令ls-files -s看下它內容
 
$ git ls-files -s
100644 86b5874bc0612638b63e760d5b47bcf43a529bb1 0       user02.txt
 
$ git cat-file -p 86b5874
user02
 
這裏我只做了一個簡單的文件提交,所以裏面只有一條數據,user02.txt表示文件名,那串hash表示內容索引,我也通過cat-file把它數出來了。
 
objects:這個目錄表示對象集合,這個裏面的對象一般有三種,blob、commit、tree這三種類型,我們前面提到的所有sha1索引指向的內容都在這objects目錄裏面能找到,我們這裏有3個objects,我們通過命令cat-file命令看看,
 
$ git cat-file -t 44de;git cat-file -t 6abc;git cat-file -t 86b5
tree
commit
blob
 
git cat-file -t 查看的是對象類型,接着我們通過cat-file -p查看這三個索引對應的內容
 
$ git cat-file -p 44de;git cat-file -p 6abc;git cat-file -p 86b5
 
100644 blob 86b5874bc0612638b63e760d5b47bcf43a529bb1    user02.txt // tree對象的內容
 
tree 44de11e3e3bbe90467ce478b79e821014c87aecd // commit對象的內容
author yukang.wu <[email protected]> 1648389719 +0800
committer yukang.wu <[email protected]> 1648389719 +0800
user02 1st
 
user02 // blob對象的內容
 
以上內容我簡單做了一些註釋,這裏再補充一下,blob對象產生是在 git add命令之後,這個對象只會記錄文件內容(注意如果兩份或者以上文件裏面的內容完全一樣,只會有一個blob對象產生,空文件夾不跟蹤),commit對象產生是在 git commit命令之後,這個對象一般會包含一個tree對象以及其他輔助信息,如作者、時間戳、時區、提交說明、父對象(因爲我這邊是首次提交),tree對象的產生同樣是在commit命令之後,tree對象裏面主要記錄的是文件內容指針,目錄結構,文件名,整個設計確實很巧妙。
 
refs目錄:前面有提到過,主要記錄的是本地、遠程、以及標籤的內容索引地址,可以回到上面看一下。
 
pack: objects對象打包目錄,一般情況下,我們第一次從遠程拉取文件,我們的所有對象都是壓縮打包的,包括index,還有一種情況,我們執行git gc命令,git也會幫我們打包所有objects對象,我們可以通過git verify-pack -v 命令查看裏面的內容
|-- objects
|   |-- info
|   |   |-- commit-graph
|   |   `-- packs
|   `-- pack
|       |-- pack-872cbb392373e21735af47cb261f9fe3886ea31c.idx
|       `-- pack-872cbb392373e21735af47cb261f9fe3886ea31c.pack
 
$ git verify-pack -v  .git/objects/pack/pack-872cbb392373e21735af47cb261f9fe3886ea31c.pack
c4ca5ee2c3162610f2d218ebf61e22f153875def commit 222 155 12
6abc29053633bce78260d5ac85a7f44b63b5d44e commit 193 136 167
fcd15acf93cad34ac127b658f4e16be63a12e915 blob   3 12 303
0fe633e30c461e9e5e08d545fe06d909243955dd blob   3 12 315
98d03acc98edaf728a186256b5cc25de43447055 blob   4 13 327
86b5874bc0612638b63e760d5b47bcf43a529bb1 blob   7 16 340
a5ecf8da194ea4dbe5b59e9156e45aba1246cb54 tree   36 45 356
64229d6afd42a9d26082572a8d11f9b529a12fa3 tree   103 108 401
44de11e3e3bbe90467ce478b79e821014c87aecd tree   38 49 509
non delta: 9 objects
.git/objects/pack/pack-872cbb392373e21735af47cb261f9fe3886ea31c.pack: ok
 
結尾

GIT計劃分兩次寫,今天主要是以概念爲主,以靜態方式解析git背後的邏輯原理,由於時間問題,明天還要上班,可能有些地方寫的不夠詳細,或者理解不對,包含吧,下次以操作爲主,當然不是講命令操作,主要是挑一些工作中碰到的問題,比如回退、撤銷、變基、合併等背後的一些邏輯。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章