2026-06-11 · 版本控制 · 分散式 · 快照思維 · 三大區域
沒有版本控制時,我們常用「複製整個資料夾」來保存進度,於是出現這種畫面:
版本控制系統(VCS)就是要有系統地解決這些問題,核心能力有四項:
| 需求 | VCS 提供的能力 |
|---|---|
| 記錄歷史 | 每次有意義的變更存成一個「版本」,附帶時間、作者、說明 |
| 回溯 | 隨時回到任何一個歷史版本,或比較版本之間的差異 |
| 分支實驗 | 開一條獨立線路嘗試新點子,不影響主線,失敗就丟掉 |
| 多人協作 | 多人各自修改,再有規則地合併,並追蹤每一行是誰改的 |
VCS 分兩大類。早期的 SVN、CVS 是集中式:只有一台中央伺服器保存完整歷史,每個人手上只是「工作副本」。Git 則是分散式:每一次 clone 都會把整個版本庫(含全部歷史)複製到本機。
commit(提交到本機)和 push(送到遠端)是兩個分開的動作——提交不需要網路,只有要分享給別人時才需要連線。
既然 clone 把整個版本庫(含全部歷史)都複製下來了,為什麼 clone 之後只看得到主分支?
「整座版本庫都複製下來」和「看得到幾個分支」是兩件事。clone 確實把所有物件(全部歷史)與所有分支指標都抓到本機,只是分兩種存放方式:
‧ 遠端追蹤分支(refs/remotes/origin/*):origin/main、origin/dev… 全部都在。
‧ 本地分支(refs/heads/*):clone 只自動建立一個(遠端的預設分支,通常是 main)。
所以「只看到 main」是因為 git branch 只列本地分支。其他分支沒有不見,它們以 origin/xxx 的形式都在硬碟裡:
git branch # 只看到 * main ← 本地分支
git branch -r # origin/main, origin/dev … ← 全都在
git branch -a # 兩者都列出
要切到別的分支,資料早在本機,只要建一個本地分支去指它即可(離線就能做):
git switch dev # 新版 Git 自動對應 origin/dev
git checkout -b dev origin/dev # 舊寫法
為什麼這樣設計:工作目錄一次只能呈現一個 commit 的內容,所以 clone 後只「簽出」一個分支;其餘分支保留為 origin/* 追蹤分支,避免汙染本地命名空間,需要時再認領。
一句話:clone 把整座倉庫搬回家了,只是預設只幫你打開其中一個房間(main);其他房間的門都在,推開即可。
多數舊式 VCS 用差異(delta)思維:記錄每個檔案相對前一版「改了哪幾行」,要還原某版本就得把一連串差異疊加回去。
Git 用快照(snapshot)思維:每次提交,Git 記錄的是當下所有檔案的完整狀態。沒有變動的檔案,不會重複存,而是用一個指標指向前一版的內容(細節在第 2 章)。
git diff 看到的「差異」,其實是 Git 即時比對兩張快照算出來的結果,而非它儲存的形式。
使用 Git 時,你的檔案隨時處在三個區域之一。幾乎所有日常指令,本質都是把檔案在這三個區域之間搬動。先記住這張圖,後面章節都會回到它。
| 重點 | 一句話記住 |
|---|---|
| VCS 的價值 | 有系統地記錄歷史、回溯、分支實驗、多人協作 |
| 分散式 | 每個 clone 都是完整版本庫,可離線提交 |
| 快照思維 | Git 存的是每次提交的完整快照,不是差異 |
| 三大區域 | 工作目錄 →(add)→ 暫存區 →(commit)→ 版本庫 |
.git 裡究竟是用什麼物件、如何儲存的。