【Git】使用 git rebase 整理提交歷史

【Git】使用 git rebase 整理提交歷史

本篇重點

  • 如果有尚未提交的變更,無法使用 git rebase
  • git rebase 合併不會產生額外的合併提交,但是會變更原本的提交 ID
  • git rebase -i(互動式 rebase)編輯功能
  • 使用 git rebase -i 調整提交順序、修改提交訊息、修改提交內容、合併提交、刪除提交
  • git rebase 的注意事項

動手做做看

我建了一個範例 repository,可以 clone 下來後跟著文章操作!
git clone https://github.com/forgetfulengineer/git-rebase-example.git

Git 拒絕執行 rebase

使用 git rebase 的前提是工作區(working directory)必須是乾淨的,也就是不能有尚未提交的變更,否則 Git 會拒絕執行 rebase,並顯示錯誤訊息

git error
1
2
Cannot rebase: You have unstaged changes.
Please commit or stash them.

因為 git rebase 會重寫提交歷史,而未提交的變更可能會導致衝突或遺失,因此 Git 會強制要求先處理這些變更。

有尚未提交的變更,Git 拒絕執行 rebase

解決方法

1. 使用 git stash 暫存變更

如果目前的變更還不想提交,可以使用 git stash 暫存起來,執行 rebase 後再取回,適合暫時性變更,不影響提交歷史

git
1
2
3
4
5
6
7
8
# 暫存變更
git stash

# 進行 rebase
git rebase ...

# 取回變更
git stash pop

2. 使用 git rebase --autostash(自動暫存變更)

可以使用 --autostash 讓 Git 在 rebase 前自動暫存變更,完成後再自動取回,適合經常遇到這個問題的人,減少手動 stash 的步驟

git
1
git rebase --autostash ...

3. 先提交變更

暫時提交變更,執行 rebase 後再撤銷提交,適合暫時性變更,不影響提交歷史

git
1
2
3
git add .
git commit -m "暫存變更以執行 rebase"
git rebase ...

如果不想保留暫存提交,可以在 rebase 後使用 git reset HEAD~1 撤銷提交,讓變更回到工作區

git
1
git reset HEAD~1

git rebase 的基本功能

將當前分支的提交銜接到另一個分支的最新進度上,與 git merge 不同,git rebase 不會產生額外的合併提交(merge commit),讓提交歷史保持乾淨且條理。

健忘筆記

如果兩分支變更的檔案有衝突,沒辦法 Fast-forward 合併,就需要重新調整提交內容

範例

當前 main 分支最新進度開發到 C 節點,但 dev 分支是從 main 分支 B 節點開始開發,因此出現分支衝突的狀況。

git tree
1
2
3
A --- B --- C (main)
\
D (dev)

main 和 dev 分支發生衝突

使用 git rebase 合併 main 分支進度,將 dev 分支的提交銜接到 main 的最新進度上

git
1
2
git checkout dev
git rebase main
git tree
1
2
# D 的提交 ID 會和原本不一樣
A --- B --- C --- D' (dev)

這樣可以確保 dev 基於 main 的最新進度,並且提交記錄保持清晰,不產生額外的合併提交。

git rebase 的合併

健忘筆記

git rebase 合併分支,銜接到最新進度的提交(commit),提交 ID 會和原本不一樣

git rebase -i(互動式 rebase)

git rebase -i 用於編輯提交歷史,可以整理提交順序、修改提交內容或合併提交等,-i 是 interactive 的意思。

git
1
2
3
4
5
6
7
8
9
10
11
# 對最近的 N 次提交執行 rebase (N 替換成數字)
git rebase -i HEAD~[N]

# 對最近的 3 次提交執行 rebase
git rebase -i HEAD~3

# 對 commit id 之後的提交執行 rebase
git rebase -i [commit id]

# 對 a1b2c3d 之後的提交執行 rebase
git rebase -i a1b2c3d

互動式 rebase 編輯介面

執行 git rebase -i [指定提交] 後會進入編輯介面,上到下以最舊到最新列出提交資訊,並且每個提交的前面會顯示操作指令

git rebae -i
1
2
3
pick  a1b2c3d  初始提交
pick d4e5f6g 修正錯誤
pick h7i8j9k 增加新功能
git rebae -i
1
2
3
4
# 設定操作方式可以直接使用縮寫指令也可以使用完整指令
r a1b2c3d 初始提交
reword d4e5f6g 修正錯誤
d h7i8j9k 增加新功能

這些是我覺得比較重要的選項:

選項功能描述
p(pick)保留提交
r(reword)修改提交訊息
e(edit)修改提交內容
s(squash)與前一個提交合併,並且設定提交訊息
f(fixup)與前一個提交合併,並且直接使用前一個提交的提交訊息
d(drop)刪除提交

完整操作指令說明可以在編輯介面查看

git rebae -i
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup [-C | -c] <commit> = like "squash" but keep only the previous
# commit's log message, unless -C is used, in which case
# keep only this commit's message; -c is same as -C but
# opens the editor
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# . create a merge commit using the original merge commit's
# . message (or the oneline, if no original merge commit was
# . specified); use -c <commit> to reword the commit message

調整提交順序

如果提交的順序不符合邏輯,或希望讓提交記錄更清晰,可以調整提交的順序。

範例

git rebae -i
1
2
3
4
pick  a1b2c3d  test4
pick d4e5f6g test2
pick h7i8j9k test1
pick y3i1j7r test3

重新調整提交歷史的順序,讓提交是 test1test4

git rebae -i
1
2
3
4
pick  h7i8j9k  test1
pick d4e5f6g test2
pick y3i1j7r test3
pick a1b2c3d test4

調整完成後儲存,Git 就會按照新的順序排列。

健忘筆記

我的編輯介面是使用 vim 做編輯器,所以直接使用 :x:x 等於 :wq)即可儲存後退出 git rebase -i,如果想把編輯器設定成 vim,可以參考【Git】了解 git config 設定

修改提交訊息

如果某次提交的訊息不夠清楚或有錯誤,可以使用 r, reword 來修改提交訊息。

範例

git rebae -i
1
2
3
4
pick  h7i8j9k  test1
pick d4e5f6g test2
pick y3i1j7r test3
r a1b2c3d test4

儲存後,Git 會提示你輸入新的提交訊息

reword
1
2
# test4 -> test4 & test5
test4 & test5

修改完成後儲存,就會更新成新的提交訊息

git
1
2
3
4
5
$ git log
h7i8j9k test1
d4e5f6g test2
y3i1j7r test3
a1b413d test4 & test

*補充:也可以一次修改多個提交訊息

git rebae -i
1
2
3
4
r  h7i8j9k  test1
r d4e5f6g test2
pick y3i1j7r test3
r a1b2c3d test4

修改提交內容

如果某個提交有錯誤,或想要補充內容,或是想修改提交的資訊(作者、信箱等),可以使用 e, edit 來修改提交內容。

git rebae -i
1
2
3
4
pick  h7i8j9k  test1
e d4e5f6g test2
pick y3i1j7r test3
pick a1b2c3d test4

儲存後,Git 會暫停在該提交,即可對該提交進行修改

edit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 修改檔案
vim example.txt

# 加入修改內容
git add example.txt

# 重新提交(覆蓋最新一次提交)
git commit --amend --no-edit

# 修改最新一次提交的作者名稱和信箱
git commit --amend --author="forgetfulengineer <thatforgetfulengineer@gmail.com>"

# 繼續 rebase
git rebase --continue

*補充:也可以一次修改多個提交

git rebae -i
1
2
3
4
pick  h7i8j9k  test1
e d4e5f6g test2
e y3i1j7r test3
e a1b2c3d test4

合併提交

如果多個提交的內容屬於同一個邏輯並且想整理成一個提交,可以使用 s, squash 或是 f, fixup 來合併提交,使歷史記錄更加簡潔。

git rebae -i
1
2
3
4
pick  h7i8j9k  test1
s d4e5f6g test2
pick y3i1j7r test3
f a1b2c3d test4

儲存後,Git 會讓你選擇合併後的提交訊息,或是自行修改

squash
1
2
# 設定合併後的提交訊息
add test1 & test2
git
1
2
3
$ git log
h7i8j7k add test1 & test2
d4e2f6g test3

完成後,提交將合併成一個

健忘筆記

s, squash 與前一個提交合併,並且設定提交訊息
f, fixup 與前一個提交合併,並且直接使用前一個提交的提交訊息

刪除提交

如果提交已經不需要或是有錯誤,可以使用 d, drop 來刪除

git rebae -i
1
2
3
4
pick  h7i8j9k  test1
pick d4e5f6g test2
d y3i1j7r test3
pick a1b2c3d test4

儲存後,Git 會該提交從歷史中刪除

git
1
2
3
4
$ git log
pick h7i8j9k test1
pick d4e5f6g test2
pick a1b2c3d test4

結論

git rebase -i 提供了很多功能整理歷史提交,讓紀錄更清晰、整潔,這邊整理我常使用到的功能:

  • 調整提交順序
  • 修改提交訊息(r, reword
  • 修改提交內容(e, edit
  • 合併提交(s, squashf, fixup
  • 刪除提交(d, drop

雖然 git rebase 很好用,但使用時有一些需要注意的地方:

  • 工作區不能有尚未提交的變更,否則 Git 會拒絕執行 rebase
  • git rebase 的操作可能會改變歷史提交的提交 ID,導致發生分支衝突
  • 多人開發時,要避免直接在公共分支使用 git rebase,可能導致和其他人分支衝突

熟悉需要注意的地方後,善用 git rebase 就可以讓 Git 提交歷史更整潔,提升專案的可讀性與維護性!

動手做做看

我建了一個範例 repository,可以 clone 下來後跟著文章操作!
git clone https://github.com/forgetfulengineer/git-rebase-example.git

延伸閱讀

作者

健忘工程師

發表於

2025-02-14

更新於

2025-02-14

許可協議


你可能也想看

【Git、Hexo】deploy github 檔名大小寫問題
【Git】了解 git config 設定
【Hexo】多台電腦佈署 GitHub page 的問題

評論

複製完成