本篇重點
git revert
的用途以及使用情境- 還原指定或多個提交的方法
- 調整容易混淆的還原範圍寫法
- 多個還原合併成一次提交
git revert
和git reset
的差異
使用 Git 做版本控制,偶爾會遇到需要「還原某些修改」的情境,這時候除了常聽到的 git reset
,還有一個更安全、常被忽略的指令:git revert
。
git revert
用途
建立一個新的 commit,將指定 commit 的變更「還原」回去,換句話說,它不會直接刪除歷史紀錄,而是新增一個「還原某次修改」的提交。
使用情境
- 誤把有問題的功能合併進主要分支,需要「還原」但不能破壞歷史。
- 在多人協作的專案裡,避免因為
git reset
改寫歷史而造成衝突。
還原指定提交
1 | git revert <commit-hash> |
範例:
1 | git log --oneline |
發現登入驗證功能 (b71c5a2) 有 bug,需要先移除功能
1 | git revert b71c5a2 |
Git 會自動進入編輯器,讓你修改 commit message,通常預設會像這樣:
1 | Revert "新增登入驗證功能" |
儲存後就會新增一個還原修改的提交了
1 | git log --oneline |
還原多個提交
還原連續提交
容易混淆的還原範圍
1 | git revert <oldest-commit>..<latest-commit> |
從 <oldest-commit>
的下一個提交開始到 <latest-commit>
為止,並依序產生「反向 commit」,<oldest-commit>
本身的內容並不會被還原。
範例
1 | git log --oneline |
如果執行 git revert a84f0d1..c3d9e28
,實際被還原的會是 b71c5a2
和 c3d9e28
,而 a84f0d1
並不會被包含在內。
調整還原範圍的寫法
因為 <oldest-commit>..<latest-commit>
的範圍並不包含 <oldest-commit>
,在實際使用時可能會造成混淆。
如果希望範圍正好是從 <oldest-commit>
到 <latest-commit>
(包含 <oldest-commit>
本身),就需要在 <oldest-commit>
後面加上 ^
,代表「從這個提交的前一個開始」。
1 | git revert <oldest-commit>^..<latest-commit> |
範例
1 | git log --oneline |
如果執行 git revert a84f0d1^..c3d9e28
,實際被還原的就是 a84f0d1
到 c3d9e28
。
多個還原合併成一次提交
還原多個提交會逐一產生「反向 commit」,如果不希望產生多個 commit,而是想把所有變更合併到一次提交中,可以使用 --no-commit
參數,然後再手動下 git commit
1 | git revert --no-commit <oldest-commit>^..<latest-commit> |
範例
1 | git log --oneline |
1 | git revert --no-commit a84f0d1^..c3d9e28 |
還原非連續提交
如果要還原的提交非連續,無法使用範圍操作
1 | git revert --no-commit <commit1> <commit2> <commit3> |
範例
1 | git log --oneline |
1 | git revert --no-commit a84f0d1 b71c5a2 |
git revert
和 git reset
的差異
指令 | 行為 | 是否保留歷史 | 適合場合 |
---|---|---|---|
git revert | 新增一個「撤銷指定 commit」的提交 | 保留歷史 | 公開分支、多人協作 |
git reset | 將分支指標移動到指定 commit | 改寫歷史 | 私人分支、尚未 push 的情況 |
範例
git revert
1 | A - B - C - D (main) |
假設要還原 C
,git revert C
後會變成:
1 | A - B - C - D - E (main) |
E
這個新 commit 就是「還原 C 的內容」
git reset
1 | A - B - C - D (main) |
執行 git reset B
1 | A - B (main) |
原本的 C
和 D
會直接消失(歷史被改寫)
結論
語法 | 作用 |
---|---|
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 revert
和git reset
最大的差異在於是否「改寫歷史」:revert
會新增 commit,保留歷史。reset
則會刪掉歷史,不適合公開分支。