一直用git,你了解git的內部機制嗎?

2021-10-13 13:07:08 字數 4084 閱讀 5228

在工作過程中我們會不可避免的使用git,但是你知道git是如何儲存你的檔案、如何儲存你的提交資訊嗎?等等 了解這些也便於我們更好的理解和記憶命令,更好的排查問題和使用git,下面就讓我們來看一下吧~

首先,我們要明確 git 是乙個分布式版本控制系統 其本質是一套內容定址檔案系統通俗點說,git 從核心上來看不過是簡單地儲存鍵值對(key-value)。它允許插入任意型別的內容,並會返回乙個鍵值,通過該鍵值可以在任何時候再取出該內容。

ps : 下面所說的sha-1碼 和 commit_id 是同一種

首先,git儲存在本地的表現形式當你在乙個新目錄或已有目錄內執行 git init 時,git 會建立乙個 .git 目錄,幾乎所有 git 儲存和操作的內容都位於該目錄下。如果你要備份或複製乙個庫,基本上將這一目錄拷貝至其他地方就可以了。如下圖:

其中,head 及 index 檔案,objects 及 refs 目錄是 git 的核心部分。

接下來,說一下git的儲存方式

如上述所說,objects 目錄儲存所有資料內容,objects 目錄下的每乙個檔案是git為每份儲存資料內容生成乙個檔案,取得該內容與頭資訊的 sha-1 校驗和,建立以該校驗和前兩個字元為名稱的子目錄,並以 (校驗和) 剩下 38 個字元為檔案命名 (儲存至子目錄下)。如下圖:

開啟00資料夾可以看到裡面儲存的內容:

git 以一種類似 unix 檔案系統但更簡單的方式來儲存內容。所有內容以 tree 或 blob 物件儲存,其中 tree 物件對應於 unix 中的目錄,blob 物件則大致對應於 inodes 或檔案內容。

乙個單獨的 tree 物件包含一條或多條 tree 記錄,每一條記錄含有乙個指向 blob 或子 tree 物件的 sha-1 指標,並附有該物件的許可權模式 (mode)、型別和檔名資訊。

正如git的每一次提交都是對**倉庫的完整備份,也就是儲存了乙份**倉庫完整的快照所說,每乙個commit都是儲存為乙個tree,如下圖:

具體在git中為:

可以看到,目錄作為tree儲存,檔案作為blob儲存

之後,我們通過git cat-file-p命令可以發現儲存是樹型的,也就是對應於git的tree物件,儲存的都是指向下乙個部分的索引id 如下圖,每一步都是檢視的上一步中的某個id:

上述所說每個commit建立乙個樹快照,那麼是通過什麼建立的呢?

這就是我們上述說的用於儲存暫存區資訊的index檔案了

通常 git 根據你的暫存區域或 index 來建立並寫入乙個 tree 。因此要建立乙個 tree 物件的話首先要通過將一些檔案暫存從而建立乙個 index 。

這也是為什麼commit前必須要有檔案被add到暫存區,如果暫存區為空,commit會報錯停止執行。

這個時候就有乙個問題了,我們有多個快照樹,它們指向了你要跟蹤的專案的不同快照,其中也沒有關於誰、何時以及為何儲存了這些快照的資訊

此時,commit物件就出場了~ 每次commit提交後就會建立乙個對應commit 物件,這個物件就是為你儲存了這些基本資訊的。

一般情況下,一次commit提交就可以理解為建立了乙個tree樹,以commit_id為根節點的tree,該樹包含了當前專案的整體快照

當我們使用git log命令檢視提交歷史的時候,就展示了commit物件的一些基本資訊,如下圖:

其中:commit 後跟的id就是當前commit快照的樹根節點id 其餘的還包含作者,作者郵箱,建立時間等基本資訊

git每次commit提交會儲存專案快照,難道是將所有的檔案重新複製乙份嗎?當然不可能,在git的檔案系統中,是存在共用檔案的。

比如有三次commit提交,產生了三個tree樹,它們在向下引用的時候,如果兩個commit中的整個資料夾或者某個檔案沒有改變,這兩個commit的tree會指向同乙個物件。對於兩次提交修改了的檔案,則會建立乙個該檔案的乙個新的版本的檔案,上一次提交指向舊的檔案,修改檔案的提交指向新版本的檔案。

整體情況如下圖:

另外,git 用 zlib 壓縮檔案內容,因此儲存的檔案並不會占用太多空間

了解了git整體儲存方式之後,我們再看一下前面提到的儲存指向資料 (分支) 的提交物件的指標的refs目錄

refs目錄內容如下圖:

首先,也是思考乙個問題:在專案開發中,有許多分支,每個分支的提交記錄都不相同,我們也不可能去記住每個commit_id,去執行像git log1a410e這樣的命令來檢視完整的歷史,這樣的話你就要記得 1a410e 是你最後一次提交並且記得這個id,這樣才能在提交歷史中找到這些物件,git是怎樣的應對這個問題的呢?

這時候,我們需要乙個檔案來用乙個簡單的名字來記錄這些 sha-1 值,這樣就可以用這些指標而不是原來的 sha-1 值去檢索了。在 git 中,稱之為「引用」(references 或者 refs)。

可以在 .git/refs 目錄下面找到這些包含 sha-1 值的檔案。如下圖refs中heads檔案下的檔案,其中每個檔案儲存的是與檔名同名的分支的最新提交的commit_id

新增上refs資料夾下的檔案後,我們的git儲存結構就看起來像下圖:

接下來,再思考乙個問題,git是怎麼標識當前是在什麼分支,從而找到refs中對應的對映檔案獲取sha-1值呢?

那就是前面所說的head檔案了,我們開啟檔案可以看到以下內容:ref:refs/heads/test_branch

這裡標識的是當前指向的是test_branch分支,並且指定了要是用的對映檔案的路徑,這樣就解決了上述問題,是不是特別簡單~

上述已經介紹了git的三個主要型別:tree樹、commit物件、head。下面我們說一下git中另外乙個重要的東西:tag(標籤)tag 物件比較簡單,tag物件非常像乙個 commit 物件---包含乙個標籤,一組資料,乙個訊息和乙個指標。最主要的區別就是 tag 物件指向乙個 commit 而不是乙個 tree。它就像是乙個分支引用,但是不會變化,永遠指向同乙個 commit,僅僅是為了提供乙個更加友好的名字。

好了,通過介紹了git的核心組成元素head及index檔案,objects及refs目錄, 你應該會對git的儲存和一些機制有乙個簡單的整體了解,這對我們更好的理解git命令和更好的使用git是有幫助的。希望本片文章會對大家有些許幫助~

參考:git官

git 密碼一直輸入錯誤 ssh建立

1.在桌面右擊 選擇 git bash here 2.輸入 cd ssh 3.然後輸入ls檢視秘鑰列表 如上圖是已經配置過了就無需配置。如果沒有看到id ras.pub檔案即沒有配置,同上開啟git base here然後輸入下面命令 1.輸入命令 cd 2.然後輸入 ssh keygen.exe ...

一直都用SVN,今天突然要使用GIT,懵逼

我之前知道github這個好東西,也一直以為git和它是同乙個東西,但是今天查了一下他倆之間的關係,才知道根本不是。什麼是版本控制?大學 知道吧?我們在寫 的時候,寫完了提交給指導老師去審核,老師說你哪哪哪寫的不好要改改,於是乎,你就屁顛屁顛的去改。一般的做法是 不直接在原 上修改,而是複製乙份,在...

為什麼你的月薪一直破不了萬?

算一筆賬,在北京扣除五險一金的全部繳納專案稅前工資需要15000元,在上海扣除五險一金要到14000元,在廣州和深圳的職場人需要稅前工資在16000元才能確保月薪破萬。所以稅前的工資不夠高,月薪拿到手裡當然只有幾千塊了。如果月薪低於萬元是常態,那麼你屬於哪一種情況?工作一兩年的職場菜鳥 如果你目前工...