❌ 無法追蹤差異
你無法快速知道 v2 和 v3 之間到底改了哪幾行。
在學任何 Git 指令之前,先搞清楚「Repository」到底是什麼——它不只是一個資料夾,而是 Git 記錄所有版本歷史的核心資料庫。
想像你正在寫一份報告,你可能會這樣做:
這種「手動版本管理」有幾個致命問題:
你無法快速知道 v2 和 v3 之間到底改了哪幾行。
刪錯東西後,如果沒有備份就永遠找不回來。
兩個人同時修改同一份檔案時,誰的版本為準?
Repository(版本庫,簡稱 Repo)是 Git 用來儲存專案所有檔案與版本歷史的地方。一個 Repo 包含:
你實際看到、編輯的檔案所在的資料夾。這是你日常操作的地方。
隱藏在專案根目錄下的資料夾,存放了 Git 的所有版本資料、設定與物件資料庫。這才是 Repo 的「本體」。
.git 資料夾,所有的版本歷史都會消失,但工作目錄中的檔案不會受影響。反過來說,只要 .git 還在,你就能還原任何一個歷史版本。
Git 在 .git/objects/ 中儲存了所有版本資料。這個資料庫由三種基本物件組成:
儲存單一檔案的內容(不含檔名)。每個不同版本的檔案內容都會產生一個新的 blob。
類似資料夾,記錄了檔名與對應的 blob 或子 tree 的關聯。一個 tree 代表某一時刻的目錄結構。
記錄一次提交,指向一個 tree(專案快照)、作者資訊、時間戳記與提交訊息,以及父 commit 的指標。
Git 中的每一個物件都有一個唯一的身份標識——SHA-1 雜湊值,這是一個 40 字元的十六進位字串。
Git 會對物件的「類型 + 大小 + 內容」進行 SHA-1 雜湊運算。
相同的內容永遠產生相同的雜湊值;內容只要差一個字元,雜湊值就完全不同。
你可以用以下指令驗證 Git 的雜湊運算:
$ echo "hello world" | git hash-object --stdin
95d09f2b10159347eece71399a7e2e907ea3df4f
$ echo "hello world!" | git hash-object --stdin
cd0875583aabe89ee197ea133980a9085d08e497
只多了一個驚嘆號,雜湊值就完全改變了。
為什麼用 SHA-1?
c3a2f1b,Git 會自動找到對應的完整 ID。
在工作目錄和版本庫之間,Git 還有一個中間層——Index(暫存區)。它扮演「打包區」的角色:你先選擇要提交哪些變更,然後再一次 commit。
| 層級 | 位置 | 說明 | 對應指令 |
|---|---|---|---|
| 工作目錄 | 你看到的檔案 | 你平常編輯、新增、刪除檔案的地方 | 一般檔案操作 |
| 暫存區(Index) | .git/index |
暫時存放「這次要 commit」的變更清單 | git add |
| 版本庫 | .git/objects/ |
所有已提交的版本快照,永久保存 | git commit |
Git 是分散式版本控制,每個開發者的電腦上都有一份完整的版本庫。
存在你自己電腦上的 .git 目錄。你可以在完全離線的情況下進行 commit、查閱歷史、建立分支。
存在伺服器上(例如 GitHub)的版本庫。用來同步團隊成員的工作成果,透過 push 與 pull 進行交換。
建立一個新資料夾,執行 git init,然後觀察 .git 目錄中有哪些東西。
$ mkdir my-first-repo
$ cd my-first-repo
$ git init
$ ls -la .git/
用 git hash-object 測試不同內容產生的雜湊值,驗證「相同內容 = 相同 ID」。
$ echo "test" | git hash-object --stdin
$ echo "test" | git hash-object --stdin
$ echo "test2" | git hash-object --stdin
git init 指令背後做了什麼。.git 目錄的每一個子目錄與檔案。