利用 git rebase 的互動模式,可以讓你簡單的去調整 Commit 的順序;或是拆分過大的 Commit;也可以刪除不必要的 Commit。
Git Rebase 是一個內建的 git 指令,可以用來將 Commit 重新提交到新的基礎。
下面這個範例中有一個 feature 分支是從 master 開出來,而 master 也有新的提交。
在這輸入文本
E---F---G feature / A---B---C---D master
我們可以執行在 feature 分支執行 git rebase master
,就可以把在 feature 的 Commit 以 D 為基礎重新套用,結果如下:
E'---F'---G' feature / A---B---C---D master
在原本的指令中,加入 -i
或是 --interactive
就可以進入互動模式。
git rebase -i <起始 Commit>
執行後,預設會使用 vim 開啟互動模式的介面,調整完後執行 :wq
存擋關閉 vim,就會依照指定的指令執行。
上半部未註解的部分會由上至下列出從指定的 Commit 到 HEAD 之間的所有 Commit,一行代表一個 Commit 及對應的操作,從頭依序 操作指令、Hash 及 Commit 訊息。
下半部有註解的部分,是一些指令的簡介及縮寫,使用時就可以直接參考不用去特別記它的指令及用法。
pick d34548f Add feature 1 pick 98fb1b9 Add feature 2 pick cbf941f Add feature 3 pick 1499a17 Add feature 4 pick 3e14876 Add feature 5 # 重定基底 bda1985..1499a17 到 bda1985(6 個提交) # # 指令: # p, pick <提交> = 使用提交 # r, reword <提交> = 使用提交,但修改提交說明 # e, edit <提交> = 使用提交,進入 shell 以便進行提交修補 # s, squash <提交> = 使用提交,但融合到前一個提交 # f, fixup <提交> = 類似於 "squash",但捨棄提交說明日誌 # x, exec <指令> = 使用 shell 執行指令(此行剩餘部分) # b, break = 在此處停止(使用 'git rebase --continue' 繼續重定基底) # d, drop <提交> = 刪除提交 # l, label <label> = 為目前 HEAD 打上標記 # t, reset <label> = 重設 HEAD 到該標記 # m, merge [-C <commit> | -c <commit>] <label> [# <oneline>] # . 建立一個合併提交,並使用原始的合併提交說明(如果沒有指定 # . 原始提交,使用備註部分的 oneline 作為提交說明)。使用 # . -c <提交> 可以編輯提交說明。 # # 可以對這些行重新排序,將從上至下執行。 # # 如果您在這裡刪除一行,對應的提交將會遺失。 # # 然而,如果您刪除全部內容,重定基底動作將會終止。
在上半部 Commit 的部分可以看到預設指令都是
pick
(使用提交),我們可以藉由更改這個指令來對任意的 Commit 進行編輯或刪除之類的操作。
需要注意的是開頭指令及 Hash 的部分,都要輸入正確否則它會無法辨識,而 Commit 訊息的部分就沒差了,不會影響執行。
常用的指令說明:
pick
:預設都是這個指令,代表會使用這個 Commit。reword
:使用這個 Commit,但是執行到此 Commit 時會開啟 vim 供更改 Commit 訊息。edit
:使用這個 Commit,但是執行到此 Commit 時會暫停,直到執行 git rebase --continue
。squash
:將這個 Commit 與前一個 Commit 合併,訊息也會合併。fixup
:與 squash
相同,但會捨棄這個 Commit 的訊息。drop
:刪除這個 Commit,結果同直接刪除行。這裡將透過一個範例來展示幾個常用操作。
原始的 Commit 如下:
* 655082e 2021-07-19 | Add feature 6 (HEAD) * 69a3e14 2021-07-19 | Add feature 5-1 * b99b647 2021-07-19 | Add feature 4 * b2e9250 2021-07-19 | Add feature 5 * 8ad13c6 2021-07-19 | Add feature 3 * c3e8936 2021-07-19 | Fix feature 2 bug * e4e3c6f 2021-07-19 | Add feature 2 * 9fa7ff7 2021-07-19 | Add feature 1 * bda1985 2021-07-19 | Init Commit
需求:
Add feature 4
及 Add feature 5
的順序。Add feature 2
及 Fix feature 2 bug
(不留訊息)。Add feature 5-1
git rebase
執行以下指令開啟 git rebase 互動模式,並指定 Rebase bda1985
之後的 Commit:
git rebase -i bda1985
執行後,將顯示以下資訊
pick 9fa7ff7 Add feature 1 pick e4e3c6f Add feature 2 pick c3e8936 Fix feature 2 bug pick 8ad13c6 Add feature 3 pick b2e9250 Add feature 5 pick b99b647 Add feature 4 pick 69a3e14 Add feature 5-1 pick 655082e Add feature 6 # 重定基底 bda1985..655082e 到 bda1985(8 個提交) # ...
Add feature 4
及 Add feature 5
的順序
直接將 Add feature 4
及 Add feature 5
兩行交換順序。
pick 9fa7ff7 Add feature 1 pick e4e3c6f Add feature 2 pick c3e8936 Fix feature 2 bug pick 8ad13c6 Add feature 3 pick b99b647 Add feature 4 pick b2e9250 Add feature 5 pick 69a3e14 Add feature 5-1 pick 655082e Add feature 6 # 重定基底 bda1985..655082e 到 bda1985(8 個提交)
Add feature 2
及 Fix feature 2 bug
為了將 Fix feature 2 bug
合併至 Add feature 2
,更改 Fix feature 2 bug
的指令為 fixup
(與上一個合併但不保留訊息)。
pick 9fa7ff7 Add feature 1 pick e4e3c6f Add feature 2 fixup c3e8936 Fix feature 2 bug pick 8ad13c6 Add feature 3 pick b99b647 Add feature 4 pick b2e9250 Add feature 5 pick 69a3e14 Add feature 5-1 pick 655082e Add feature 6 # 重定基底 bda1985..655082e 到 bda1985(8 個提交)
Add feature 5-1
因為要刪除 Add feature 5-1
這個 Commit,所以將這一行直接移除。
pick 9fa7ff7 Add feature 1 pick e4e3c6f Add feature 2 fixup c3e8936 Fix feature 2 bug pick 8ad13c6 Add feature 3 pick b99b647 Add feature 4 pick b2e9250 Add feature 5 pick 655082e Add feature 6 # 重定基底 bda1985..655082e 到 bda1985(8 個提交)
在 Vim 中執行
:wq
就可以關閉互動模式,並執行 Rebase。
執行結果如下,可以看到已完成上面列的需求。
* 31d6978 2021-07-19 | Add feature 6 (HEAD -> master) * 5e4f588 2021-07-19 | Add feature 5 * 04b8a95 2021-07-19 | Add feature 4 * 17fc05f 2021-07-19 | Add feature 3 * a30783f 2021-07-19 | Add feature 2 * 9fa7ff7 2021-07-19 | Add feature 1 * bda1985 2021-07-19 | Init Commit
執行過程動畫:
利用 Git Rebase 的互動模式介面,可以快速的整理 Commit,讓我們的變更紀錄更容易理解。但 rebase 的操作是會變更整個歷史,要注意一點是不要在共用的分支進行 rebase
,會造成其他人的歷史紀錄亂掉。