Git 合併 (Merge)

git merge 把一個分支的變更合併到另一個分支,是團隊協作中最常用的操作之一。

基本用法

假設你在 feature 分支完成了開發,要合併回 main

# 1. 切換到目標分支
git checkout main

# 2. 合併來源分支
git merge feature

這會把 feature 分支的變更合併到 main

合併的類型

Fast-forward 合併

當目標分支沒有新的 commit 時,Git 會執行 fast-forward 合併:

合併前:
main:     A --- B
                 \
feature:          C --- D

合併後:
main:     A --- B --- C --- D
git checkout main
git merge feature
# Fast-forward

這種合併不會產生新的 merge commit,只是把 main 的指標移動到 feature 的最新位置。

三方合併 (3-way merge)

當兩個分支都有新的 commit 時,Git 會執行三方合併:

合併前:
main:     A --- B --- E
                 \
feature:          C --- D

合併後:
main:     A --- B --- E --- M
                 \         /
feature:          C --- D
git checkout main
git merge feature
# Merge made by the 'ort' strategy.

三方合併會產生一個新的 merge commit(M),有兩個父 commit。

合併選項

禁止 Fast-forward

git merge --no-ff feature

即使可以 fast-forward,也會建立一個 merge commit。這樣可以保留分支的歷史:

main:     A --- B --------- M
                 \         /
feature:          C --- D

只允許 Fast-forward

git merge --ff-only feature

如果不能 fast-forward,就會失敗。適合用在希望保持線性歷史的情況。

Squash 合併

git merge --squash feature

feature 分支的所有變更壓縮成一個 commit,但不會自動 commit:

git merge --squash feature
git commit -m "Add feature (squashed)"

結果:

main:     A --- B --- C (包含 feature 的所有變更)

Squash 合併不會保留原本的 commit 歷史,適合不想保留細節的情況。

指定 Commit 訊息

git merge feature -m "Merge feature branch"

合併策略

Git 有多種合併策略,大部分情況下自動選擇就好:

# 使用特定策略
git merge -s recursive feature
git merge -s ours feature
git merge -s theirs feature
  • recursive:預設策略,適合大多數情況
  • ours:保留我們的版本,忽略對方的變更
  • resolve:較舊的策略

合併遠端分支

# 先取得遠端更新
git fetch origin

# 合併遠端分支
git merge origin/main

或者一步到位:

git pull origin main

git pull = git fetch + git merge

查看合併狀態

查看即將合併的內容

# 先不合併,只查看
git log main..feature  # feature 有哪些 commit
git diff main...feature  # 差異是什麼

查看合併歷史

git log --merges  # 只顯示 merge commit
git log --graph   # 圖形化顯示

取消合併

合併前取消

如果還沒開始合併,但想取消:

git merge --abort

合併後取消

如果合併已完成,想回到合併前:

# 如果還沒推送到遠端
git reset --hard HEAD~1

# 如果已經推送(產生新的 revert commit)
git revert -m 1 HEAD

處理合併衝突

當兩個分支修改了同一個檔案的同一個部分,Git 無法自動合併,就會產生衝突。

詳細說明請參考下一篇「解決合併衝突」。

實際範例

合併功能分支

# 確保 main 是最新的
git checkout main
git pull

# 合併功能分支
git merge feature/login --no-ff

# 推送
git push

合併多個分支

git checkout main
git merge feature1 feature2 feature3

合併特定 Commit

如果只想合併特定的 commit,用 cherry-pick

git cherry-pick a1b2c3d

最佳實踐

  1. 合併前先更新:先 git pull 確保你的 main 是最新的

  2. --no-ff 保留歷史:讓合併的來龍去脈更清楚

  3. 刪除已合併的分支:保持分支列表乾淨

git branch -d feature/login
  1. 避免長期分支:分支存在越久,合併衝突的機會越大

  2. 小步合併:經常合併,避免大規模衝突

合併 vs Rebase

合併和 Rebase 都可以整合分支,差異在於:

  • Merge:保留分支的歷史,產生 merge commit
  • Rebase:重寫歷史,讓 commit 變成線性

詳細比較請參考「Git rebase」。