【Git】使用 git revert 一次性還原多個提交

【Git】使用 git revert 一次性還原多個提交

本篇重點

  • git revert 的用途以及使用情境
  • 還原指定或多個提交的方法
  • 調整容易混淆的還原範圍寫法
  • 多個還原合併成一次提交
  • git revertgit reset 的差異

動手做做看

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

使用 Git 做版本控制,偶爾會遇到需要「還原某些修改」的情境,這時候除了常聽到的 git reset,還有一個更安全、常被忽略的指令:git revert

git revert

用途

建立一個新的 commit,將指定 commit 的變更「還原」回去,換句話說,它不會直接刪除歷史紀錄,而是新增一個「還原某次修改」的提交。

使用情境

  • 誤把有問題的功能合併進主要分支,需要「還原」但不能破壞歷史。
  • 在多人協作的專案裡,避免因為 git reset 改寫歷史而造成衝突。

還原指定提交

git
1
git revert <commit-hash>

範例:

git
1
2
3
4
5
git log --oneline
c3d9e28 修正 README 錯字
b71c5a2 新增登入驗證功能
a84f0d1 新增會員註冊功能
9d2a6ff 初始化專案

發現登入驗證功能 (b71c5a2) 有 bug,需要先移除功能

git
1
git revert b71c5a2

Git 會自動進入編輯器,讓你修改 commit message,通常預設會像這樣:

git
1
2
3
Revert "新增登入驗證功能"

This reverts commit b71c5a2.

儲存後就會新增一個還原修改的提交了

git
1
2
3
4
5
6
git log --oneline
gak451r Revert "新增登入驗證功能"
c3d9e28 修正 README 錯字
b71c5a2 新增登入驗證功能
a84f0d1 新增會員註冊功能
9d2a6ff 初始化專案

健忘筆記

直接使用預設提交訊息,不做任何修改,可以使用 git revert <commit-hash> --no-edit

還原多個提交

還原連續提交

容易混淆的還原範圍

git
1
git revert <oldest-commit>..<latest-commit>

<oldest-commit>下一個提交開始<latest-commit> 為止,並依序產生「反向 commit」,<oldest-commit> 本身的內容並不會被還原。

範例

git
1
2
3
4
5
git log --oneline
c3d9e28 修正 README 錯字
b71c5a2 新增登入驗證功能
a84f0d1 新增會員註冊功能
9d2a6ff 初始化專案

如果執行 git revert a84f0d1..c3d9e28,實際被還原的會是 b71c5a2c3d9e28,而 a84f0d1 並不會被包含在內。

調整還原範圍的寫法

因為 <oldest-commit>..<latest-commit> 的範圍並不包含 <oldest-commit>,在實際使用時可能會造成混淆。

如果希望範圍正好是從 <oldest-commit><latest-commit>(包含 <oldest-commit> 本身),就需要在 <oldest-commit> 後面加上 ^,代表「從這個提交的前一個開始」。

git
1
git revert <oldest-commit>^..<latest-commit>

範例

git
1
2
3
4
5
git log --oneline
c3d9e28 修正 README 錯字
b71c5a2 新增登入驗證功能
a84f0d1 新增會員註冊功能
9d2a6ff 初始化專案

如果執行 git revert a84f0d1^..c3d9e28,實際被還原的就是 a84f0d1c3d9e28

多個還原合併成一次提交

還原多個提交會逐一產生「反向 commit」,如果不希望產生多個 commit,而是想把所有變更合併到一次提交中,可以使用 --no-commit 參數,然後再手動下 git commit

git
1
2
git revert --no-commit <oldest-commit>^..<latest-commit>
git commit -m "Revert commits from <oldest-commit> to <latest-commit>"

範例

git
1
2
3
4
5
git log --oneline
c3d9e28 修正 README 錯字
b71c5a2 新增登入驗證功能
a84f0d1 新增會員註冊功能
9d2a6ff 初始化專案
git
1
2
git revert --no-commit a84f0d1^..c3d9e28
git commit -m "還原到專案初始化的狀態" -m "Revert commits from a84f0d1 to c3d9e28"

健忘筆記

第一個 -m 是提交訊息,第二個 -m 是提交的補充說明,多個 -m 選項會串連成個別段落,詳細說明可察看官方文件

還原非連續提交

如果要還原的提交非連續,無法使用範圍操作

git
1
2
git revert --no-commit <commit1> <commit2> <commit3>
git commit -m "Revert selected commits"

範例

git
1
2
3
4
5
git log --oneline
b71c5a2 新增登入驗證功能
c3d9e28 修正 README 錯字
a84f0d1 新增會員註冊功能
9d2a6ff 初始化專案
git
1
2
git revert --no-commit a84f0d1 b71c5a2
git commit -m "移除會員註冊、登入驗證功能" -m "Revert commits a84f0d1, b71c5a2"

git revertgit reset 的差異

指令行為是否保留歷史適合場合
git revert新增一個「撤銷指定 commit」的提交保留歷史公開分支、多人協作
git reset將分支指標移動到指定 commit改寫歷史私人分支、尚未 push 的情況

範例

git revert

git tree
1
2
A - B - C - D (main)
↑ (HEAD)

假設要還原 Cgit revert C 後會變成:

git tree
1
2
A - B - C - D - E (main)
↑ (HEAD)

E 這個新 commit 就是「還原 C 的內容」

git reset

git tree
1
2
A - B - C - D (main)
↑ (HEAD)

執行 git reset B

git tree
1
2
A - B (main)
↑ (HEAD)

原本的 CD 會直接消失(歷史被改寫)

健忘筆記

還原指令建議

  • 如果專案已經 push 到 GitHub,建議使用 git revert
  • 如果還在本地測試、未 push,可以用 git reset 來清理歷史

結論

語法作用
git revert --no-commit A..D還原 B、C、D(不包含 A
git revert --no-commit A^..D還原 A、B、C、D
git revert --no-commit A B C D手動指定還原 A, B, C, D
  • git revert 適合在多人協作、公開分支上使用,能保留完整歷史並安全還原修改。
  • 如果要還原多個提交,可以 一次指定多個 commit使用範圍語法
  • git revertgit reset 最大的差異在於是否「改寫歷史」:
    • revert 會新增 commit,保留歷史。
    • reset 則會刪掉歷史,不適合公開分支。

動手做做看

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

延伸閱讀

【Git】使用 git revert 一次性還原多個提交

https://forgetfulengineer.github.io/Other/Git/Git-Revert-Multiple-Commits/

作者

健忘工程師

發表於

2025-08-28

更新於

2025-08-28

許可協議


你可能也想看

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

評論

複製完成