Git 和 Git Flow 是什麼?如何應用?
2023年2月5日
假如你今天在開發一個重要功能,結果團隊中的其他人更新了一段程式碼,你同步後發現整個專案都跑不起來了。又或者,另一位團隊成員正在修復線上的緊急問題,但這些修改又跟你的程式碼產生衝突,讓程式跑不起來。這類混亂的情況,是在沒有適當版本控制策略的團隊中,經常會發生的。
而 Git 和 Git Flow 就是為了解決這類問題而生。讓我們透過這篇文章,來了解如何透過 Git 與 Git Flow 來讓軟體團隊協作變得更有條理。
Git 是什麼?
Git 是一個分散式版本控制系統,它讓開發團隊能用非常簡單的方式管理程式碼庫。雖然 Git 會被用來追蹤檔案變化,但 Git 背後的運作方式,其實會更貼近「快照」的思考方式。
讓我們用一個具體的例子來理解這個概念。假設今天我們要開發一個簡單的網站,在最開始有兩個初始檔案:index.html
和 style.css
。
版本 1 版本 2 版本 3
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ 專案 │ │ 專案 │ │ 專案 │
│ ┌──────────┐ │ │ ┌──────────┐ │ │ ┌──────────┐ │
│ │index.html│ │ + │ │index.html│ │ + │ │index.html│ │
│ │style.css │ │ │ │ (ref v1) │ │ │ │ (ref v1) │ │
│ └──────────┘ │ │ │style.css │ │ │ │style.css │ │
└──────────────┘ │ │ (ref v1) │ │ │ │ (新 v3) │ │
│ │about.html│ │ │ │about.html│ │
│ │script.js │ │ │ │ (ref v2) │ │
│ └──────────┘ │ │ │script.js │ │
└──────────────┘ │ │ (ref v2) │ │
│ └──────────┘ │
└──────────────┘
初始檔案 新增檔案 更新 style.css
版本 1:我們建立了初始的網站檔案— index.html
放首頁內容,style.css
放初始的樣式。Git 會為整個專案拍一個完整的快照。
版本 2:我們擴展了網站功能,新增 about.html
和 script.js
。由於 index.html
和 style.css
沒有變化,Git 只需要參照版本 1 的內容。只有新檔案會被儲存為新的內容。
版本 3:我們修改了 style.css
來改善設計。index.html
還是參照版本 1,about.html
和 script.js
參照版本 2。只有更新的 style.css
會被儲存為新內容。
可以看到,這種快照的形式,跟追蹤個別檔案變化不太一樣。而也因為 Git 在每個時間點都會捕捉專案的完整狀態,我們可以很輕易地跳到任何之前的版本。
Git 的三個狀態:你的程式碼存在哪裡?
在 Git 中,你的檔案可以存在三種不同的狀態,理解這個概念可以幫你避免很多麻煩。
工作目錄 索引 (Git 暫存區) 儲存庫
┌─────────────────┐ ┌────────────────────┐ ┌─────────────────┐
│ │ │ │ │ │
│ ┌─────────────┐ │ │ ┌─────────────┐ │ │ ┌─────────────┐ │
│ │ 已修改檔案 │ │ │ │ 已暫存檔案 │ │ │ │ 已提交快照 │ │
│ │ │ │ │ │ │ │ │ │ │ │
│ │ │ │ │ │ │ │ │ │ │ │
│ │ *.html │ │ │ │ README.md │ │ │ │ v1.0 ────── │ │
│ │ *.css │ │ │ │ style.css │ │ │ │ v1.1 ────── │ │
│ │ *.js │ │ │ │ │ │ │ │ v1.2 ────── │ │
│ └─────────────┘ │ │ └─────────────┘ │ │ └─────────────┘ │
│ │ │ │ │ │
└─────────────────┘ └────────────────────┘ └─────────────────┘
│ │ │
│ git add <file> │ git commit │
└───────────────────────┼───────────────────────┘
│
"git add ." 暫存所有變更
工作目錄:這是你實際編輯檔案的地方。當你在編輯器中打開 index.html
並做修改時,你就是在工作目錄中操作。這些變更只存在於你的電腦上,除非你對它們做些什麼。
索引 (Git 暫存區):把這個想像成一個準備區。當你對修改滿意,想要把它們包含在下一個快照中時,你可以用 git add
把它們加到索引中。這就像在說「我準備好要提交這些特定的變更,但其他的還沒準備好」。
儲存庫:這是 Git 永久儲存快照的地方。當你執行 git commit
時,Git 會把索引中的所有內容拿來建立一個新的提交物件到儲存庫中。
你可能會問「為什麼要有索引?」想像一下,你同時在開發兩個不同的功能,修改了五個檔案。你想要現在就提交功能 A 的工作,但功能 B 還沒準備好。索引讓你可以選擇性地選擇哪些變更要放進每次提交中,保持你的專案歷史乾淨且有邏輯。
Git Flow 是什麼?
瞭解了 Git 的運作方式後,現在讓我們面對一個更大的挑戰:當有多個開發者同時在處理不同功能、bug 修復、以及版本發布時,我們該如何組織工作?
考慮一個典型的開發情境:
- 一個開發者正在開發新的使用者註冊功能
- 另一個開發者正在修復線上的重要安全性問題
- 你正在準備下個月的版本發布
- 你的團隊主管正在審查和測試功能,準備上線
我們要如何防止這些不同的工作流程互相干擾?如何確保緊急的 bug 修復不會意外包含尚未完成的功能?
Git Flow 透過結構化的分支策略提供了解決方案。就像為不同類型的工作準備不同的工作空間。
Git Flow 分支模型
Master ●────────●────────●────────●────────●
│ │ │ │ │
│ │ │ │ │
│ │ v1.0 │ v1.1 │ v2.0 │
│ │ │ │ │
│ │ │ │ │
Hotfix │ │ ●────────┘ │
│ │ ╱ │
│ │ ╱ │
│ │ ╱ │
│ │ ╱ │
Release │ ●───╱──────────────────────┘
│ ╱
│ ╱
│ ╱
│ ╱
Develop ●───●────●────●────●────●────●────●
│ │ │ │ │ │ │
│ │ │ │ │ │ │
Feature A │ ●────●────┘ │ │ │
│ ╱ ╱ │ │ │
│ ╱ ╱ │ │ │
Feature B │ ╱ ╱ ●────●────┘
│ ╱ ╱ ╱ ╱
│ ╱ ╱ ╱ ╱
│ ╱ ╱ ╱ ╱
│ ╱ ╱ ╱ ╱
●╱ ╱ ╱ ╱
╱ ╱ ╱
╱ ╱ ╱
╱ ╱ ╱
╱ ╱ ╱
╱ ╱ ╱
╱ ╱ ╱
╱ ╱ ╱
● ╱ ╱
╱ ╱
╱ ╱
╱ ╱
╱ ╱
╱ ╱
╱ ╱
╱ ╱
●────●
圖例:
● = 提交/合併點
╱ = 分支建立
── = 分支延續
五種分支類型:各有各的用途
讓我們來瞭解 Git Flow 中每種分支類型的作用,以及什麼時候會用到它們。
Master 分支:你的生產環境程式碼 master 分支代表目前正在線上運行的版本。master 上的每個提交都應該是穩定、經過測試、準備好讓使用者使用的。把它想成你的「黃金版本」——這是客戶實際使用的版本。我們什麼時候會動到 master?只有在準備發布到生產環境時才會。我們絕不直接在 master 上開發,因為我們希望隨時保持它的穩定性。
Develop 分支:整合發生的地方 develop 分支是我們整合已完成功能、準備下一次發布的地方。就像一個中介區域,我們把不同的工作合併在一起,看看它們如何協作。所有功能開發都從 develop 開始,功能完成後也會合併回 develop。這個分支通常應該是穩定的,但在整合新工作時偶爾可能會出現問題。
Feature 分支:個人開發工作空間 這裡是真正開發發生的地方。當有人開始開發使用者註冊功能時,他們會建立一個叫做 feature/user-registration
的功能分支。這給了他們一個完全獨立的工作空間,可以實驗、弄壞東西、反覆修改,而不會影響到其他人。功能分支總是從 develop 分支出來,完成後也會合併回 develop。
Release 分支:準備上線 當我們在 develop 中累積了足夠的功能,準備發布時,我們會建立像 release/1.2.0
這樣的發布分支。這個分支是我們進行最終測試、bug 修復、以及準備工作的地方。為什麼不直接從 develop 發布?因為當我們在準備 1.2.0 版本時,其他開發者可能正在加入預定給 1.3.0 版本的功能。發布分支給我們一個穩定的快照,讓我們可以在上線前進行最後的打磨。
Hotfix 分支:緊急生產修復 有時候線上環境出問題,我們需要立即修復。我們不能等到下一個計劃的發布。這時就需要 hotfix 分支。Hotfix 分支是唯一直接從 master(生產環境)分支出來的分支類型。當有人發現重要的安全漏洞時,他們會建立 hotfix/security-vulnerability
,修復它,然後合併回 master 和 develop。
什麼時候用 Git Flow(什麼時候不用)
Git Flow 並不適合每個團隊或專案。我們來想想什麼時候使用它比較合適。
Git Flow 適合的情況:
- 你有計劃性的發布,而不是持續部署
- 多個開發者同時工作
- 需要維護穩定的生產分支
- 你的團隊能夠處理多種分支類型的複雜度
- 你在開發有明確發布週期的傳統軟體
考慮使用更簡單的替代方案:
- 小團隊(1-3 個開發者)進行持續部署
- 你每天部署多次
- 你的團隊剛開始學習 Git
- 你在開發簡單的專案或原型
對於小團隊,GitHub Flow 可能更適合——它只使用功能分支和 master,直接從 master 部署。
下一步該怎麼做
瞭解了五種分支類型和它們的作用後,你對 Git Flow 如何組織開發工作就有了完整的概念。master 和 develop 分支提供穩定的基礎,而 feature、release、和 hotfix 分支則處理特定類型的工作,彼此不會干擾。這種結構化的方法把混亂的程式碼協作轉變成有組織的團隊合作。
但瞭解理論只是開始。成功實施 Git Flow 的關鍵是要配合你團隊的具體需求。當你有計劃性的發布、多個開發者、需要維護穩定的生產程式碼時,使用 Git Flow。對於進行持續部署的小團隊,GitHub Flow 這樣的簡單替代方案可能更適合。如果你的團隊還沒有採用 Git Flow,建議從小規模開始——先在一個小專案上試試看,然後逐漸引入到團隊中。記住,Git Flow 是工具,不是規則。適應你的工作流程,但要確保團隊中的每個人都理解並遵循一致的策略。
加入 E+ 成長計畫
如果你覺得這篇內容有幫助,喜歡我們的內容,歡迎加入 ExplainThis 籌辦的 E+ 成長計畫,透過每週的深度主題文,以及技術討論社群,讓讀者在前端、後端、軟體工程的領域上持續成長。