GitLab 工作原理詳解
1. Git 的數據模型
Git 是一個分布式版本控制系統,其核心數據模型基于對象存儲。每個提交(commit)在文件系統上以對象的形式存儲,這些對象包括:
- ?Blob 對象?:存儲文件內容。
- ?Tree 對象?:存儲目錄結構,指向 Blob 對象和子 Tree 對象。
- ?Commit 對象?:存儲提交信息,包括作者、提交時間、提交信息、父提交等。
1.1 Blob 對象
Blob 對象用于存儲文件內容。每個 Blob 對象包含文件的內容,并通過 SHA-1 哈希值唯一標識。
- ?創建 Blob 對象?:當文件被添加到暫存區時,Git 會計算文件內容的 SHA-1 哈希值,并將文件內容存儲為 Blob 對象。
bash<svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-insert-line1"></use></svg><svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-copy-line"></use></svg><svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-additive-code-file-line"></use></svg>
git add <file> - ?存儲?:Blob 對象存儲在
.git/objects目錄下,路徑為SHA-1 哈希值的前兩位/后38位。例如,文件內容的 SHA-1 哈希值為abc123...,則存儲路徑為.git/objects/ab/c123...。
1.2 Tree 對象
Tree 對象用于存儲目錄結構,指向 Blob 對象和子 Tree 對象。每個 Tree 對象包含目錄中的文件和子目錄的信息。
- ?創建 Tree 對象?:當文件被添加到暫存區時,Git 會創建一個 Tree 對象,記錄當前目錄結構。
bash<svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-insert-line1"></use></svg><svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-copy-line"></use></svg><svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-additive-code-file-line"></use></svg>
git add <file> - ?存儲?:Tree 對象也存儲在
.git/objects目錄下,路徑為SHA-1 哈希值的前兩位/后38位。例如,Tree 對象的 SHA-1 哈希值為def456...,則存儲路徑為.git/objects/de/f456...。
1.3 Commit 對象
Commit 對象用于存儲提交信息,包括作者、提交時間、提交信息、父提交等。每個 Commit 對象指向一個 Tree 對象,表示提交時的目錄結構。
-
?創建 Commit 對象?:當提交代碼時,Git 會創建一個新的 Commit 對象,包含以下信息:
- 作者信息
- 提交時間
- 提交信息
- 指向當前 Tree 對象的哈希值
- 指向父 Commit 對象的哈希值
bash<svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-insert-line1"></use></svg><svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-copy-line"></use></svg><svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-additive-code-file-line"></use></svg>git commit -m "提交信息" -
?存儲?:Commit 對象也存儲在
.git/objects目錄下,路徑為SHA-1 哈希值的前兩位/后38位。例如,Commit 對象的 SHA-1 哈希值為ghi789...,則存儲路徑為.git/objects/gh/i789...。
2. 本地代碼暫存
在 Git 中,代碼暫存的過程涉及將文件內容存儲為 Blob 對象,并將這些 Blob 對象組織成 Tree 對象。
- ?添加文件到暫存區?:使用
git add命令將文件內容存儲為 Blob 對象,并更新索引文件(.git/index)。bash<svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-insert-line1"></use></svg><svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-copy-line"></use></svg><svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-additive-code-file-line"></use></svg>git add <file> - ?索引文件?:索引文件(.git/index)記錄了暫存區的文件狀態,包括文件路徑、文件內容的哈希值(SHA-1)等。
3. 代碼提交
提交代碼時,Git 會創建一個新的 Commit 對象,并將當前的 Tree 對象作為 Commit 對象的樹根。
-
?創建 Commit 對象?:提交時,Git 會生成一個新的 Commit 對象,包含以下信息:
- 作者信息
- 提交時間
- 提交信息
- 指向當前 Tree 對象的哈希值
- 指向父 Commit 對象的哈希值
bash<svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-insert-line1"></use></svg><svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-copy-line"></use></svg><svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-additive-code-file-line"></use></svg>git commit -m "提交信息" -
?更新分支指針?:提交后,Git 會更新當前分支的指針,使其指向新的 Commit 對象。
4. 分支管理
分支在 Git 中是輕量級的指針,指向某個 Commit 對象。每個分支都有一個獨立的指針,記錄當前分支的最新提交。
- ?創建分支?:創建分支時,Git 會創建一個新的指針,指向當前分支的最新提交。
bash<svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-insert-line1"></use></svg><svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-copy-line"></use></svg><svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-additive-code-file-line"></use></svg>
git branch <new-branch> - ?切換分支?:切換分支時,Git 會更新工作目錄和索引文件,使其與目標分支的最新提交一致。
bash<svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-insert-line1"></use></svg><svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-copy-line"></use></svg><svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-additive-code-file-line"></use></svg>
git checkout <branch>
5. 沖突解決
沖突發生在多個分支對同一文件的同一部分進行修改時。Git 在合并時會檢測沖突,并在沖突文件中插入沖突標記。
- ?沖突標記?:沖突文件中會插入
<<<<<<<,=======, 和>>>>>>>標記,分別表示當前分支的修改、分隔符和合并分支的修改。plaintext<svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-insert-line1"></use></svg><svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-copy-line"></use></svg><svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-additive-code-file-line"></use></svg><<<<<<< HEAD 當前分支的修改 ======= 合并分支的修改 >>>>>>> <source-branch> - ?手動解決沖突?:開發者需要手動編輯沖突文件,刪除沖突標記,保留正確的代碼。
- ?標記沖突已解決?:解決沖突后,將文件添加到暫存區,標記沖突已解決。
bash<svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-insert-line1"></use></svg><svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-copy-line"></use></svg><svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-additive-code-file-line"></use></svg>
git add <file> - ?完成合并?:提交合并后的代碼,生成一個新的 Commit 對象。
bash<svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-insert-line1"></use></svg><svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-copy-line"></use></svg><svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-additive-code-file-line"></use></svg>
git commit -m "解決沖突"
6. Merge 和 Rebase
-
?Merge?:合并兩個分支時,Git 會創建一個新的 Commit 對象,包含兩個父 Commit 對象的哈希值。這個新的 Commit 對象稱為合并提交。
bash<svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-insert-line1"></use></svg><svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-copy-line"></use></svg><svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-additive-code-file-line"></use></svg>git merge <source-branch>- ?合并過程?:
- Git 找到兩個分支的最近共同祖先(Common Ancestor)。
- 比較當前分支和合并分支的差異。
- 生成新的 Tree 對象,包含合并后的目錄結構。
- 創建新的 Commit 對象,包含兩個父 Commit 對象的哈希值。
- 更新當前分支的指針,使其指向新的 Commit 對象。
- ?合并過程?:
-
?Rebase?:Rebase 操作將一個分支的更改應用到另一個分支的最新提交上,保持線性的提交歷史。Rebase 會創建新的 Commit 對象,覆蓋原有的提交歷史。
bash<svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-insert-line1"></use></svg><svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-copy-line"></use></svg><svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-additive-code-file-line"></use></svg>git rebase <base-branch>- ?Rebase 過程?:
- Git 找到兩個分支的最近共同祖先(Common Ancestor)。
- 將當前分支的 Commit 對象從共同祖先開始,逐個應用到目標分支的最新提交上。
- 生成新的 Commit 對象,覆蓋原有的 Commit 對象。
- 更新當前分支的指針,使其指向新的 Commit 對象。
- ?Rebase 過程?:
7. 分支對比
-
?本地對比?:使用
git diff命令對比兩個分支的差異。Git 會計算兩個分支的最新提交之間的差異,生成差異文件。bash<svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-insert-line1"></use></svg><svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-copy-line"></use></svg><svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-additive-code-file-line"></use></svg>git diff <branch1> <branch2>- ?對比過程?:
- Git 找到兩個分支的最新 Commit 對象。
- 比較兩個 Commit 對象的 Tree 對象,生成差異文件。
- ?對比過程?:
-
?GitLab 界面對比?:在 GitLab 界面中,選擇兩個分支進行對比,GitLab 會調用 Git 的差異計算功能,生成詳細的代碼差異。
8. 遠程倉庫管理
-
?推送代碼?:將本地提交的代碼推送到遠程倉庫時,Git 會將新的 Commit 對象和相關的 Tree 對象、Blob 對象推送到遠程倉庫。
bash<svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-insert-line1"></use></svg><svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-copy-line"></use></svg><svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-additive-code-file-line"></use></svg>git push <remote> <branch>- ?推送過程?:
- Git 找到本地分支的最新 Commit 對象。
- 將新的 Commit 對象、Tree 對象和 Blob 對象推送到遠程倉庫。
- 更新遠程分支的指針,使其指向新的 Commit 對象。
- ?推送過程?:
-
?拉取代碼?:從遠程倉庫拉取最新的代碼到本地時,Git 會下載新的 Commit 對象和相關的 Tree 對象、Blob 對象,并更新本地分支指針。
bash<svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-insert-line1"></use></svg><svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-copy-line"></use></svg><svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use xlink:href="#yunxiao-additive-code-file-line"></use></svg>git pull <remote> <branch>- ?拉取過程?:
- Git 從遠程倉庫下載最新的 Commit 對象、Tree 對象和 Blob 對象。
- 更新本地分支的指針,使其指向新的 Commit 對象。
- 如果存在沖突,Git 會提示解決沖突。
- ?拉取過程?:
9. 代碼審查和合并請求
- ?創建合并請求?:在 GitLab 中,創建合并請求時,GitLab 會記錄源分支和目標分支的信息,并生成差異文件。其他開發者可以審查這些差異文件,提出修改意見或批準合并。
- ?代碼審查?:審查者可以在合并請求頁面查看代碼差異,添加評論和建議。GitLab 會記錄這些評論和建議,幫助開發者改進代碼。
- ?合并合并請求?:當合并請求被批準后,GitLab 會執行合并操作,生成新的 Commit 對象,并更新目標分支的指針。
10. 代碼保護和權限管理
- ?代碼保護?:在 GitLab 中,設置代碼保護規則時,GitLab 會記錄這些規則,并在推送和合并操作時進行檢查。如果操作不符合保護規則,GitLab 會拒絕操作。
- ?權限管理?:GitLab 提供了細粒度的權限管理,可以為不同的用戶和組分配不同的權限。權限管理信息存儲在 GitLab 的數據庫中,用于控制用戶對項目的訪問和操作。
總結
GitLab 通過 Git 的數據模型和操作機制,提供了強大的代碼管理功能。每個提交在文件系統上以對象的形式存儲,分支管理通過輕量級的指針實現,合并和沖突解決通過生成新的 Commit 對象和手動編輯沖突文件實現。遠程倉庫管理通過推送和拉取操作同步代碼,代碼審查和合并請求通過 GitLab 的界面和后端服務實現。代碼保護和權限管理通過規則和數據庫記錄實現,確保代碼的安全和可控。