git使用下



Git 內部工作原理


Git 本質上是一個內容尋址文件系統,最初是一套面向版本控制系統的工具集,而不是一個完整的用戶友好的版本控制系統。因此它還包含了一些用於完成底層工作的命令,這些命令被稱爲“底層命令”,而那些更友好的命令則被當作“高層命令”來使用。


Git 目錄


當執行 git init 操作時會生成一個 .git 目錄


這是一個全新的 git init 目錄,這個目錄後續可能還會添加其他文件。其中description文件僅供 GitWeb 程序使用,我們無需關心,info 包含全局性排除文件,用來放置那些不希望被記錄在 .ignore中的忽略模式。hooks 放置鉤子腳本。


config


Git 自帶一個 git config工具來控制設置 git 外觀和行爲的配置變量,這些變量存儲在三個不同的位置。

1. ./etc/git config 包含系統上每個用戶及其倉庫的通用配置。

        git  config --system 命令會從此位置讀取配置變量

2. ~/.gitconfig 或 ~/.config/git/config:只針對當前用戶

        git config --global 命令會從此位置讀取配置變量

3. 當前使用倉庫的 .git 目錄中的 config 文件:只針對該倉庫,一些分支的信息和遠端倉庫的信息以及 fetchpush操作的信息都有保存。


Objects(對象):保存所有數據內容


剛剛我們提到,git 是一個內容尋址文件系統,那麼什麼是內容尋址文件系統呢?其實 git 的核心部分是一個鍵值對數據庫,它的值可以存儲任何數據類型的內容,這個值對應返回一個鍵,通過這個鍵可以檢索對應的內容。

接下來我們通過實驗,來看看 git 在 add 和 commit 的過程中都做了什麼


1.創建一個全新的 git 倉庫

2.在倉庫中添加一個文件,並執行 add 操作


此時我們可以在 objects 目錄下看到多了一個文件夾


文件夾裏面的東西是很麼呢?


其實這就是執行 git add 命令後生成的一個對象,git將對象的 hash 值的前兩位 8d 作爲文件夾名,其餘38位作爲文件名保存。

我們可以通過 git cat-file 命令可以從對象中取出數據:

    git cat-file -p 8d0e41234f24b6da002d962a26c2495ea16a425f


控制檯輸出了 hello git,而文件 test.txt 中的內容正是 "hello git"

這個對象就是 git objects 中的數據對象 (blob object) ,我們可以用:

    git cat-file -t 8d0e41234f24b6da002d962a26c2495ea16a425f 命令查看對象類型


接下來我們繼續 git commit 操作,


可以看到提交後又生成了兩個對象。

我們分別來看一下這兩個對象的內容,


裏面保存的是 blob 對象 hash 值,文件名稱。

查看它的類型可以看到控制檯返回了 tree,這就是 git 對象中的樹對象 (tree object)

如果我們多提交幾次,大致就可以看到裏面的內容其實是一個樹形結構,


再來看看另一個對象,


這個對象中的格式也很簡單,它首先指定頂層樹對象,代表當前項目快照,然後是作者信息和提交者信息,留一行空,接着是提交描述信息。


查看他的類型是 commit,這個對象其實就是提交對象 (commit object)

如果我們多進行幾次提交,將看到 .git/logs/HEAD 文件保存這樣的內容

這個 HEAD 文件保存的是當前分支下的快照,裏面記錄了當前分支中的提交記錄,我們可以發現每一行代表一個提交記錄,後一個 commit 持有前一個 commit 的 hash 值,以此形成了一個鏈表結構。

以上我們所看到的就是 git 執行 add 和 commit 的實質工作,將被改寫的文件保存爲數據對象,更新暫存區,記錄樹對象,最後創建一個指明瞭頂層樹對象和父提交的提交對象。


Refs(引用):保存指向分支的提交對象的指針


Refs 相當於最後一個提交的 commit hash 的一個別名,因爲我們可以執行類似 git log 8d0e412來查看完整的提交歷史,但是遍歷那段歷史從而找到相關對象,我們需要記住最後一個提交的 hash 值,git將這個 hash 值用文件保存起來,並給文件取一個簡單的名字,用這個名字指針指向原始的 hash 值。

git 分支的本質其實基本上就是一個指向某一系列提交之首的指針或引用。


我們通過 git log --pretty=oneline master 命令查看到 master 分支下的提交記錄

現在你若想在第二個提交上創建一個分支可這麼做:


當我們用類似於 git branch <branchname> 的命令時,git 底層執行的是 update-ref 命令,取得當前所在分支最新提交的 hash 值,然後將其加入到我們創建的新引用中。這也是 git 創建分支比 svn 快得多的原因,git 創建一個分支只需要創建一個引用的時間。

refs 目錄下包含 heads,tags,remotes 目錄;

heads 目錄:定義所有的本地引用;

tags 目錄:標籤引用;

remotes 目錄:遠程引用;

遠程分支引用和本地分支引用最大的區別在於遠程分支引用是隻讀的,雖然可以用 git checkout 到某個遠程引用,但是 head 指針並不會指到遠程引用上去,git 只是將這些遠程引用作爲指向遠程倉庫中最後一次提交的書籤來管理。


Index:保存暫存區信息


HEAD:指向當前被檢出的分支


我們發現這個引用和別的引用不一樣,實際上他是指向其他引用的一個指針。當我們執行 git checkout  <branchName> 命令時,實際上是將 HEAD 文件中的引用改爲了需要檢出分支的引用。


總結

以上就是我所學習的 Git 進階全部內容,因爲 Git 還有很多其他操作,此處無法窮舉。如果真的要完全理解 Git 的原理還是要在實際工作中多操作練習。

Git 內部工作原理


Git 本質上是一個內容尋址文件系統,最初是一套面向版本控制系統的工具集,而不是一個完整的用戶友好的版本控制系統。因此它還包含了一些用於完成底層工作的命令,這些命令被稱爲“底層命令”,而那些更友好的命令則被當作“高層命令”來使用。


Git 目錄


當執行 git init 操作時會生成一個 .git 目錄


這是一個全新的 git init 目錄,這個目錄後續可能還會添加其他文件。其中description文件僅供 GitWeb 程序使用,我們無需關心,info 包含全局性排除文件,用來放置那些不希望被記錄在 .ignore中的忽略模式。hooks 放置鉤子腳本。


config


Git 自帶一個 git config工具來控制設置 git 外觀和行爲的配置變量,這些變量存儲在三個不同的位置。

1. ./etc/git config 包含系統上每個用戶及其倉庫的通用配置。

        git  config --system 命令會從此位置讀取配置變量

2. ~/.gitconfig 或 ~/.config/git/config:只針對當前用戶

        git config --global 命令會從此位置讀取配置變量

3. 當前使用倉庫的 .git 目錄中的 config 文件:只針對該倉庫,一些分支的信息和遠端倉庫的信息以及 fetchpush操作的信息都有保存。


Objects(對象):保存所有數據內容


剛剛我們提到,git 是一個內容尋址文件系統,那麼什麼是內容尋址文件系統呢?其實 git 的核心部分是一個鍵值對數據庫,它的值可以存儲任何數據類型的內容,這個值對應返回一個鍵,通過這個鍵可以檢索對應的內容。

接下來我們通過實驗,來看看 git 在 add 和 commit 的過程中都做了什麼


1.創建一個全新的 git 倉庫

2.在倉庫中添加一個文件,並執行 add 操作


此時我們可以在 objects 目錄下看到多了一個文件夾


文件夾裏面的東西是很麼呢?


其實這就是執行 git add 命令後生成的一個對象,git將對象的 hash 值的前兩位 8d 作爲文件夾名,其餘38位作爲文件名保存。

我們可以通過 git cat-file 命令可以從對象中取出數據:

    git cat-file -p 8d0e41234f24b6da002d962a26c2495ea16a425f


控制檯輸出了 hello git,而文件 test.txt 中的內容正是 "hello git"

這個對象就是 git objects 中的數據對象 (blob object) ,我們可以用:

    git cat-file -t 8d0e41234f24b6da002d962a26c2495ea16a425f 命令查看對象類型


接下來我們繼續 git commit 操作,


可以看到提交後又生成了兩個對象。

我們分別來看一下這兩個對象的內容,


裏面保存的是 blob 對象 hash 值,文件名稱。

查看它的類型可以看到控制檯返回了 tree,這就是 git 對象中的樹對象 (tree object)

如果我們多提交幾次,大致就可以看到裏面的內容其實是一個樹形結構,


再來看看另一個對象,


這個對象中的格式也很簡單,它首先指定頂層樹對象,代表當前項目快照,然後是作者信息和提交者信息,留一行空,接着是提交描述信息。


查看他的類型是 commit,這個對象其實就是提交對象 (commit object)

如果我們多進行幾次提交,將看到 .git/logs/HEAD 文件保存這樣的內容

這個 HEAD 文件保存的是當前分支下的快照,裏面記錄了當前分支中的提交記錄,我們可以發現每一行代表一個提交記錄,後一個 commit 持有前一個 commit 的 hash 值,以此形成了一個鏈表結構。

以上我們所看到的就是 git 執行 add 和 commit 的實質工作,將被改寫的文件保存爲數據對象,更新暫存區,記錄樹對象,最後創建一個指明瞭頂層樹對象和父提交的提交對象。


Refs(引用):保存指向分支的提交對象的指針


Refs 相當於最後一個提交的 commit hash 的一個別名,因爲我們可以執行類似 git log 8d0e412來查看完整的提交歷史,但是遍歷那段歷史從而找到相關對象,我們需要記住最後一個提交的 hash 值,git將這個 hash 值用文件保存起來,並給文件取一個簡單的名字,用這個名字指針指向原始的 hash 值。

git 分支的本質其實基本上就是一個指向某一系列提交之首的指針或引用。


我們通過 git log --pretty=oneline master 命令查看到 master 分支下的提交記錄

現在你若想在第二個提交上創建一個分支可這麼做:


當我們用類似於 git branch <branchname> 的命令時,git 底層執行的是 update-ref 命令,取得當前所在分支最新提交的 hash 值,然後將其加入到我們創建的新引用中。這也是 git 創建分支比 svn 快得多的原因,git 創建一個分支只需要創建一個引用的時間。

refs 目錄下包含 heads,tags,remotes 目錄;

heads 目錄:定義所有的本地引用;

tags 目錄:標籤引用;

remotes 目錄:遠程引用;

遠程分支引用和本地分支引用最大的區別在於遠程分支引用是隻讀的,雖然可以用 git checkout 到某個遠程引用,但是 head 指針並不會指到遠程引用上去,git 只是將這些遠程引用作爲指向遠程倉庫中最後一次提交的書籤來管理。


Index:保存暫存區信息


HEAD:指向當前被檢出的分支


我們發現這個引用和別的引用不一樣,實際上他是指向其他引用的一個指針。當我們執行 git checkout  <branchName> 命令時,實際上是將 HEAD 文件中的引用改爲了需要檢出分支的引用。


總結

以上就是我所學習的 Git 進階全部內容,因爲 Git 還有很多其他操作,此處無法窮舉。如果真的要完全理解 Git 的原理還是要在實際工作中多操作練習。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章