iT邦幫忙

2025 iThome 鐵人賽

DAY 21
0
Modern Web

Git 起來!每日一招學起來系列 第 21

Day 21:git revert —— 撤回修改的安全後悔藥

  • 分享至 

  • xImage
  •  

《Git 起來!》系列來到了最後十天,讓我們開始逐漸深入瞭解 Git 的進階功能吧!

在專案開發中,難免會出現「啊,我剛剛那個 commit 好像做錯了」的情況。

這時候,很多人第一個想到的就是 git reset,但是 —— reset 會改變歷史
一旦你已經推到遠端,團隊其他人會瞬間崩潰 😱。

所以 Git 準備了一個更安全的工具:git revert

它的概念是:

與其假裝錯誤沒發生,不如大方承認,並且用一個新的 commit 來修正。

它就是你的 安全後悔藥:撤回 commit 的內容,但保留歷史完整,團隊合作更安心。


什麼是 git revert

簡單來說:

git revert <commit> = 新增一個「反向 commit」,把指定 commit 的修改抵銷

特點:

  • 不會刪掉原本 commit
  • 歷史完整,團隊友好
  • 適合用於已經 push 遠端的 commit

比喻:

你的 commit 是日記上的一行,如果寫錯了,revert 就是在旁邊寫一行「改正註解」,而不是直接撕掉原本的日記。


重點圖示

假設歷史是這樣:

A --- B --- C --- D  (main)

你發現 commit C 有錯,需要撤回。

1️⃣ 如果用 reset(危險,改歷史)

git reset --hard B

結果:

A --- B  (main)
  • commit CD 都消失了(被 reset 抹掉)
  • 本地 OK,但如果 C 已經 push 遠端,會造成團隊困擾

2️⃣ 如果用 revert(安全)

git revert C

結果:

A --- B --- C --- D --- C'  (main)
  • C' 就是自動產生的反向提交,把 C 的改動抵銷
  • 歷史完整保留,適合團隊協作,不會破壞遠端歷史

如果壞掉的不只一個,可以指定範圍:

git revert A..C

這樣會反向的依序還原 B、C 的變更(注意:範圍 A..C 是「不含 A 本身,直到 C」)。

結果:

A --- B --- C --- D --- C' --- B'   (main)
  • 其中 C'B' 是用來抵銷 CB 的新 commit(先 C' 、再 B'

如果連 A 也一併 revert,就要用:

git revert A^..C
# 或
git revert A~..C
  • A^ & A~ :表示 A 的前一個 commit,這樣範圍就會覆蓋到 A

基本用法

假設我們有一個錯誤的提交:

git log --oneline
abc123 修錯的功能
def456 新增登入頁面
...

我們想要「撤銷」abc123,就可以執行:

# 撤回單一 commit
git revert <commit-hash>

# 範例
git revert abc123

執行後會進入編輯 commit 訊息畫面,預設訊息通常是:

Revert "原本 commit 訊息"

可以保留或修改訊息,然後儲存退出即可。

這時候 Git 會幫你建立一個「新的 commit」,內容是「把 abc123 做的修改反向操作」。
換句話說,它不會抹掉歷史,而是新增一個 commit 來打臉錯誤。


撤回多個 commit

有時候你會一次做了幾個連環錯誤 commit ,也可以用範圍一次還原:

git revert <old_commit>..<new_commit>

# 連續撤回最近三個 commit
git revert HEAD~2..HEAD

# 撤回指定的 commit-hash 範圍
git revert abc123..def456
  • 從 HEAD~2 到 HEAD 逐個產生反向 commit
  • abc123 之後到 def456 的提交全部反向操作

⚠️ 注意:這會逐一產生多個 revert commit,而非一次性覆蓋。若 commit 很多,建議分批操作


已推送遠端的撤回

  1. 確認本地分支最新:

    git pull
    
  2. 使用 git revert 產生反向 commit

  3. 推送到遠端:

    git push origin main
    

同事拉取後,修改就會被「安全撤回」。


Revert 遇到衝突

有時候 revert 也會遇到衝突,這時候流程和解決 merge 衝突很像,必須手動解決衝突並重新提交。

解決流程如下:

git revert <commit_hash>
# 發生衝突
# 解決檔案衝突後
git add .
git revert --continue

小提醒:如果在執行過程中遇到衝突,git revert 會中止並要求你解決衝突,解決完要用 git revert --continue(或用 --skip 跳過、--abort 取消)。


小技巧

  • 撤回 merge commit:需要加 m 1 指定父分支

    git revert -m 1 <merge-commit-hash>
    
  • 配合 branch:如果不確定,先在 feature branch 試 revert,再 merge 回 main

  • 如果只想暫時看看結果,可以加 -no-commit

    git revert <commit-hash> --no-commit
    

    這樣改動會套用到工作目錄,但不會立刻生成 commit,讓你可以先檢查。

  • 在團隊合作中,建議盡量用 git revert 取代 git reset,避免搞亂大家的歷史紀錄。


Reset vs Revert

指令 特性 適用情境
git reset 回到指定版本,刪除之後的歷史 個人開發、尚未分享給他人
git revert 產生一個新提交,抵銷指定版本的修改 團隊協作、需要保留歷史

git reset:把專案狀態倒回去,好像把時間線硬生生抹掉。
git revert:在現有歷史的基礎上,再新增一個「反向 commit」,抵銷之前的修改。

簡單來說:

👉 reset = 假裝沒發生(會改歷史)
👉 revert = 承認錯了,但加註說明(不改歷史)


小挑戰 💪

  1. 對專案執行 git log --oneline,找出一個錯誤 commit
  2. 使用 git revert <commit-hash> 撤回修改
  3. 推送到遠端,確認同事拉下來後歷史完整
  4. 嘗試一次撤回多個 commit
  5. 觀察 commit 歷史,理解 revert 如何保留歷史

小結

  • git revert 會新增一個「反向 commit」,安全還原錯誤變更。
  • 不會像 git reset 那樣直接改寫歷史,因此非常適合團隊協作。
  • 如果你的修改已經 push 到遠端,請優先使用 revert,而不是 reset
  • 把錯誤留在歷史裡,是一種真實的開發紀錄 —— 這也是 Git 的精神。

想像每日 commit 是日記,revert 就是在旁邊貼上一行「更正註解」
不撕掉原本日記,團隊也看得懂。


上一篇
Day 20:git tag —— 重要瞬間的紀錄貼紙
下一篇
Day 22:git status & git log 進階 —— 專案考古學家的放大鏡
系列文
Git 起來!每日一招學起來23
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言