Git內部原理

Git有什么特點?

圖片

?

  • fast,scalable,distributed revision control system(快速,可擴展的分布式版本控制系統)

?

    • 幾乎所有操作都是本地執行

    • 每一個clone都是整個生命周期的完整副本

?

  • the stupid content tracker(只是一個內容追蹤器)

?

?

    • Git追蹤的是內容而不是文件

    • 如果兩個文件的內容相同,無論是否在相同的目錄,Git在對象庫里只保存一份blob對象

  • Immutable(不可變性)

?

    • Git版本庫中存儲的數據對象均為不可變的,一旦創建數據對象并放入了數據庫中,它們便不可修改。這也意味著存儲在版本數據庫中的整個歷史也是不可變的。

?

  • Porcelain(高層命令)

?

    • init, add, commit, branch, merge.

?

  • Plumbing(底層命令)

?

    • hash-object, update-index, write-tree.

?

圖片

每一個Client端都可以是Server

?

Git Version Database是什么?

圖片

?

Git是一個內容尋址文件系統。這意味著,Git的核心部分是一個簡單的鍵值對數據庫(key-value data store)。你可以向該數據庫插入任意類型的內容,它會返回一個鍵值,通過該鍵值可以在任意時刻再次檢索該內容。而這些數據全部是存儲在objects目錄里。key是一個hash,hash前兩個字符用于命名子目錄,余下的38個字符則用作文件名。如果了解tree樹的朋友應該會想明白之所以這樣處理是因為檢索優化策略,提高文件系統效率(如果把太多的文件放入同一個目錄中,一些文件系統會變慢)。而這個hash的內容(即hash對應的Value)有四種對象類型,commit(提交),tree(目錄樹),blob(塊),tag(標簽)。

?

Git基本概念:

?

  • Content addressable filesystem(內容尋址文件系統)

  • Simple key-value data store(鍵值對數據)

  • Key:SHA-1散列(hash,哈希)

?

    • Everything is hash

    • 這是一個由40個十六進制字符(0-9和a-f)組成字符串

?

  • Value:binary files

?

    • Commit:Actual git commits(提交)

    • Tree:Directoy(目錄樹)

    • Blob:file content(文件內容)

?

note:可以理解成Commit = Tree + Blob的snapshot

?

什么是SHA-1:SHA-1(安全散列函數),是一種密碼散列函數,美國國家安全局設計,并由美國國家標準技術研究所發布為聯邦數據處理標準。SHA-1可以生成一個被稱為消息摘要的160位(20字節)散列值,散列值通常的呈現形式為40個十六進制數。用js來理解就是一個純函數,輸入一定輸出也一定,相同的輸入一定有相同的輸出。不相同的輸入一定有不同的輸出(不考慮碰撞 ,比彗星撞擊地球的概率還低)。

?

Git到底是如何工作呢?

圖片

?

我們知道最簡單的git flow主要有三步:

?

  1. 在工作目錄中修改文件。

  2. 暫存文件,將文件的快照放入暫存區域。

  3. 提交更新,找到暫存區域的文件,將快照永久性存儲到Git倉庫目錄。

?

對應高層命令是這樣的:

 

$?git?init
$?git?add?.
$?git?commit

在我們看這三個命令到底做了什么之前,先來了解一下幾個概念:

?

圖片

?

  • Working Directory:工作區(工作目錄)

  • Stageing Area (Index):暫存區

  • Repository:倉庫區(本地倉庫)

?

Git init

圖片

?

我們先用Git init來初始化一個項目,并查看項目的目錄結構。

 

$?git?init?demo1?&&?cd?demo1
$?tree?.git
.git
├──?HEAD
├──?config
├──?description
├──?hooks
│???├──?applypatch-msg.sample
│???├──?commit-msg.sample
│???├──?fsmonitor-watchman.sample
│???├──?post-update.sample
│???├──?pre-applypatch.sample
│???├──?pre-commit.sample
│???├──?pre-push.sample
│???├──?pre-rebase.sample
│???├──?pre-receive.sample
│???├──?prepare-commit-msg.sample
│???└──?update.sample
├──?info
│???└──?exclude
├──?objects
│???├──?info
│???└──?pack
└──?refs
????├──?heads
????└──?tags

description文件僅供GitWeb程序使用。config文件包含項目特有的配置選項。info目錄包含一個全局性排除文件,用以放置那些不希望被記錄在.gitignore文件中的忽略模式。hooks目錄包含客戶端或服務端的鉤子腳本,這些我們暫時都無需關心。最重要的是:HEAD文件、(尚待創建的)index文件,和objects目錄、refs目錄。這些條目是Git的核心組成部分。objects目錄存儲所有數據內容(hash);refs目錄存儲指向數據(分支)的提交對象的指針(commit hash);HEAD文件指示目前被檢出的分支(refs目錄內的分支名);index 文件保存暫存區信息(git ls-files --stage命令查看當前暫存區信息)。

?

下面我們就用底層命令來實現git init指令(另創建一個demo2目錄)。

?

mkdir -p參數是能直接創建一個不存在的目錄下的子目錄:

 

$?mkdir?-p?.git/refs/heads?.git/refs/tags?.git/objects
$?echo?'ref:?refs/heads/master'?>?.git/HEAD

圖片

?

可以看到已經成功初始化了一個Git項目。

?

git add

圖片

?

 

$?echo?'hello?git'?>?index.txt
$?git?add?index.txt

執行完這兩句指令后我們再來看.git文件夾發生了什么變化(為了顯示效果,簡化目錄結構,之后tree 都忽略hooks文件夾)

 

.git
├──?HEAD
├──?config
├──?description
├──?index
├──?info
│???└──?exclude
├──?objects
│???├──?8d
│???│???└──?0e41234f24b6da002d962a26c2495ea16a425f
│???├──?info
│???└──?pack
└──?refs
????├──?heads
????└──?tags

可以看到多了一個index文件,并且objects目錄里面多了一個8d的文件夾,里面有一個0e41開頭的文件、那這個8d0e4這個是什么呢?其實這個就是index.txt文件內容的hash。還記得嘛,剛才寫入文件內容是hello git,我們來手動輸出這個內容的hash。

 

$?echo?'hello?git'?|?git?hash-object?--stdin
$?8d0e41234f24b6da002d962a26c2495ea16a425f

可以通過cat-file命令從Git那里取回數據。為cat-file指定-p選項可指示該命令自動判斷內容的類型,并為我們顯示格式友好的內容:

 

$?git?cat-file?-p?8d0e
$?hello?git

為cat-file指定-t選項可以查看文件的類型:

 

$?git?cat-file?-t?8d0e
$?blob

git add做了兩件事情:

?

  • 文件內容做一個hash存成blob object

  • 把index放入到Staging Area

?

當為index.txt創建一個對象的時候,git并不關心index.txt的文件名,git 只關心文件里面的內容。

?

按照這個思路,我們用底層命令來實現一下git add指令。

 

$?echo?'hello?git'?|?git?hash-object?-w?--stdin

$?git?update-index?--add?--cacheinfo?100644?8d0e41234f24b6da002d962a26c2495ea16a425f?index.txt

-w選項指示hash-object命令存儲數據對象;若不指定此選項,則該命令僅返回對應的鍵值。

?

我們指定的文件模式為100644,表明這是一個普通文件。其他選擇包括:100755,表示一個可執行文件;120000,表示一個符號鏈接。

?

圖片

?

因為并沒有去創建這個index.txt文件, 所以這邊提示已經刪除了,執行git checkout -- index.txt取出文件。

?

圖片

?

可以看到已經成功用底層命名實現了git add的功能。

?

到這里,我們自然就會有個疑問了,那文件名怎么辦?

?

Git是通過tree對象來跟蹤文件的路徑名的。當使用git add命令時,git會給添加的文件內容創建一個blob對象,但是這個時候并不會創建tree對象。而只是更新索引,索引在.git/index中,它跟蹤文件的路徑名和相對應blob,每次執行git add 、git rm 、 git mv 的時候,git都會更新索引,我們可以通過命令git ls-files --stage來查看當前的索引信息。

 

$?git?ls-files?--s
$?100644?8d0e41234f24b6da002d962a26c2495ea16a425f?0?index.txt

?

git commit

圖片

?

執行git commit -m 'init-1'后,查看tree結構,發現object 多出了兩個文件:

 

.git
├──?COMMIT_EDITMSG
├──?HEAD
├──?config
├──?description
├──?index
├──?info
│???└──?exclude
├──?logs
│???├──?HEAD
│???└──?refs
│???????└──?heads
│???????????└──?master
├──?objects
│???├──?75
│???│???└──?0d7c0f7f998d3e2ce2d71ec801902f69bf6a39
│???├──?88
│???│???└──?bc066ebf3d864e34297f7051a0ded16e49813a
│???├──?8d
│???│???└──?0e41234f24b6da002d962a26c2495ea16a425f
│???├──?info
│???└──?pack
└──?refs
????├──?heads
????│???└──?master
????└──?tags
$?git?log
$?commit?750d7c0f7f998d3e2ce2d71ec801902f69bf6a39?(HEAD?->?master)

查看這個commit 的文件類型,可以看到這是一個commit:

 

$?git?cat-file?-t?750d
$?commit

$?git?cat-file?-p?750d
$?tree?88bc066ebf3d864e34297f7051a0ded16e49813a

但是多出來的88bc是什么呢,其實就是當前目錄的tree對象,所以Git是在commit的時候才創建tree對象的(其實是把索引轉化成tree對象)。

 

$?git?cat-file?-t?88bc
$?tree

$?git?cat-file?-p?88bc
$?100644?blob?8d0e41234f24b6da002d962a26c2495ea16a425f??index.txt

這個時候再看HEAD:

 

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

繼續查看refs/heads/master:

 

$?cat?.git/refs/heads/master
$?750d7c0f7f998d3e2ce2d71ec801902f69bf6a39

所以整個指向關系就是:HEAD里面的內容是當前的ref,而當前ref的內容是commit hash,commit對象內容是tree hash,tree對象的內容是文件夾/文件信息,而blob對象存儲著文件的具體內容。這樣當完成一次提交的時候,整個狀態的對應關系也是確定的,所以說commit對象就是當前系統的snapshot。

?

圖片

?

再來回顧下一次完整的提交流程:

?

圖片

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/535423.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/535423.shtml
英文地址,請注明出處:http://en.pswp.cn/news/535423.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

git存儲原理

四種數據類型 實際上Git基于數據類型的不同,把對象分為四種:數據對象、樹對象、提交對象、標簽對象。Git文件系統的設計思路與linux文件系統相似,即將文件的內容與文件的屬性分開存儲,文件內容以“裝滿字節的袋子”存儲在文件系統…

詳解設計模式:中介者模式

中介者模式(Mediator Pattern)也被稱為調停者模式,是在 GoF 23 種設計模式中定義了的行為型模式。 中介者模式 是用來降低多個對象和類之間的通信復雜性。這種模式提供了一個中介類,該類通常處理不同類之間的通信,并支…

rebase參數以及注意事項

可以根據需要將pick參數,改變為下面代表不同作用的參數;這樣就可以對節點C和D進行不同的操作了。比如: pick:默認參數,表示不對提交節點進行任何操作,直接應用原提交節點。不創建新提交; rewor…

RPC 服務 與 HTTP 服務的區別

1、什么是RPC RPC(Remote Procedure Call)—遠程過程調用,它是一種通過網絡從遠程計算機程序上請求服務,而不需要了解底層網絡技術的協議。RPC協議假定某些傳輸協議的存在,如TCP或UDP,為通信程序之間攜帶信…

Docker 網絡命名空間

Docker 用戶可以通過與 CNM 的 Object 以及 API 的交互來管理對應容器的網絡,下面是一個典型的容器網絡生命周期: 1、Driver要向NetworkController注冊。內置的Driver在Libnetwork內注冊,遠程的Driver則通過Plugin mechanism注冊。每一個Driv…

緩存雪崩、擊穿、穿透解決方案

用戶的數據一般都是存儲于數據庫,數據庫的數據是落在磁盤上的,磁盤的讀寫速度可以說是計算機里最慢的硬件了。 當用戶的請求,都訪問數據庫的話,請求數量一上來,數據庫很容易就奔潰的了,所以為了避免用戶直…

Ansible中的playbook詳解

首先簡單說明一下playbook,playbook是什么呢? 根本上說playbook和shell腳本沒有任何的區別,playbook就像shell一樣,也是把一堆的命令組合起來,然后加入對應條件判斷等等,在shell腳本中是一條一條的命令&am…

【Docker】容器鏡像有哪些特性

首先解釋一下什么是Docker鏡像? Docker鏡像它其實是一個模板,擁有這個模板我們才能創建我們的Docker容器,鏡像里含有啟動 docker 容器所需的文件系統結構及其內容,因此是啟動一個 docker 容器的基礎。docker 鏡像的文件內容以及一…

nginx中的location指令

1、location 介紹 location是Nginx中的塊級指令(block directive),location指令的功能是用來匹配不同的url請求,進而對請求做不同的處理和響應,這其中較難理解的是多個location的匹配順序,本文會作為重點來解釋和說明。 開始之前…

容器底層實現技術Namespace/Cgroup

Docker容器實現原理 Docker容器在實現上是通過namespace技術來進行進程隔離,通過cgroup技術實現容器進程可用資源的限制,當docker啟動一個容器時,實際是創建了多了namespace參數的進程。 Namespace Namespace:命名空間 作用&#…

身體原因 斷更一周

由于眾所周知的原因,博主最近具有發熱、全身乏力、酸痛、干咳等癥狀,已嚴重影響日常的工作學習和博客編寫,所以斷更我將一周,由下周三(即2022年12月21日)恢復更新 更多往期內容可以參考:全網最…

異方差與多重共線性對回歸問題的影響

異方差的檢驗 1.異方差的畫圖觀察 2.異方差的假設檢驗,假設檢驗有兩種,一般用懷特檢驗使用方法在ppt中,課程中也有實驗,是一段代碼。 異方差的解決辦法 多重共線性 多重共線性可能帶來的影響: 多重共線性的檢驗 多重…

如何修改Docker的鏡像源

改或新增/etc/docker/daemon.json 文件 vi/etc/docker/daemon.json 添加需要修改的國內鏡像源鏡像源 { "registry-mirrors":["http://hub-mirror.c.163.com"] } 重啟Docker服務 Systemctl restart docker.service 方法二 修改或新增 /etc/sysconfig…

nginx 的 rewrite 模塊

ngxhttprewrite_module 模塊用來使用正則表達式(PCRE)改變請求的 URI,返回重定向,并有條件地選擇配置。 指令執行順序 首先順序執行 server 塊中的 rewrite 模塊指令,得到 rewrite 后的請求 URI 然后循環執行如下指令…

所有的Python庫

庫名稱簡介 Chardet字符編碼探測器,可以自動檢測文本、網頁、xml的編碼。 colorama主要用來給文本添加各種顏色,并且非常簡單易用。 Prettytable主要用于在終端或瀏覽器端構建格式化的輸出。 difflib,[Python]標準庫,計算文本…

Oracle行轉列語法總結大全

一、decode語法 SELECT deptno, nvl(SUM(decode(job, MANAGER, sal)), 0) s_MANAGER, nvl(SUM(decode(job, ANALYST, sal)), 0) s_ANALYST, nvl(SUM(decode(job, CLERK, sal)), 0) s_CLERK, nvl(SUM(decode(job, PRESIDENT, sal)), 0) s_PRESIDENT, …

Shell 各種符號 之 含義

#!&#xff1a;符號能夠被內核識別成是一個腳本的開始&#xff0c;這一行必須位于腳本的首行 $0&#xff1a;當前腳本的名字 $#&#xff1a;輸入<調用>參數(腳本或函數的位置參數) 的個數&#xff0c;如 NumArg$#&#xff1b;echo"\$#: $#;\$NumArg: $NumArg"…

Nginx的11個執行流程

1 Nginx簡介 Web服務器市場份額 Nginx [engine x] 最初由 Lgor Sysoev 編寫。根據 Netcraft 的數據&#xff0c;到2020年9月&#xff0c;Nginx 服務或代理了25.76&#xff05;站點&#xff0c;市場份額占到了約34.03&#xff05;。 Nginx 被廣泛用作&#xff1a; HTTP服務器…

Nginx的執行階段詳解

在了解nginx的執行階段前&#xff0c;先看一個例子 對echo不熟悉的&#xff0c;可以先看文章Nginx調試必備了解下echo擴展 回到上面這個例子&#xff0c;在server塊中配置這樣的location&#xff0c;你覺得輸出是什么樣子&#xff1f; 按照正常的邏輯&#xff0c;輸出應該是32 …

Docker掛了,數據如何找回

docker在實際使用中&#xff0c;讓運維人員詬病的&#xff0c;除了安全問題外&#xff0c;大概就是數據的問題了 很多人在初用docker的時候&#xff0c;很多時候都忘記或不知道docker中需要保留的數據需要掛載到宿主機文件夾到容器內部對應目錄&#xff08;當然除了掛載宿主機目…