Git 的運作方式——快照、分支與歷史紀錄

Git 的運作方式,畫在一張互動畫布上:工作目錄、暫存區、本機與遠端儲存庫,以及提交如何堆疊出一段共用的歷史紀錄。

Git 是一套以快照為基礎的版本控制系統:每一次提交都是儲存庫的一張完整圖像,並連向它的父提交,而分支只是沿著歷史紀錄移動的指標。

Git 的運作方式——快照、分支與歷史紀錄

The interactive FlowJam canvas for this explanation — every lane, row and arrow above is a real QueryChart diagram you can open and edit.

How to read this visual

  • 由左至右讀這三個直欄:編輯、提交、分享。
  • 四個泳道群組就是一條管線:工作目錄到暫存區、到本機、再到遠端——每一個箭頭都把這項改動推近共用一步。
  • 「兩個人改動了同樣的行?」這個決策是全圖唯一的分岔,而兩個出口最後都匯合到共用的歷史紀錄。

編輯與暫存

「開發者在工作目錄裡編輯檔案」是尚未提交的現實——磁碟上的檔案,還未成為歷史紀錄的一部分。「git add 把改動移入暫存區」是刻意設置的中間一步:暫存讓你由挑選出來的改動組成一次提交,而不是把你碰過的所有東西一併提交。這張圖解把它們分成各自的群組,因為這種兩步式的提交,正是 Git 精準之處。

提交這張快照

「git commit 為已暫存的改動製作快照」就是一項改動變成永久的地方。「Git 把這次提交連同一個指向父提交的指標一起儲存」把那張圖畫得明明白白——除了第一次以外,每一次提交都指名它前面的那一次,而這正是歷史紀錄只增不改、可供稽核的原因。「分支指標移到新的提交上」完成了整個動作:分支只是一個指標,所以在一條分支上提交,就是把那個指標往前移。提交本身完全不在乎自己身處哪一條分支。

共用歷史紀錄

「git push 把這些提交送到遠端」由「本機儲存庫」跨進「遠端儲存庫」群組——這是資料唯一離開你機器的地方。「遠端儲存庫記下新的歷史紀錄」就是那份共用的副本,而「兩個人改動了同樣的行?」描繪的是合併:除非同樣的行被編輯過,否則 Git 會自動合併分歧的歷史紀錄;若真的重疊,「合併衝突——由開發者人手解決」就把人的決定明確畫出來,然後才由「歷史紀錄已共用而且是最新的」把流程收結。

Key relationships and takeaways

  • 一次提交是一張連向父提交的完整快照,而這正是歷史紀錄成為一張只增不改的圖的原因。
  • 分支是一個指向某次提交的指標,不是裝著改動的容器——正因如此,建立與切換分支的成本都很低。
  • 暫存是刻意設置的中間一步,讓你選擇一次提交裡到底包含甚麼。
  • Git 是分散式的:每個人在本機都持有完整的歷史紀錄,而 push 與 pull 只交換缺少的那些部分。
  • 衝突是例外,不是常態——而一旦發生,就由人明確地去解決。

When to use this visual

  • 向一支只把 Git 當成一連串指令來用的團隊,講解快照這個模型。
  • 用指標模型而不是死記硬背的指令,去解釋分支、合併與衝突。
  • 以歷史紀錄實際的結構,為一次團隊提交與分支流程的覆核定下基礎。

運作方式

  1. 描出你團隊真實的工作流程

    在那些方框上標註你團隊實際使用的指令——功能分支、Pull Request、rebase 相對於 merge——讓這張圖記錄的是你們的實務,而不是教科書的。

  2. 加上分支模型

    在本機儲存庫群組裡插入功能分支與主分支兩列,並在它們之間畫出合併的箭頭,最後通向共用的歷史紀錄。

  3. 畫出 Pull Request 這道關卡

    在本機推送與遠端記錄之間加一個決策:一次覆核加上 CI 檢查,必須通過之後那條分支才可以併入 main。

  4. 加上復原的路徑

    把復原用的分岔路徑也畫進去——還原一次提交、修改提交訊息、重設到較早的狀態——每一條都以一個明確的結果結束,因為復原本來就佔了真實 Git 用法的一半。

常見問題

甚麼是 Git?它與其他版本控制有甚麼分別?

Git 是一套以快照為基礎的分散式版本控制系統。每一次提交儲存的是儲存庫的一張完整圖像,加上一個指向父提交的指標,而不只是一份檔案改動清單。由於每一位開發者在本機都持有完整的歷史紀錄,大部分操作都可以離線進行,而協作就只是與遠端交換提交這回事。

Git 裡的分支是甚麼?

分支是一個可以移動、指向某次提交的指標。當你在一條分支上提交,指標就前移到新的提交上;提交本身並不知道、也不在乎自己身處哪一條分支。這就是建立一條分支可以即時完成的原因,也是切換分支只改變你的工作目錄顯示哪一張快照的原因。

Git 為甚麼要有一個暫存區?

暫存區讓你有意識地組成一次提交。你可以編輯好幾個檔案,只把屬於同一件事的那些放入暫存,然後提交這個選擇——把無關的工作留在未提交的狀態。工作目錄、暫存區與儲存庫是三個各自獨立的狀態,而這正是這張圖解所畫的那條管線。

Git 怎樣解決合併衝突?

當兩條分支改動的是不同的檔案,或者不同的行,Git 會自動合併。當它們改動同樣的行,Git 猜不出哪一個版本才對,於是把衝突標示出來,交由人去選擇。衝突是一個決定,不是一次失敗——這也是這張圖解把它導向一個明確的解決步驟,之後歷史紀錄才共用出去的原因。

用 QueryChart(FlowJam)編輯這張圖解

把上面這張 Git 畫布開啟為你自己的圖表——把泳道改名為你的工作流程,並描出你自己的歷史紀錄。

用 QueryChart(FlowJam)編輯這張圖解

互動圖解的更多內容