2025-08-08 Line 訂單系統- git Rebase
2025-08-08 Line 訂單系統- git Rebase
好的,我來詳細解釋 **git rebase**,並用簡單的方式讓你理解它跟 git merge 的差別。
1️⃣ 基本概念
git rebase 的作用是 把一個分支的修改「搬到」另一個分支的最前面。
換句話說,它不是把分支「合併」在一起,而是 改寫提交歷史,讓它看起來像是在目標分支之後直接做的修改。
簡單比喻:
- 假設你在
main分支上有提交 A → B → C - 你從
main分出一個feature分支,做了提交 D → E
歷史:
1 | main: A---B---C |
如果你現在做 **git rebase main**:
feature分支會把 D、E 移到 C 之後- 最終歷史變成:
1 | main: A---B---C |
注意:D 和 E 被重新生成了(變成 D’、E’),所以 commit hash 會變。
2️⃣ Rebase vs Merge
| 特性 | Merge | Rebase |
|---|---|---|
| 歷史 | 保留所有分支歷史,會出現 merge commit | 重新寫歷史,保持線性,不會產生 merge commit |
| 視覺上 | 分支歷史會分叉 | 分支歷史線性,看起來像直接接在 main 後面 |
| 衝突解決 | merge 時解決一次衝突 | 每個 commit 都可能需要解決衝突 |
例子:
- Merge:
1 | A---B---C---M |
- Rebase:
1 | A---B---C---D'---E' |
3️⃣ 常用指令
- 讓當前分支重放到
main之後:
1 | git checkout feature |
- 如果衝突,Git 會提示你,解決衝突後:
1 | git add <file> |
- 中斷 rebase:
1 | git rebase --abort |
- 互動式 rebase(整理 commit):
1 | git rebase -i main |
4️⃣ 使用場景
- 保持提交歷史乾淨:讓歷史看起來線性,不出現太多 merge commit。
- 把 feature 分支更新到最新 main:在 push 前用 rebase,避免 merge commit。
⚠️ 注意:不要對已經推送到遠端的分支做 rebase,會改變 commit hash,可能導致別人 pull 出問題。
如果你要,我可以幫你畫一張 圖解 Git Rebase vs Merge,一眼就能看懂兩者差別。
你想要我畫嗎?
好的,我用 真實開發情境來說明何時用 rebase、何時用 merge,讓你容易理解兩者的使用場景。
1️⃣ 情境 1:小組開發新功能(建議用 rebase)
情境:
- 你在
feature/login分支開發登入功能。 - 你的同事在
main分支做了更新(例如修正了 API URL)。 - 你想把最新的
main更新拿到你的feature/login分支上,保持分支乾淨。
做法:
1 | git checkout feature/login |
效果:
- 你的 feature 分支會「搬到最新 main 後面」,歷史線性。
- 不會出現 merge commit,git log 乾淨。
✅ 適用時機:你還沒把 feature 分支推到遠端,或團隊允許改寫分支歷史。
2️⃣ 情境 2:完成 feature,要合併回 main(建議用 merge)
情境:
- 你開發的 feature 分支已完成,經過測試。
- 你要把
feature/login分支合併回main,保留開發過程的歷史。
做法:
1 | git checkout main |
效果:
- 會產生一個 merge commit,把 feature 分支完整合併回 main。
- 歷史保留原本分叉過程,方便追蹤誰在何時做了什麼。
✅ 適用時機:feature 分支已經推送給團隊,或你想保留分支歷史。
3️⃣ 情境 3:多人長期開發同一分支(混合策略)
- 每個人先 rebase 自己的 feature 分支到最新 main,保持線性、避免衝突。
- 最後再用 merge 將完成的 feature 分支合併回 main,保留完整歷史。
這樣可以兼顧「線性歷史」與「完整紀錄」。
💡 簡單記憶法:
- Rebase = 更新你的分支(搬到最新 main 之後,乾淨線性)
- Merge = 合併完成的分支回主線(保留歷史,出現 merge commit)
如果你想,我可以幫你畫一張 圖解三種情境的 Git Rebase vs Merge 流程圖,用線條表示 commit 移動和 merge,這樣一眼就能看懂。
你希望我畫嗎?
好,我用 最簡單、生活化的例子來說明 rebase 和 merge,保證你一看就懂。
情境設定:
- 你有一本「工作筆記本」,主線是
main分支。 - 你想加一個「新功能」,就從主線複製出一本副本,叫
feature分支。
主線(main)有事件:
1 | A: 今天吃早餐 |
你從 B 分出副本做 feature:
1 | feature: |
歷史看起來像這樣:
1 | main: A --- B |
1️⃣ 情境:main 有新事情,你要更新 feature(用 rebase)
- main 又更新了 E: 去跑步
- 你希望 feature 分支在最新 main 之後繼續
做法:
1 | git checkout feature |
結果:
1 | main: A --- B --- E |
✅ 好處:
- 歷史變線性,好像你的 feature 從最新 main 開始
- 沒有多餘的 merge commit
2️⃣ 情境:feature 做完,要回到 main(用 merge)
- 你 feature 做完了 C、D
- 想把 feature 合併回 main
做法:
1 | git checkout main |
結果:
1 | main: A --- B --- E --- M |
- M 是 merge commit
- 歷史保留誰做了什麼,不改寫原本的 commit
✅ 好處:
- 安全,不會改變已經推到遠端的 commit
- 可以保留完整開發歷史
簡單理解:
| 操作 | 類比 | 結果 |
|---|---|---|
| Rebase | 把你的 feature 分支搬到最新的主線後面 | 歷史線性、乾淨 |
| Merge | 把 feature 分支合回主線,保留分叉歷史 | 歷史有分叉和 merge commit |
如果你願意,我可以幫你畫一個 小圖,把早餐、咖啡、跑步、寫程式、測試程式 都畫在 commit 線上,視覺化 rebase 和 merge,保證一眼就懂。
你想要我畫這個圖嗎?
好的,我幫你用 Mermaid 畫出剛才那個生活化例子的 rebase 與 merge 流程圖。
flowchart LR
%% 主線 main 的 commit
A["A: 吃早餐"] --> B["B: 喝咖啡"]
B --> E["E: 跑步"]
%% feature 分支原始 commit
B --> C["C: 寫程式"]
C --> D["D: 測試程式"]
%% Merge 的結果
E --> M["M: merge feature"]
%% Rebase 的結果 (用虛線表示重放 commit)
E --> C_prime["C': 寫程式"]
C_prime --> D_prime["D': 測試程式"]
%% 標註
classDef main fill:#f9f,stroke:#333,stroke-width:1px;
classDef feature fill:#9f9,stroke:#333,stroke-width:1px,stroke-dasharray: 5 5;
class A,B,E main;
class C,D,M feature;
class C_prime,D_prime feature;
解釋圖:
- 主線 main:A → B → E
- feature 分支原本:從 B 分出 C → D
- Merge:M commit 將 feature 分支合回 main,歷史保留分叉
- Rebase:C’ → D’ 重新放到最新 main E 後面,線性歷史
- 虛線表示 rebase 之後的 commit,有新 commit hash
- Merge commit M 保留原本分支歷史,不改寫 commit
如果你想,我可以幫你做 一個更直觀的 Mermaid 動態流程圖,把 Merge 和 Rebase 比較在同一張圖,用不同顏色標示,視覺更清楚。
你希望我做嗎?