用 Claude Code 處理 Git Revert 連鎖:120 次 Revert 的生存指南


我們的專案 git 歷史中有 120 個 revert commit12 個 reapply commit

這不是什麼值得驕傲的數字。每一個 revert 背後都是一段「改壞了、趕快退回來」的故事。但回頭看,這些 revert 記錄了團隊在 Legacy 系統維護中最真實的掙扎。

這篇挑了五個最有代表性的 revert 故事,分析為什麼會發生、怎麼用 Claude Code 降低 revert 的機率。


故事一:34 秒內 4 次 Revert

時間線

同一天內,一個 issue 經歷了 4 次 merge 和 4 次 revert:

10:23  v1 commit — 修正指標頁面打勾顯示問題
11:00  v1 merge PR
11:39  v2 commit — 「還原排版」
11:42  v2 merge PR
13:34  v3 commit — 修正「持續載入中」問題
13:38  v3 merge PR
13:59  v4 commit — 修復因異動導致的載入問題
14:26  v4 merge PR

15:58:13  ❌ Revert v4
15:58:40  ❌ Revert v3
15:58:43  ❌ Revert v2
15:58:47  ❌ Revert v1

四次 revert 在 34 秒內完成,按照 v4 → v3 → v2 → v1 的反向順序。

為什麼會這樣

v1 的 diff 顯示 817 行新增、793 行刪除——1,610 行的變動量。但問題只是「打勾沒顯示」,不需要動這麼多行。

原因是 v1 混入了大量排版修改(空格、縮排、換行)。這讓 code review 幾乎不可能——真正的邏輯修改淹沒在排版差異中。

v2 的存在就是為了「還原排版,只保留 bug 修復」。但還原不乾淨,引入了新的載入問題(v3 修)。v3 又引入其他問題(v4 修)。最後乾脆全部 revert。

教訓

邏輯修改和排版修改永遠要分開 commit。 混在一起的後果:

  • Code review 看不出真正改了什麼
  • 出問題時無法只 revert 邏輯,排版改動也被退回
  • 「還原排版」本身又可能引入新問題

Claude Code 怎麼幫忙

> 這個 diff 有 1,600 行變動,但實際邏輯修改應該很少。
  幫我分離出純邏輯修改和純排版修改。

Claude Code 可以讀完整個 diff,標記哪些是空白/縮排變更、哪些是實際邏輯改動。在提交 PR 之前做這個檢查,就能避免「大 diff 小修改」的陷阱。


故事二:傷口標記的五個版本

時間線

一個「傷口癒合後標記消失」的 bug,修了整整一週、5 個版本:

Day 1  v1 — 修正癒合紀錄的標記查詢邏輯
Day 5  v2 — 修正列印和 WORD 匯出中的標記
Day 6  v3 — WORD 匯出的 GD 圖片有問題,退回無標記版本
       ❌ Revert v3 — 決定還是要標記
       v4 — 修改生圖失敗時的預設圖處理
Day 7  v5 — 終於找到根因:換字體

為什麼修了五次

每一版都只修了「表面症狀」,沒有找到根因:

版本修了什麼實際根因
v1SQL 查詢邏輯不是查詢問題
v2列印 + WORD 匯出不是匯出問題
v3退回無標記版本放棄式修正
v4預設圖片處理接近根因但沒到
v5換字體FreeSansBold.ttf 不支援 # 符號的渲染

v5 的修改只有一行——把字體從 FreeSansBold.ttf 換成 NotoSansTC-VariableFont_wght.ttf

教訓

在修 bug 之前,先確認根因。 五個版本的工作量加起來可能有幾十小時,但如果一開始就問對問題:「為什麼 # 符號會變成方框?」,答案就是「字體不支援」。

Claude Code 怎麼幫忙

> GD 渲染的 # 符號顯示為方框,可能的原因有哪些?

Claude Code 會列出:1. 字體不支援該字元 2. 編碼問題 3. GD 版本差異。第一個猜測就是正確答案。


故事三:Revert 再 Reapply——44 分鐘的猶豫

時間線

Day 1   merge PR — 某客製功能(取消表單欄位聯動)
Day 7   ❌ Revert — 退回 merge
         (44 分鐘後)
        ✅ Reapply — 又把 revert 退回(等於恢復原本的 merge)

為什麼會這樣

這是一個客製化功能——只影響特定機構。Revert 的原因可能是:有人在其他機構看到了非預期的行為,以為是這個 PR 造成的。44 分鐘後確認不是這個 PR 的問題,又 reapply。

教訓

Revert 之前先確認因果關係。 不是「這個 PR merge 之後出了問題」就代表「問題是這個 PR 造成的」。

這種「先 revert 再調查」的策略在緊急情況下是合理的,但如果不是緊急情況,先調查再決定是否 revert 會避免很多 git 歷史混亂。


故事四:63 秒的 Revert-of-Revert

時間線

11:12:05  ❌ Revert — 批次 revert 三個 issue 的 cherry-picks
11:13:08  ✅ Revert of Revert — 63 秒後把 revert 退回

有人把三個功能的 cherry-pick 一次 revert 掉了。63 秒後意識到不對,又 revert 了那個 revert。

Git 歷史的樣子

commit abc1234 — Revert "Revert issue-X, issue-Y, issue-Z cherry-picks"
commit def5678 — Revert issue-X, issue-Y, issue-Z cherry-picks

Revert of Revert 是 git 歷史中最令人困惑的模式。三個月後有人看到這段歷史,需要花很長時間才能理解「所以最終結果是什麼?這些功能到底在不在?」

教訓

在做大範圍 revert 之前,花 5 分鐘確認影響範圍。特別是批次 revert 多個 issue 時——你可能只想退回其中一個,但 revert 了全部。


故事五:Revert v2 → Revert v1 → Reapply v1 → 繼續開發 v3-v5

時間線

Day 1  v1 commit + merge
       v2 commit + merge(4 分鐘後)
       ❌ Revert v2(4 小時後)
       ❌ Revert v1(21 秒後)
       v3 commit — 重新實作邏輯
       ✅ Reapply v1(16 分鐘後)
       v3 additional commit
       v3 merge
Day 2  v4
Day 5  v5 — 最終修正

分析

21 秒內 revert 了 v2 和 v1(反向順序),然後 16 分鐘後 reapply 了 v1。這表示 v1 的修改是對的,v2 才是問題。但 revert 的順序是 v2 → v1(因為 git revert 要從最新的開始),結果 v1 也被誤殺了。

教訓

如果只需要退回 v2,不要連 v1 一起 revert。 Git 可以選擇性 revert 單一 commit。但在時間壓力下,人傾向「全部退回到安全狀態」,然後再逐一恢復需要的部分。


120 個 Revert 的統計

模式次數佔比
單次 revert(修壞了,退回)~9075%
Revert + Reapply(退回又恢復)~1210%
多次 revert 連鎖(同一 issue 2+ 次 revert)~1815%

高 revert 率的 issue

有些 issue 特別「多災多難」:

  • 電子給藥功能:6 次 revert(跨多個 release 分支)
  • 用藥排序功能:4 次 revert
  • 照顧紀錄表 V3:3 次 revert(v1/v2/v3)
  • 指標頁面打勾:4 次 revert(本文故事一)
  • 除錯相關:4 次連續 revert

用 Claude Code 降低 Revert 率

1. 提交前檢查 diff 範圍

> 這個 PR 的 diff 有多少行?
  有沒有混入不相關的排版修改?

故事一的教訓:大 diff 是 revert 的溫床。

2. 修 Bug 前先確認根因

> 這個症狀的可能根因有哪些?按可能性排序。

故事二的教訓:不要修表面症狀,花 10 分鐘讓 Claude Code 分析根因可以省 10 小時。

3. Revert 前先確認影響範圍

> 這個 commit 修改了哪些檔案?影響哪些功能?
  如果 revert,哪些已經依賴它的修改也會受影響?

故事四的教訓:批次 revert 前先看清楚會連帶退回什麼。

4. 在隔離環境中驗證

> 幫我在 worktree 中測試這個修改,不影響主分支

Claude Code 的 worktree 功能可以在隔離環境中驗證修改,確認沒問題再 merge。

5. 客製化功能的影響範圍檢查

> 這個修改只影響特定機構的邏輯嗎?
  有沒有可能影響到其他機構?

故事三的教訓:客製功能出問題時,先確認是不是這個 PR 造成的。


Revert 不是失敗,但可以更少

Revert 本身不是壞事——它是 git 提供的安全網。比起「改壞了硬撐」,果斷 revert 然後重來才是正確的做法。

但 120 次 revert 說明了一些系統性的問題:

  1. Code review 不足——大 diff 難 review,容易放過問題
  2. 根因分析不足——修表面症狀導致反覆修改
  3. 測試環境不足——只能在 release 分支上驗證
  4. 時間壓力——每週 release 的節奏下,「先 merge 再說」很常見

Claude Code 能幫上忙的是前兩點:讓 diff 更乾淨、讓根因分析更快。後兩點需要流程上的改變,AI 幫不了。

但即使只解決前兩點,revert 率就能顯著下降。因為大部分 revert 的根因都是「改太多」或「改錯方向」。