本篇重點
- 如果有尚未提交的變更,無法使用
git rebase
git rebase
合併不會產生額外的合併提交,但是會變更原本的提交 IDgit rebase -i
(互動式 rebase)編輯功能- 使用
git rebase -i
調整提交順序、修改提交訊息、修改提交內容、合併提交、刪除提交 git rebase
的注意事項
Git 拒絕執行 rebase
使用 git rebase
的前提是工作區(working directory)必須是乾淨的,也就是不能有尚未提交的變更,否則 Git 會拒絕執行 rebase
,並顯示錯誤訊息
1 | Cannot rebase: You have unstaged changes. |
因為 git rebase
會重寫提交歷史,而未提交的變更可能會導致衝突或遺失,因此 Git 會強制要求先處理這些變更。
解決方法
1. 使用 git stash
暫存變更
如果目前的變更還不想提交,可以使用 git stash
暫存起來,執行 rebase
後再取回,適合暫時性變更,不影響提交歷史
1 | # 暫存變更 |
2. 使用 git rebase --autostash
(自動暫存變更)
可以使用 --autostash
讓 Git 在 rebase
前自動暫存變更,完成後再自動取回,適合經常遇到這個問題的人,減少手動 stash
的步驟
1 | git rebase --autostash ... |
3. 先提交變更
暫時提交變更,執行 rebase
後再撤銷提交,適合暫時性變更,不影響提交歷史
1 | git add . |
如果不想保留暫存提交,可以在 rebase
後使用 git reset HEAD~1
撤銷提交,讓變更回到工作區
1 | git reset HEAD~1 |
git rebase
的基本功能
將當前分支的提交銜接到另一個分支的最新進度上,與 git merge
不同,git rebase
不會產生額外的合併提交(merge commit),讓提交歷史保持乾淨且條理。
範例
當前 main
分支最新進度開發到 C 節點,但 dev
分支是從 main
分支 B 節點開始開發,因此出現分支衝突的狀況。
1 | A --- B --- C (main) |
使用 git rebase
合併 main
分支進度,將 dev
分支的提交銜接到 main
的最新進度上
1 | git checkout dev |
1 | # D 的提交 ID 會和原本不一樣 |
這樣可以確保 dev
基於 main
的最新進度,並且提交記錄保持清晰,不產生額外的合併提交。
git rebase -i
(互動式 rebase)
git rebase -i
用於編輯提交歷史,可以整理提交順序、修改提交內容或合併提交等,-i
是 interactive 的意思。
1 | # 對最近的 N 次提交執行 rebase (N 替換成數字) |
互動式 rebase 編輯介面
執行 git rebase -i [指定提交]
後會進入編輯介面,上到下以最舊到最新列出提交資訊,並且每個提交的前面會顯示操作指令
1 | pick a1b2c3d 初始提交 |
1 | # 設定操作方式可以直接使用縮寫指令也可以使用完整指令 |
這些是我覺得比較重要的選項:
選項 | 功能描述 |
---|---|
p (pick) | 保留提交 |
r (reword) | 修改提交訊息 |
e (edit) | 修改提交內容 |
s (squash) | 與前一個提交合併,並且設定提交訊息 |
f (fixup) | 與前一個提交合併,並且直接使用前一個提交的提交訊息 |
d (drop) | 刪除提交 |
完整操作指令說明可以在編輯介面查看
1 | # Commands: |
調整提交順序
如果提交的順序不符合邏輯,或希望讓提交記錄更清晰,可以調整提交的順序。
範例
1 | pick a1b2c3d test4 |
重新調整提交歷史的順序,讓提交是 test1
到 test4
1 | pick h7i8j9k test1 |
調整完成後儲存,Git 就會按照新的順序排列。
修改提交訊息
如果某次提交的訊息不夠清楚或有錯誤,可以使用 r, reword
來修改提交訊息。
範例
1 | pick h7i8j9k test1 |
儲存後,Git 會提示你輸入新的提交訊息
1 | # test4 -> test4 & test5 |
修改完成後儲存,就會更新成新的提交訊息
1 | $ git log |
*補充:也可以一次修改多個提交訊息
1 | r h7i8j9k test1 |
修改提交內容
如果某個提交有錯誤,或想要補充內容,或是想修改提交的資訊(作者、信箱等),可以使用 e, edit
來修改提交內容。
1 | pick h7i8j9k test1 |
儲存後,Git 會暫停在該提交,即可對該提交進行修改
1 | # 修改檔案 |
*補充:也可以一次修改多個提交
1 | pick h7i8j9k test1 |
合併提交
如果多個提交的內容屬於同一個邏輯並且想整理成一個提交,可以使用 s, squash
或是 f, fixup
來合併提交,使歷史記錄更加簡潔。
1 | pick h7i8j9k test1 |
儲存後,Git 會讓你選擇合併後的提交訊息,或是自行修改
1 | # 設定合併後的提交訊息 |
1 | $ git log |
完成後,提交將合併成一個
刪除提交
如果提交已經不需要或是有錯誤,可以使用 d, drop
來刪除
1 | pick h7i8j9k test1 |
儲存後,Git 會該提交從歷史中刪除
1 | $ git log |
結論
git rebase -i
提供了很多功能整理歷史提交,讓紀錄更清晰、整潔,這邊整理我常使用到的功能:
- 調整提交順序
- 修改提交訊息(
r, reword
) - 修改提交內容(
e, edit
) - 合併提交(
s, squash
或f, fixup
) - 刪除提交(
d, drop
)
雖然 git rebase
很好用,但使用時有一些需要注意的地方:
- 工作區不能有尚未提交的變更,否則 Git 會拒絕執行
rebase
git rebase
的操作可能會改變歷史提交的提交 ID,導致發生分支衝突- 多人開發時,要避免直接在公共分支使用
git rebase
,可能導致和其他人分支衝突
熟悉需要注意的地方後,善用 git rebase
就可以讓 Git 提交歷史更整潔,提升專案的可讀性與維護性!