做技術一定要知其然知其所以然,意思就是:知道它是這樣的,更知道它為什么是這樣的。我主要通過4塊內容來簡單介紹 Git 原理是什么樣的。這4塊內容如下:
git merge原理,當然 Git 原理不僅僅包含這些,想要更深入了解請查看官方教程 https://git-scm.com/book/zh/v2/。
本文內容是我在 GitChat 分享關于Git 的Chat 《Git實用操作手冊》 摘抄一個章節,關于《Git實用操作手冊》其他內容請訪問 https://gitbook.cn/gitchat/activity/5cb46e9dd877c443a183f9d4。
Git 存儲目錄結構介紹
首先我們先從 Git 存儲目錄說起,通過 git init 創建一個空的 Git 倉庫,具體操作如下圖:
創建完成后進入 .git 目錄,如下圖所示:
通過 git config --local 查看 config 文件的變化
我們通過 git config --local 配置僅對于 gitLearn 項目有效,用戶名和郵箱配置如下圖所示:
查看 config 文件,會發現該文件新增用戶信息配置。
Git 是一個內容尋址文件系統 其核心部分是一個簡單的鍵值對數據庫(key-value data store)。 你可以向該數據庫插入任意類型的內容,它會返回一個 40 位字符串鍵,通過該 40 位字符串鍵可以在任意時刻再次檢索(retrieve)該內容。
每次我們進行提交會通過 SHA-1 算法生成一個長度為 40 個字符的校驗和(checksum hash)(也就是我們的 key)然后根據校驗和去獲取我們文件的內容。這種通過唯一標識的 key(也可以理解為內容的地址)去獲取我們的內容的操作就是內容尋址。
Git 的對象
在 Git 中有四種對象分別為:
了解 Git 的對象需要使用如下命令進行查看:
我們創建一個 first.txt 文件,并將其提交到暫存區中。
進入 .git 文件夾下會發現新增了一個 index 文件。
我們可以通過 git ls-files --stage 查看 index 文件的內容。
進入 objects 目錄發現 9c 文件夾名稱+文件名稱 和 index 文件中的一段字符串內容相同。
我們通過 git cat-file -t 9c59e24b8393179a5d712de4f990178df5734d99 我查看該表示對象類型 如下圖所示表示該標識對象類型是 blob。
執行 git commit -m 將 first.txt 文件提交到本地倉庫中。
執行 git log 查看我們的提交記錄。
如下圖所示我們通過 git cat-file -p commitId 查看我們提交的內容。如下圖所示:我們最新一次提交包含了一個 59b06 開頭的 tree 對象。
在 ./git/objects 目錄中可以找到我們對應的文件。
我們通過 git cat-file -p tree對象哈希值,查看該 tree 對象的內容 。如下圖所示顯示就是我們 git add參生的 blob對象。
在通過 git cat-file -p blob對象哈希值,查看我們 blob對象內容,如下圖所示 blob對象 內容就是我們 first.txt 文件的內容。
我們將 first.txt 文件提交到本地倉庫 會產生一個 commit 一個 tree 和一個 blob 對象。
首先我們通過 git log 查看最新的提交是 add a.txt 注釋的 commit 如下圖所示。
通過 git tag -a v1.1 -m ‘add a.txt tag’ 為該 commit 創建一個附注標簽。
在我們的 .git/refs/tags/ 目錄下會新增 v1.1 文件。
v1.1 內容如下:
看到這個你肯定想到了這是一個 Git 對象,我們通過 git cat-file -t 查看這個哈希值對象類型。如下圖所示它是一個 tag。
然后通過 git cat-file -p 查看它的內容,如下圖所示,該tag包含了commit 對象和 標注的信息。
什么是 Git 的引用?
這里的引用我們可以理解成一個書簽,你在閱讀一本書的時候可以為你讀到的部分打上標簽。然后你可以通過這個書簽快速找到你之前閱讀的位置。在 Git 中我們 創建新的 Commit 或者創建分支都會進行一次打標簽的操作。我們各個不同 commit 之間的切換或分支的切換其實就是標簽的切換。
Git 引用的三種類型
在 Git 中有三種類型的的引用 分別是:
HEAD 引用
HEAD 引用原理 我的個人理解是一個 Head 頭指針+當前分支 指向當前最新提交的 commit 對象。我們也可以通過 git reset --hard 來切換我們commit 記錄,切換后的 commit 以前的 commit 記錄就沒有了,不過我們可以通過 git reflog 查詢操作記錄將以前 commit 找回。
為了更好的理解 HEAD,引用建議大家訪問 http://onlywei.github.io/explain-git-with-d3/#zen 執行 Git 相關的操作來理解什么是 HEAD引用。
如下圖所示,我們的 Head頭指針分支 指向 master分支 同時指向最新的 commit e137e。
我們執行一次 commit Head頭指針分支 + master分支 就指向的是最新的提交 896ee 上。
通過 git branch b1 創建新的分支名稱為b1,如下圖所示,我們發現 Head 頭指針還是指向 master 。
當執行 git checkout b1 的時候,如下圖所示,此時 Head 指針指向分支 b1。
我們在分支 b1 上執行 commit Head 指針指向了在該分支下的最新提交 3c7acb。
當執行 git checkout master 是 Head 指針指向了 master 上最新的 commit 896ee。
當執行 git merge b1 的時候,會將 b1分支最新 commit 合并到 master,我們 Head指針 + master 同時指向最新的 commit 3c7ba 上。
通過上面的動態演示,這回對 Head 應用如何切換 commit 切換分支有了一定的理解。
這里非常建議你自己通過訪問
http://onlywei.github.io/explain-git-with-d3/#zen
來親自體驗一下。
接下來我們來通過查看 .git 目錄來介紹 Head 指針是如何實現的。進入 .git 目錄你會發現有一個 HEAD 文件,它的內容是 ref: refs/heads/master,如下圖所示。
refs/heads/master 是具體文件路徑,我們查 refs/heads 目錄下的 master 文件內容,如下圖所示,master 文件內容就是我們最新的 commit。
我們執行 git chekcout demoBranch3。
此時我們的 HEAD 文件內容變成了 ref: refs/heads/demoBranch3。
查看 refs/heads/ 路徑下的 demoBranch3 文件,如下圖所示 demoBranch3 文件記錄是demoBranch3 分支下最新的 commit。
標簽引用是一個特殊的引用,它不像 HEAD 引用可以通過 git checkout 來更改引用的指針指向。標簽引用不會移動它永遠會指向一個 Commit 對象。
標簽引用的演示請參看 Tag 對象原理演示部分。
遠程引用是只讀的我們不能通過切換到遠程引用執行 commit 將提交更新到遠程倉庫中
我們在本地分支執行 push 操作,Git 都會幫我們記錄 push 到遠程分支的最新 comit,當執行push 的時候,如果發現遠程分支最新 commit 和我們本地倉庫記錄最后一次 push 的 commit 不同會報 Note about fast-forwards 異常,如下圖所示:
出現 Note about fast-forwards 我們需要執行 git pull 將遠程最新的 commit 拉取下來 然后再執行 git push 操作 或者 直接執行 git puhs -f。這里強調一下不建議執行 git puhs -f 操作因為會強制將本地的歷史記錄覆蓋到遠程倉庫的歷史記錄。
通過查看 .git 目錄理解遠程引用
在 .git/refs/remotes/origin 文件夾中 HEAD 文件內容表示內容表示遠程分支處于哪個分支。
在 .git/refs/remotes/origin 文件夾中 master 文件內容,表示最后一次 push 到遠程倉庫的commit,如下圖所示:
在 .git/refs/remotes/origin 文件夾中 demoBranch1 文件表示,最后一次 push 到 demoBranch1 分支提交的 commitId。
原文鏈接:https://blog.csdn.net/ljk126wy/article/details/101064186
版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。
工作时间:8:00-18:00
客服电话
电子邮件
admin@qq.com
扫码二维码
获取最新动态