☕ NEW! 完成新手任務即可參加抽獎!LINE 星巴克禮券等你拿,名額有限!        🎉 推廣活動:邀請好友註冊 DevLearn,累積推薦抽 LINE 星巴克禮券! 活動詳情 →        🔥 活動期間 2026/4/1 - 5/31 |已有 0 人參加       
Git 初學

分支與合併

什麼是分支?

💡 比喻:平行宇宙 想像你在寫一篇小說,突然想試試「主角變壞人」的劇情, 但又不想改壞原本的故事。 分支就像開啟一個平行宇宙—— 你可以在新宇宙裡隨便改, 改得好就合併回主宇宙,改得爛就丟掉,完全不影響原本的故事。

主線(main)    ──●──●──●──●──●──●──
                        \         ↗
功能分支(feature)      ●──●──●
                       在平行宇宙開發新功能

分支基本操作

建立與切換分支

# 查看所有分支(* 標記目前所在分支)
git branch  # 列出本地所有分支

# 建立新分支
git branch feature/login  # 建立一個叫 feature/login 的新分支

# 切換到新分支(傳統方式)
git checkout feature/login  # 切換到 feature/login 分支

# 切換到新分支(新語法,推薦)
git switch feature/login  # 切換到 feature/login 分支(更直覺)

# 建立並同時切換(傳統方式)
git checkout -b feature/signup  # 建立 feature/signup 並立即切換過去

# 建立並同時切換(新語法,推薦)
git switch -c feature/signup  # 建立 feature/signup 並立即切換過去

# 查看所有分支(包含遠端)
git branch -a  # 列出本地和遠端的所有分支

# 刪除已合併的分支
git branch -d feature/login  # 刪除已合併的分支(安全刪除)

# 強制刪除分支(未合併也刪)
git branch -D feature/abandoned  # 強制刪除分支(即使未合併)

# 重新命名分支
git branch -m old-name new-name  # 把分支 old-name 改名為 new-name

分支命名慣例

常用的分支命名規則:
┌───────────────────────────────────────────────────┐
│ 類型             │ 命名格式              │ 範例                    │
├───────────────────────────────────────────────────┤
│ 功能開發         │ feature/功能名稱       │ feature/login           │
│ Bug 修復         │ bugfix/問題描述        │ bugfix/login-crash      │
│ 緊急修復         │ hotfix/問題描述        │ hotfix/security-patch   │
│ 版本發佈         │ release/版本號         │ release/v1.2.0          │
│ 實驗性功能       │ experiment/描述        │ experiment/new-ui       │
└───────────────────────────────────────────────────┘

Merge 合併

💡 比喻:樹枝嫁接 Merge 就像把一根樹枝嫁接回主幹, 兩邊的「生長紀錄」都會保留下來, 歷史中可以清楚看到分支從哪裡分出、又在哪裡合併。

基本合併操作

# 步驟 1:先切換到要合併「進去」的目標分支
git switch main  # 切換到 main 分支

# 步驟 2:執行合併
git merge feature/login  # 把 feature/login 的變更合併進 main

# 合併後刪除分支(保持整潔)
git branch -d feature/login  # 刪除已合併的 feature/login 分支

合併的兩種情況

Fast-forward 合併(快進合併):
main 沒有新的 commit,直接「快進」到 feature 的最新位置

合併前:
main     ──●──●
                \
feature          ●──●──●

合併後(fast-forward):
main     ──●──●──●──●──●
                        ↑
                   直接快進到這裡

---

Three-way 合併(三方合併):
main 也有新的 commit,需要建立一個「合併 commit」

合併前:
main     ──●──●──●──●
                \
feature          ●──●──●

合併後(three-way merge):
main     ──●──●──●──●──●──M  ← 合併 commit
                \         ↗
feature          ●──●──●
# 強制建立合併 commit(即使可以 fast-forward)
git merge --no-ff feature/login  # 保留分支歷史,建立合併 commit

# 查看合併歷史圖形
git log --oneline --graph --all  # 圖形化顯示分支和合併的歷史

Rebase 變基

💡 比喻:搬家重蓋 Rebase 就像把你蓋在舊地基上的房子, 整棟搬到新地基上重蓋。 結果看起來就像是你一開始就蓋在新地基上一樣, 歷史紀錄變得很乾淨、一條直線。

Rebase 前:
main     ──●──●──A──B
                \
feature          ●──●──●

Rebase 後(把 feature 搬到 main 最新的 B 上面):
main     ──●──●──A──B
                      \
feature                ●'──●'──●'
                       重新套用在 B 之後
# 在 feature 分支上執行 rebase
git switch feature/login  # 先切換到 feature 分支
git rebase main  # 把 feature 的 commit 重新套用在 main 最新的基礎上

# 然後切換回 main 合併(這時會 fast-forward)
git switch main  # 切換回 main
git merge feature/login  # 因為已經 rebase 過,會是 fast-forward

Merge vs Rebase 比較

┌──────────────┬──────────────────────┬──────────────────────┐
│              │ Merge                │ Rebase               │
├──────────────┼──────────────────────┼──────────────────────┤
│ 歷史紀錄     │ 保留分支結構         │ 線性歷史(一條線)   │
│ 安全性       │ 不會改寫歷史         │ 會改寫 commit hash   │
│ 適用場景     │ 公開分支/團隊協作    │ 個人分支/整理歷史    │
│ 比喻         │ 樹枝嫁接             │ 搬家重蓋             │
│ 黃金規則     │ 隨時都可以用         │ 不要對已推送的分支用 │
└──────────────┴──────────────────────┴──────────────────────┘

解決合併衝突

💡 比喻:兩人同時改同一份文件 你和同事同時改了同一行程式碼, Git 無法決定要用誰的版本, 所以它把兩個版本都標出來,讓你手動選擇。

衝突發生時的樣子

# 嘗試合併時出現衝突
git merge feature/login  # Git 回報:CONFLICT (content): Merge conflict in Program.cs
// Program.cs 中衝突的樣子:
<<<<<<< HEAD
// 這是 main 分支的版本
var greeting = "你好,歡迎回來!";  // main 的歡迎訊息
=======
// 這是 feature/login 分支的版本
var greeting = "嗨,歡迎登入!";  // feature 的歡迎訊息
>>>>>>> feature/login

解決衝突的步驟

# 步驟 1:查看哪些檔案有衝突
git status  # 顯示「both modified」的檔案就是有衝突的

# 步驟 2:打開有衝突的檔案,手動編輯
# 移除 <<<<<<<、=======、>>>>>>> 標記
# 選擇要保留的版本(或兩個都保留/合併)

# 步驟 3:解決後加入暫存區
git add Program.cs  # 標記衝突已解決

# 步驟 4:完成合併提交
git commit -m "解決 Program.cs 的合併衝突"  # 提交合併結果

# 如果想放棄這次合併
git merge --abort  # 取消合併,回到合併前的狀態

VS Code 衝突解決工具

VS Code 會自動偵測衝突並提供按鈕:
┌──────────────────────────────────────────────┐
│ Accept Current Change   │ 使用目前分支的版本 │
│ Accept Incoming Change  │ 使用合併進來的版本 │
│ Accept Both Changes     │ 兩個都保留         │
│ Compare Changes         │ 並排比較兩個版本   │
└──────────────────────────────────────────────┘

分支策略

Git Flow

Git Flow 分支策略:
┌────────────────────────────────────────────────────────────┐
│ main        ──●────────────────●────────────●──            │
│                \              ↗              ↑              │
│ release        ●──●──●──●──●        release/v2             │
│                ↑              \                              │
│ develop    ──●──●──●──●──●──●──●──●──●──●──                │
│               \  ↗  \     ↗                                 │
│ feature       ●──●    ●──●                                  │
│              login    signup                                 │
│                                                             │
│ hotfix     ────────────────────────●──●                     │
│                                        \→ main & develop    │
└────────────────────────────────────────────────────────────┘

- main:正式發佈版本
- develop:開發主線
- feature/*:功能分支(從 develop 分出)
- release/*:發佈準備
- hotfix/*:緊急修復(從 main 分出)

GitHub Flow(簡化版)

GitHub Flow 分支策略(適合小團隊和持續部署):
┌────────────────────────────────────────┐
│ main       ──●──●──●──M──●──M──●──    │
│                  \    ↗    \  ↗        │
│ feature-1         ●──●      │         │
│                              │         │
│ feature-2                   ●──●      │
│                                        │
│ 規則:                                 │
│ 1. main 永遠可部署                     │
│ 2. 從 main 建立 feature 分支           │
│ 3. 開 Pull Request 請人 review         │
│ 4. Review 通過後合併回 main            │
│ 5. 合併後立即部署                      │
└────────────────────────────────────────┘

Cherry-pick 與 Stash

Cherry-pick(摘櫻桃)

💡 比喻:從其他分支「摘」一個特定的 commit 就像從別人的果園摘一顆特別好的櫻桃到自己的籃子裡, 不需要把整棵樹搬過來。

# 從其他分支挑選特定 commit 套用到目前分支
git cherry-pick abc1234  # 把 commit abc1234 的變更套用到目前分支

# 挑選多個 commit
git cherry-pick abc1234 def5678  # 依序套用兩個 commit

# 只套用變更但不自動提交
git cherry-pick --no-commit abc1234  # 套用變更到工作區,但不自動 commit

# 放棄 cherry-pick
git cherry-pick --abort  # 取消目前的 cherry-pick 操作

Stash(暫時擱置)

💡 比喻:把桌上的東西先塞進抽屜 你正在寫功能 A,突然要緊急修 Bug, 但功能 A 還沒寫完不想 commit。 Stash 就是把半成品先「塞進抽屜」, 修完 Bug 後再「從抽屜拿出來」繼續做。

# 暫時擱置目前的變更
git stash  # 把所有未 commit 的變更存起來,工作區變乾淨

# 擱置時附上說明
git stash push -m "做到一半的登入功能"  # 加上說明方便之後辨識

# 查看所有暫存的東西
git stash list  # 列出所有 stash,顯示編號和說明

# 恢復最新的 stash(並從清單移除)
git stash pop  # 拿出最新的 stash 並從清單中刪除

# 恢復最新的 stash(但保留在清單中)
git stash apply  # 套用最新的 stash,但不從清單刪除

# 恢復特定的 stash
git stash apply stash@{2}  # 套用編號 2 的 stash

# 刪除特定的 stash
git stash drop stash@{0}  # 刪除編號 0 的 stash

# 清空所有 stash
git stash clear  # 刪除所有暫存的變更

🤔 我這樣寫為什麼會錯?

❌ 錯誤 1:在 main 分支上直接開發

# 錯誤:直接在 main 上改程式
git switch main  # 切換到 main
# ... 開始寫新功能 ...
git commit -m "新增登入功能"  # 直接在 main 上提交

# ✅ 正確:先建立分支再開發
git switch main  # 先確認在 main 上
git switch -c feature/login  # 建立並切換到功能分支
# ... 開始寫新功能 ...
git commit -m "新增登入功能"  # 在功能分支上提交

為什麼錯? 直接在 main 上開發,萬一寫到一半要緊急修 Bug,你的半成品程式碼就會混在一起。用分支可以隔離不同的工作。

❌ 錯誤 2:對已推送的公開分支做 rebase

# 錯誤:對已經 push 到遠端的分支做 rebase
git switch main  # 切換到 main
git rebase feature/login  # 改寫了 main 的歷史!

# ✅ 正確:公開分支用 merge
git switch main  # 切換到 main
git merge feature/login  # 用 merge 合併,不改寫歷史

為什麼錯? Rebase 會改寫 commit 的 hash,如果其他人已經基於舊的 hash 在工作,他們的歷史就會跟你的對不上,造成混亂。黃金規則:不要 rebase 已經推送到遠端的 commit

❌ 錯誤 3:衝突解決後忘記 commit

# 錯誤:解決衝突後忘記提交
git merge feature/login  # 發生衝突
# ... 手動解決衝突 ...
git add Program.cs  # 標記已解決
# 忘記 git commit 了!

# ✅ 正確:解決衝突後要完成提交
git merge feature/login  # 發生衝突
# ... 手動解決衝突 ...
git add Program.cs  # 標記已解決
git commit -m "解決合併衝突:整合登入功能"  # 完成合併提交

為什麼錯? 衝突解決後沒有 commit,Git 仍然處於「合併中」的狀態,後續操作會出問題。


📝 本章重點整理

指令 用途 比喻
git branch 管理分支 開啟平行宇宙
git switch 切換分支 跳到另一個宇宙
git merge 合併分支 樹枝嫁接
git rebase 變基 搬家重蓋
git cherry-pick 挑選 commit 摘櫻桃
git stash 暫時擱置 塞進抽屜

💡 大家的想法 · 0

載入中...
💬 即時聊天室 🟢 0 人在線
😀 😎 🤓 💻 🎮 🎸 🔥
➕ 新問題
📋 我的工單
💬 LINE 社群
🔒
需要註冊才能使用此功能
註冊帳號即可解鎖測驗、遊戲、簽到、筆記下載等所有功能,完全免費!
免費註冊