

就真的那麼剛好發生 force push 事故時, 時間就是一切。以下三種情境希望能解決到你的危急任務。讓你可以匆匆容容游刃有餘~
立即行動清單(黃金 5 分鐘,當然是越快越好)
發現錯誤的瞬間,立刻執行以下步驟:
步驟一:凍結操作(30 秒內)
# 1. 不要關閉終端機視窗!
# 2. 不要執行任何 git 命令!
# 3. 截圖或複製終端機輸出為什麼: 終端機中的 force push 輸出包含關鍵的 commit hash,是恢復的重要線索。
步驟二:緊急通知團隊(1 分鐘內)
立即在團隊頻道發布緊急通知:
🚨 緊急通知 🚨
我剛才誤對 [分支名稱] 執行了 force push
請所有人:
1. 立即停止推送任何程式碼
2. 不要執行 git pull
3. 保持現有的本地分支狀態
我正在進行恢復操作,約需 5-10 分鐘步驟三:評估損害範圍(2 分鐘內)
快速檢查影響範圍:
指令 1:查看本地操作歷史
git reflog | head -20使用時機: 你是執行 force push 的操作者,需要查看本地的操作記錄
說明:
git reflog顯示本地 HEAD 的移動歷史,包含所有操作(commit、checkout、reset 等)| head -20只顯示最近 20 筆記錄,避免輸出過多- 這個記錄是純本地的,即使遠端分支被覆蓋,本地的 reflog 仍然完整保存
輸出範例:
cf4c40e HEAD@{0}: commit: 正確的提交
e92a30e HEAD@{1}: commit: 前一個提交
f961cff HEAD@{2}: checkout: moving from main to feature-branch關鍵資訊: 從這裡可以找到 force push 之前的正確 commit hash
指令 2:更新並檢查遠端當前狀態
git fetch origin
git log origin/<分支名稱> --oneline --decorate --graph -10使用時機: 需要確認遠端分支現在的狀態(被覆蓋後的狀態)
說明:
git fetch origin更新本地的遠端追蹤分支,但不會改變你的工作目錄git log origin/<分支名稱>查看遠端分支的提交歷史-oneline每個提交只顯示一行(簡短格式)-decorate顯示分支名稱和標籤-graph用圖形方式顯示分支結構10只顯示最近 10 個提交
範例:
# 如果你 force push 的是 main 分支
git log origin/main --oneline --decorate --graph -10
# 如果是其他分支,例如 demo-branch
git log origin/demo-branch --oneline --decorate --graph -10輸出範例:
* 42ce27d (origin/demo-branch) WRONG COMMIT: 錯誤的提交
* d48e20c Initial commit關鍵用途: 確認遠端分支現在指向哪個錯誤的 commit,以及還剩下多少提交
指令 3:比較本地與遠端的差異
# 查看「遠端有,但本地沒有」的提交
git log HEAD..origin/<分支名稱> --oneline
# 查看「本地有,但遠端沒有」的提交
git log origin/<分支名稱>..HEAD --oneline使用時機: 需要了解哪些提交在 force push 後消失了
說明:
第一條命令 (HEAD..origin/<分支名稱>):
- 顯示遠端分支領先本地的提交
- 如果輸出為空,表示遠端沒有本地不知道的新提交
- 正常情況: 有其他人推送了新程式碼,你需要先 pull
- force push 後: 通常為空(因為遠端被你覆蓋了)
第二條命令 (origin/<分支名稱>..HEAD):
- 顯示本地分支領先遠端的提交
- 這些是存在於你本地但遠端沒有的提交
- force push 後: 如果輸出很多提交,表示那些是被你覆蓋掉的正確提交
範例:
# 假設你在 demo-branch 上執行了錯誤的 force push
git log HEAD..origin/demo-branch --oneline
# 輸出: (空的) - 表示遠端沒有新東西
git log origin/demo-branch..HEAD --oneline
# 輸出:
# cf4c40e Scenario1: 正常開發工作
# e92a30e feat: Add important feature
# f961cff Add user authentication
# 這些就是被覆蓋掉、需要恢復的提交!關鍵用途: 快速識別哪些提交需要恢復
指令 4(可選):完整的視覺化比較
git log --oneline --all --decorate --graph -20使用時機: 需要完整了解所有分支的關係和狀態
說明:
-all顯示所有分支(本地 + 遠端追蹤分支)- 這會產生一個完整的分支圖,幫助你理解整個情況
輸出範例:
* 42ce27d (origin/demo-branch) WRONG COMMIT
| * cf4c40e (HEAD -> demo-branch) Correct commit
| * e92a30e Another correct commit
|/
* d48e20c Initial commit關鍵用途: 視覺化地看到本地分支和遠端分支的分歧點
快速評估檢查清單
執行完上述指令後,你應該能回答以下問題:
- [ ] 遠端分支現在指向哪個 commit?(錯誤的那個)
- [ ] 正確的 commit hash 是什麼?(應該恢復的目標)
- [ ] 有多少個提交消失了?
- [ ] 這些消失的提交是誰的?(只有你的,還是包含其他人的)
- [ ] 本地是否還保留完整的歷史?
根據答案選擇恢復策略:
- 如果只有你的提交 → 使用「情境一」
- 如果包含其他人的提交 → 使用「情境二」或「情境三」
情境一:你是最後推送者(最簡單)
適用條件: 在你 force push 之前,沒有其他人推送過新提交。
判斷方法:
- 你剛執行完 force push,終端機視窗還開著
- 從「步驟三:評估損害範圍」得知只有你自己的提交被影響
- 你是最後一個推送到這個分支的人
步驟 1:從終端機輸出找回正確的 commit
關鍵線索:終端機的 force push 輸出
在終端機中查看 force push 的輸出:
+ deadbeef...f00f00ba main -> main (forced update)輸出格式解析:
+符號:表示這是一個強制更新(非 fast-forward)deadbeef: 被覆蓋前的最後一個正確提交 ← 這是你要恢復的目標!...: 表示從 deadbeef 到 f00f00ba 之間有歷史變更f00f00ba: 你錯誤推送的提交(現在遠端指向這個)main -> main: 本地 main 分支推送到遠端 main 分支(forced update): 確認這是強制更新
實際範例 (從我們的驗證測試):
+ cf4c40e...42ce27d wrong-branch -> demo-branch (forced update)- 要恢復的正確 commit:
cf4c40e - 錯誤的 commit:
42ce27d
⚠️ 重要: 如果你已經關閉終端機,跳到「方式二」從 reflog 查找
步驟 2:立即恢復遠端分支
方式一:直接使用終端機輸出的 commit hash(最快速)
git push --force origin <正確的commit-hash>:<分支名稱>使用時機: 你的終端機還開著,能看到 force push 的輸出
指令說明:
git push --force: 再次使用強制推送(這次是為了恢復)origin: 遠端儲存庫名稱<正確的commit-hash>: 從終端機輸出找到的正確 commit(例如deadbeef或cf4c40e):<分支名稱>: 要更新的遠端分支名稱(例如:main或:demo-branch)
實際範例:
# 從輸出 "+ cf4c40e...42ce27d" 得知要恢復 cf4c40e
git push --force origin cf4c40e:demo-branch
# 或者使用完整的 hash
git push --force origin cf4c40e01485d26fa11cc4058caf619de23e71d7:demo-branch預期輸出:
+ 42ce27d...cf4c40e cf4c40e -> demo-branch (forced update)這表示成功將遠端從錯誤的 42ce27d 恢復到正確的 cf4c40e
為什麼這樣做有效:
- Git 的 commit 是永久不變的,只要知道 hash 就能直接引用
- 你不需要在本地有那個 commit 的分支,直接推送 hash 即可
- 這是最快的恢復方式,通常在 30 秒內完成
方式二:從本地 reflog 查找(如果終端機已關閉)
步驟 2.1:查看 HEAD 的 reflog
git reflog使用時機: 你關閉了終端機,或者看不到 force push 的輸出
指令說明:
git reflog顯示本地 HEAD 的所有移動記錄- 包含 commit、checkout、reset、merge 等所有操作
- 預設保留 90 天的歷史記錄
輸出範例:
42ce27d HEAD@{0}: commit: WRONG COMMIT: 這是錯誤的提交
cf4c40e HEAD@{1}: commit: Scenario1: 正常開發工作 - 應該被保留的提交
e92a30e HEAD@{2}: commit: feat: Add important feature
f961cff HEAD@{3}: checkout: moving from main to demo-branch如何找到正確的 commit:
- 找到 force push 操作的那一行(可能顯示為
push或你執行 force push 前的最後一個 commit) - 向上看一行,那就是被覆蓋前的正確狀態
- 記下那個 commit hash(例如
cf4c40e)
步驟 2.2:查看遠端追蹤分支的 reflog(更精確)
git reflog show origin/<分支名稱>使用時機: 需要更精確地找到遠端分支被覆蓋前的狀態
指令說明:
git reflog show origin/<分支名稱>顯示本地對遠端分支的追蹤記錄- 這個記錄追蹤的是
git fetch和git push如何改變遠端分支 - 比
git reflog更精確,因為它專注於遠端分支的變化
範例:
# 查看 origin/main 的歷史
git reflog show origin/main
# 查看 origin/demo-branch 的歷史
git reflog show origin/demo-branch輸出範例:
42ce27d refs/remotes/origin/demo-branch@{0}: push: forced update
cf4c40e refs/remotes/origin/demo-branch@{1}: fetch: forced update
e92a30e refs/remotes/origin/demo-branch@{2}: fetch: fast-forward關鍵資訊:
@{0}: 最新狀態(錯誤的 force push 結果)@{1}: 上一個狀態(這通常是正確的!)- 找到
@{1}對應的 commit hash(例如cf4c40e)
步驟 2.3:執行恢復推送
git push --force origin <找到的commit-hash>:<分支名稱>範例:
# 從 reflog 找到正確的 commit 是 cf4c40e
git push --force origin cf4c40e:demo-branch步驟 3:驗證恢復結果
恢復完成後,必須驗證以確保一切正確。
驗證步驟 3.1:更新本地的遠端追蹤資訊
git fetch origin使用時機: 每次恢復後的第一步
指令說明:
- 從遠端下載最新的分支資訊
- 更新本地的遠端追蹤分支(
origin/main、origin/demo-branch等) - 不會改變你的工作目錄或當前分支
- 這是一個安全的操作,只是同步資訊
預期輸出:
From gitlab.com:james-berget/git_demo
+ 42ce27d...cf4c40e demo-branch -> origin/demo-branch (forced update)驗證步驟 3.2:檢查遠端分支的提交歷史
git log origin/<分支名稱> --oneline -5使用時機: 確認遠端分支現在有正確的提交歷史
指令說明:
git log origin/<分支名稱>顯示遠端分支的提交歷史-oneline每個提交顯示一行(簡潔格式)5只顯示最近 5 個提交
範例:
git log origin/demo-branch --oneline -5預期輸出 (應該看到所有正確的提交):
cf4c40e (origin/demo-branch) Scenario1: 正常開發工作 - 應該被保留的提交
e92a30e feat: Add important feature - CORRECT COMMIT TO PRESERVE
f961cff Add user authentication - CORRECT COMMIT
6d0a795 Add test file 1 - normal development
d48e20c Initial commit驗證要點:
- ✅ 最新的 commit 是你要恢復的那個(例如
cf4c40e) - ✅ 所有應該存在的提交都在歷史中
- ❌ 不應該看到錯誤的 commit(例如
42ce27d)
驗證步驟 3.3:確認最新 commit 的完整 hash
git rev-parse origin/<分支名稱>使用時機: 需要 100% 確認遠端分支指向正確的 commit
指令說明:
git rev-parse將引用(分支名、標籤等)轉換為完整的 commit hash- 這是最精確的驗證方式
範例:
git rev-parse origin/demo-branch預期輸出:
cf4c40e01485d26fa11cc4058caf619de23e71d7驗證方式:
- 將這個 hash 與你從終端機輸出或 reflog 找到的正確 commit 比對
- 應該完全一致(至少前 7 個字元一致)
驗證步驟 3.4(可選):比對檔案內容
# 切換到本地的正確分支
git checkout <分支名稱>
# 比較本地和遠端的差異
git diff origin/<分支名稱>使用時機: 想要確認檔案內容完全一致
指令說明:
git diff比較兩個提交之間的差異- 如果恢復成功,應該沒有任何差異
預期輸出:
- 如果完全一致:沒有任何輸出(這是好事!)
- 如果有差異:會顯示不同的檔案和內容
步驟 4:通知團隊恢復完成
立即發送恢復成功通知
在團隊頻道發送以下訊息:
恢復完成 - 緊急事故已解決!
分支 [分支名稱] 已恢復到正確狀態
恢復資訊:
- 恢復的 commit: <commit-hash>
- 恢復時間: <實際花費時間,例如: 2分鐘>
- 受影響範圍: 僅我個人的推送
後續行動:
- 大家可以繼續正常工作
- 如果你的本地分支與遠端有衝突,請執行:
git fetch origin
git reset --hard origin/<分支名稱>
如有任何問題請立即回報實際範例
恢復完成 - 緊急事故已解決
分支 demo-branch 已恢復到正確狀態
恢復資訊:
- 恢復的 commit: cf4c40e (Scenario1: 正常開發工作)
- 恢復時間: 2分鐘
- 受影響範圍: 僅我個人的推送
後續行動:
- 大家可以繼續正常工作
- 如果你的本地分支與遠端有衝突,請執行:
git fetch origin
git reset --hard origin/demo-branch
如有任何問題請立即回報情境一完整操作檢查清單
執行完所有步驟後,確認以下項目:
- [ ] 從終端機輸出或 reflog 找到正確的 commit hash
- [ ] 執行
git push --force origin <hash>:<branch>恢復遠端分支 - [ ] 執行
git fetch origin更新本地資訊 - [ ] 執行
git log origin/<branch>確認提交歷史正確 - [ ] 執行
git rev-parse origin/<branch>確認 commit hash 正確 - [ ] 通知團隊恢復完成
- [ ] 所有團隊成員確認可以正常工作
如果所有項目都勾選,恭喜你!成功從 force push 災難中恢復了!🎉
情境二:其他人的提交也被覆蓋(中等難度)
適用條件: 在你 force push 之前,其他團隊成員已經推送了新提交,現在這些提交都消失了。
判斷方法:
- 從「步驟三:評估損害範圍」發現遺失的提交包含其他人的工作
- 執行
git log origin/<branch>..HEAD看到多位開發者的提交 - 團隊成員回報他們推送的程式碼消失了
與情境一的差異:
- 情境一:只有你自己的提交,可以直接 force push 恢復
- 情境二:包含多人的提交,需要建立恢復分支後合併(更安全)
步驟 1:找到所有遺失的提交
方法 A:使用本地 reflog 查找(最快速)
git reflog | head -20使用時機: 你的本地儲存庫還保留完整的歷史
指令說明:
- 查看本地 HEAD 的移動歷史
- 找到 force push 之前的最後一個正確提交
- 這是最快速的方法,因為不需要依賴遠端或其他人
輸出範例:
935ccec HEAD@{0}: commit: WRONG COMMIT: Accidental force push
04c363a HEAD@{1}: reset: moving to HEAD~3
c6e1b9e HEAD@{2}: commit: Developer C - Add analytics dashboard
eb0562b HEAD@{3}: commit: Developer B - Add order processing
370dbde HEAD@{4}: commit: Developer A - Add user login關鍵資訊: c6e1b9e 是包含所有開發者提交的最後正確狀態
方法 B:使用遠端追蹤分支的 reflog
git reflog show origin/<分支名稱>使用時機: 需要確認遠端分支被覆蓋前的狀態
指令說明:
origin/<分支名稱>替換為實際的分支名(如origin/main)- 顯示本地對遠端分支的追蹤記錄
- 可以看到 force push 前後的 commit hash
範例:
# 查看 main 分支的遠端追蹤歷史
git reflog show origin/main
# 查看其他分支
git reflog show origin/develop輸出範例:
935ccec refs/remotes/origin/scenario2-test@{0}: update by push
c6e1b9e refs/remotes/origin/scenario2-test@{1}: update by push分析: @{1} 位置的 c6e1b9e 就是要恢復的目標
方法 C:使用 GitHub/GitLab 網頁介面
使用時機: 本地 reflog 不可用,或需要從遠端平台獲取資訊
GitHub 操作步驟:
- 前往 Commits 頁面:
- URL 格式:
https://github.com/[組織]/[專案]/commits/[分支名稱] - 範例:
https://github.com/myteam/myproject/commits/main
- URL 格式:
- 查看提交歷史:
- 即使 commit 已經不在任何分支上,GitHub 仍會保留一段時間
- 在頁面上找到 force push 之前的最後一個正常提交
- 記下該 commit 的 hash(點擊提交可以看到完整 hash)
- 使用 GitHub API(進階方法):
# 查看最近的 push 事件
curl -H "Authorization: token YOUR_GITHUB_TOKEN" \
<https://api.github.com/repos/[owner]/[repo]/events> \
| jq '.[] | select(.type == "PushEvent")'GitLab 操作步驟:
- 前往專案頁面 → Repository → Commits
- 在右上角的分支選擇器查看歷史
- 或使用 GitLab API:
curl --header "PRIVATE-TOKEN: YOUR_TOKEN" \
"<https://gitlab.com/api/v4/projects/[project_id]/events>"方法 D:詢問團隊成員
使用時機: 無法從 reflog 或遠端找到完整資訊
在團隊頻道發送請求:
🔍 緊急協助請求
我剛才誤對 [分支名稱] 執行了 force push
需要找回被覆蓋的提交
請問有人在 [時間範圍,例如:今天下午 2 點後] 推送過程式碼嗎?
如果有,請執行以下命令並回報結果(不要執行其他 git 命令):
git log --oneline -10
git rev-parse HEAD
請將輸出截圖或複製到討論串,謝謝!收集資訊:
- 記錄所有團隊成員回報的 commit hash
- 找出最新的那個 commit(通常是被覆蓋前的最後狀態)
- 確認該 commit 包含所有人的工作
範例回報:
開發者 A: 我的最後一個 commit 是 370dbde
開發者 B: 我的是 eb0562b
開發者 C: 我的是 c6e1b9e (最新)從回報可知 c6e1b9e 是要恢復的目標
步驟 2:建立恢復分支
找到正確的 commit hash 後,建立恢復分支來保存這些提交。
2.1 從本地建立恢復分支
git branch recovery-<分支名稱>-<日期> <遺失的commit-hash>使用時機: 你的本地儲存庫有完整的歷史記錄
指令說明:
git branch: 建立新分支的命令recovery-<分支名稱>-<日期>: 恢復分支的命名規範- 使用
recovery-前綴便於識別 - 包含原始分支名稱
- 加上日期(格式:YYYYMMDD)便於追蹤
- 使用
<遺失的commit-hash>: 從步驟 1 找到的正確 commit hash
實際範例:
# 為 main 分支建立恢復分支
git branch recovery-main-20251017 c6e1b9e
# 為 develop 分支建立恢復分支
git branch recovery-develop-20251017 abc1234
# 使用完整的 hash 也可以
git branch recovery-main-20251017 c6e1b9e01485d26fa11cc4058caf619de23e71d7預期輸出: (沒有輸出表示成功)
驗證分支已建立:
git branch -v | grep recovery2.2 推送恢復分支到遠端
git push origin recovery-<分支名稱>-<日期>使用時機: 建立本地恢復分支後的下一步
指令說明:
- 將恢復分支推送到遠端儲存庫
- 讓團隊成員可以查看和驗證恢復內容
- 作為遠端備份,避免本地資料遺失
範例:
git push origin recovery-main-20251017預期輸出:
Enumerating objects: 10, done.
Counting objects: 100% (10/10), done.
Writing objects: 100% (9/9), 1.42 KiB | 1.42 MiB/s, done.
Total 9 (delta 4), reused 0 (delta 0)
To gitlab.com:myteam/myproject.git
* [new branch] recovery-main-20251017 -> recovery-main-202510172.3 如果本地沒有完整歷史
# 方法一:如果 GitHub 上還能看到該 commit
# 直接在 GitHub 網頁介面操作:
# 1. 前往該 commit 頁面
# 2. 點擊 commit hash 旁的 "<>" 按鈕
# 3. 在分支下拉選單輸入: recovery-main-20251017
# 4. 點擊 "Create branch"
# 方法二:從團隊成員的本地儲存庫獲取
# 請參考「情境三」的做法使用時機: 你的本地儲存庫已經沒有完整的歷史記錄
GitHub 網頁操作優點:
- 不需要本地有完整歷史
- 操作簡單直觀
- 立即在遠端建立分支
⚠️ 注意: 如果 GitHub 上也找不到該 commit,需要使用情境三的方法
步驟 3:驗證恢復分支內容
建立恢復分支後,必須驗證內容是否正確,避免恢復錯誤的版本。
3.1 切換到恢復分支
git checkout recovery-<分支名稱>-<日期>使用時機: 需要檢查恢復分支的內容
指令說明:
- 切換工作目錄到恢復分支
- 讓你可以查看檔案和提交歷史
範例:
git checkout recovery-main-20251017預期輸出:
Switched to branch 'recovery-main-20251017'3.2 檢查提交歷史
git log --oneline -10使用時機: 確認恢復分支包含所有必要的提交
指令說明:
-oneline: 每個提交顯示一行,便於快速瀏覽10: 顯示最近 10 個提交(可根據需要調整)
預期輸出:
c6e1b9e feat: Developer C - Add analytics dashboard
eb0562b feat: Developer B - Add order processing system
370dbde feat: Developer A - Add user login feature
04c363a test: add synthetic record #15
...驗證要點:
- 看到所有開發者的提交
- 提交順序正確
- 提交訊息符合預期
3.3 比較恢復分支與事故分支的差異
git log --oneline <事故分支>..<恢復分支>使用時機: 需要確認哪些提交在事故中遺失了
指令說明:
<事故分支>..<恢復分支>: 顯示恢復分支比事故分支多出的提交- 這些就是需要恢復的內容
範例:
# 比較 main 分支與恢復分支
git log --oneline main..recovery-main-20251017
# 比較當前分支(事故分支)與恢復分支
git log --oneline scenario2-test..recovery-scenario2-20251017預期輸出:
c6e1b9e feat: Developer C - Add analytics dashboard
eb0562b feat: Developer B - Add order processing system
370dbde feat: Developer A - Add user login feature分析: 這三個提交就是在 force push 中遺失的,需要恢復
3.4 查看檔案差異(可選)
git diff <事故分支>..<恢復分支>使用時機: 需要查看具體的程式碼變更
指令說明:
- 顯示兩個分支之間所有檔案的差異
- 幫助確認恢復的內容是否正確
範例:
git diff main..recovery-main-20251017輸出: 會顯示所有新增、修改、刪除的檔案內容
⚠️ 注意: 如果輸出很多,可以只檢查特定檔案:
git diff main..recovery-main-20251017 -- path/to/important/file.js3.5 檢查檔案清單
ls -la使用時機: 快速確認關鍵檔案是否存在
範例: 在驗證測試中,我們確認了以下檔案存在:
ls -la scenario2_*.txt預期輸出:
scenario2_developer_A_feature.txt
scenario2_developer_B_feature.txt
scenario2_developer_C_feature.txt步驟 4:將恢復分支合併回主分支
驗證完成後,使用合併方式將遺失的提交恢復到事故分支。
4.1 切回事故分支
git checkout <分支名稱>使用時機: 驗證完恢復分支後,準備執行合併
指令說明:
- 切回原本發生事故的分支
- 在這個分支上執行合併操作
範例:
# 切回 main 分支
git checkout main
# 切回 scenario2-test 分支
git checkout scenario2-test預期輸出:
Switched to branch 'main'
Your branch is up to date with 'origin/main'.4.2 執行合併(使用 –no-ff)
git merge --no-ff recovery-<分支名稱>-<日期> -m "Merge: 恢復因 force push 遺失的提交"使用時機: 準備將恢復分支的提交合併回來
指令說明:
git merge: 合併分支的命令-no-ff: 非常重要,強制建立合併提交- 保留完整的分支歷史
- 清楚顯示這是一次恢復操作
- 便於日後追蹤和審查
m "訊息": 指定合併提交的訊息
為什麼要使用 –no-ff:
- 不使用
-no-ff: Git 可能使用 fast-forward,歷史看起來像直線 - 使用
-no-ff: 保留分支結構,清楚顯示合併點
範例:
git merge --no-ff recovery-main-20251017 -m "Merge: 恢復因 force push 遺失的提交"
# 更詳細的訊息範例
git merge --no-ff recovery-main-20251017 -m "Merge: 恢復因 force push 遺失的提交
包含以下開發者的工作:
- Developer A: 使用者登入功能
- Developer B: 訂單處理系統
- Developer C: 資料分析儀表板
事故發生時間: 2025-10-17 14:00
恢復執行者: [你的名字]"預期輸出:
Merge made by the 'ort' strategy.
scenario2_developer_A_feature.txt | 13 +++++++++++++
scenario2_developer_B_feature.txt | 13 +++++++++++++
scenario2_developer_C_feature.txt | 13 +++++++++++++
3 files changed, 39 insertions(+)
create mode 100644 scenario2_developer_A_feature.txt
create mode 100644 scenario2_developer_B_feature.txt
create mode 100644 scenario2_developer_C_feature.txt分析:
- 合併成功
- 三個檔案已加入
- 顯示新增的行數
4.3 查看合併後的提交圖
git log --oneline --graph -10使用時機: 合併後驗證分支結構
指令說明:
-graph: 以圖形方式顯示分支結構- 可以清楚看到合併點和分支關係
預期輸出:
* 01ab8ad (HEAD -> scenario2-test) Merge: 恢復因 force push 遺失的提交
|\
| * c6e1b9e (recovery-scenario2-20251017) feat: Developer C
| * eb0562b feat: Developer B
| * 370dbde feat: Developer A
* | 935ccec WRONG COMMIT
|/
* 04c363a Initial commit分析:
- 清楚顯示合併的分支結構
- 錯誤提交(935ccec)保留在歷史中(用於事故追蹤)
- 所有遺失的提交都已恢復
4.4 推送到遠端
git push origin <分支名稱>使用時機: 合併完成後,將恢復結果推送到遠端
指令說明:
- 這是正常的 push,不需要
-force - 因為我們使用合併方式,不是覆蓋歷史
範例:
git push origin main
# 如果遠端拒絕(不應該發生),檢查是否有分支保護
git push origin scenario2-test預期輸出:
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Writing objects: 100% (2/2), 368 bytes | 368.00 KiB/s, done.
Total 2 (delta 1), reused 0 (delta 0)
To gitlab.com:myteam/myproject.git
935ccec..01ab8ad scenario2-test -> scenario2-test分析:
- 推送成功
- 從 935ccec(錯誤提交)更新到 01ab8ad(合併提交)
步驟 5:驗證恢復結果
推送完成後,必須進行全面驗證確保恢復成功。
5.1 更新本地的遠端追蹤資訊
git fetch origin使用時機: 推送後的第一步
指令說明:
- 從遠端下載最新的分支資訊
- 更新本地的遠端追蹤分支
- 確保本地與遠端同步
預期輸出: 通常沒有輸出(因為剛推送過)
5.2 檢查遠端分支的提交歷史
git log origin/<分支名稱> --oneline --graph -10使用時機: 確認遠端分支有正確的歷史
範例:
git log origin/main --oneline --graph -10
預期輸出:
驗證要點:
- 看到合併提交
- 所有遺失的提交都在歷史中
- 分支結構正確
5.3 確認最新 commit 的 hash
git rev-parse origin/<分支名稱>使用時機: 精確驗證遠端分支指向的提交
範例:
git rev-parse origin/main預期輸出:
01ab8ad7f84ad3ba2b09d4a465ca8cb02352bb74這應該是合併提交的完整 hash
5.4 比較本地與遠端(應該一致)
git diff origin/<分支名稱>使用時機: 最後確認本地與遠端完全一致
預期輸出: (沒有任何輸出,表示完全一致)
如果有輸出,表示還有差異,需要檢查原因。
5.5 驗證所有檔案已恢復
# 列出相關檔案
ls -la
# 或檢查特定檔案是否存在
test -f important_file.txt && echo "檔案存在" || echo "檔案不存在"使用時機: 確認關鍵檔案已經恢復
步驟 6:清理與通知團隊
6.1 發送恢復完成通知
在團隊頻道發送詳細的恢復報告:
恢復完成 - Force Push 事故已解決
分支 [分支名稱] 已成功恢復
恢復資訊:
- 事故發生時間: [時間]
- 恢復完成時間: [時間]
- 總耗時: [例如: 8 分鐘]
- 恢復的提交數: [例如: 3 個]
- 涉及開發者: [列出所有人]
恢復的提交:
- c6e1b9e: Developer C - 資料分析儀表板
- eb0562b: Developer B - 訂單處理系統
- 370dbde: Developer A - 使用者登入功能
後續行動:
1. 所有人請執行以下命令同步:
git fetch origin
git pull origin [分支名稱]
2. 如遇到衝突,請先備份本地工作:
git stash save "備份-恢復前"
3. 驗證你的提交是否都在:
git log --oneline -20
如有任何問題或發現遺漏的提交,請立即回報6.2 清理恢復分支(可選)
# 刪除本地恢復分支
git branch -d recovery-<分支名稱>-<日期>
# 刪除遠端恢復分支
git push origin --delete recovery-<分支名稱>-<日期>使用時機: 確認恢復成功且團隊驗證無誤後
範例:
git branch -d recovery-main-20251017
git push origin --delete recovery-main-20251017⚠️ 建議: 保留恢復分支幾天,直到確定一切正常
保留恢復分支的理由:
- 作為備份,以防需要重新恢復
- 便於事後分析和學習
- 提供清晰的審計記錄
情境二完整操作檢查清單
執行完所有步驟後,確認以下項目:
- [ ] 從 reflog 或遠端找到所有遺失的提交 hash
- [ ] 基於正確的 commit hash 建立恢復分支
- [ ] 推送恢復分支到遠端
- [ ] 切換到恢復分支並驗證內容
- [ ] 使用
git log確認所有遺失的提交都在恢復分支中 - [ ] 使用
git diff比較差異 - [ ] 切回事故分支
- [ ] 執行
git merge --no-ff合併恢復分支 - [ ] 使用
git log --graph檢查合併後的分支結構 - [ ] 推送合併後的分支到遠端(正常 push,不用 force)
- [ ] 執行
git fetch origin更新本地資訊 - [ ] 確認遠端分支的提交歷史正確
- [ ] 確認所有關鍵檔案已恢復
- [ ] 發送詳細的恢復完成通知給團隊
- [ ] 團隊成員驗證並同步
- [ ] (可選)清理恢復分支
如果所有項目都勾選,恭喜你!成功從情境二的 force push 災難中恢復了!🎉
情境三:完全無法從遠端找回(這真的就有點麻煩了…)
適用條件: GitHub/GitLab 事件流中也找不到遺失的提交,需要從團隊成員的本地儲存庫恢復。
判斷方法:
- 執行 force push 的操作者本地也沒有完整歷史(可能執行了
git reset --hard等破壞性操作) - GitHub/GitLab 網頁介面找不到遺失的 commit
- 執行
git reflog顯示的歷史也不完整或已被清理 - 這是最後的救援手段,必須依賴團隊成員的本地備份
與情境一、二的差異:
- 情境一: 操作者本地有完整歷史,直接 force push 恢復
- 情境二: 可從 reflog 或遠端平台找到 commit,建立恢復分支合併
- 情境三: 操作者和遠端都無法找回,必須依賴團隊成員
步驟 1:發送緊急求助訊息
1.1 立即在團隊頻道發送請求
使用時機: 確認本地和遠端都無法找回完整歷史的第一時間
在團隊頻道發送以下訊息:
🆘 緊急求助 - Force Push 事故 🆘
我剛才誤對 [分支名稱] 執行了 force push
而且我的本地歷史也不完整,無法從 reflog 恢復
需要找到在 [具體時間,例如:今天下午 2 點] 之前
有執行過 git pull 或 git fetch 的成員
如果你符合條件,請執行以下命令並截圖回報:
git log --oneline -10
⚠️ 重要:不要執行任何其他 git 命令!
⚠️ 特別是不要執行 git pull(會拉取損壞的遠端)
遺失的提交應該包含:
- [列出遺失的功能或開發者名稱]
- [例如:Developer A 的使用者認證系統]
- [例如:Developer B 的支付整合]為什麼這樣做:
- 清楚說明情況的嚴重性
- 明確指示不要執行
git pull(避免團隊成員的歷史也被覆蓋) - 提供具體的時間範圍幫助成員判斷
- 列出遺失的內容幫助成員確認他們的本地是否有
步驟 2:驗證團隊成員的本地歷史
2.1 團隊成員執行檢查命令
使用時機: 團隊成員收到求助訊息後,在自己的本地儲存庫執行
給團隊成員的指示:
# 步驟 2.1.1: 檢查本地提交歷史
git log --oneline -10使用時機: 快速查看最近的 10 個提交
指令說明:
git log: 顯示提交歷史-oneline: 每個提交顯示一行(簡潔格式)10: 只顯示最近 10 個提交
預期輸出:
d8d9535 feat: Developer C - 資料分析儀表板
7848581 feat: Developer B - 訂單處理系統
8cf0e5d feat: Developer A - 使用者認證系統
34d3940 test: add synthetic record #15
...如何判斷:
- ✅ 如果看到所有遺失的提交 → 你的本地有完整歷史!立即回報
- ❌ 如果缺少某些提交 → 你的本地不完整,繼續等待其他成員
# 步驟 2.1.2: 獲取完整的 commit hash
git rev-parse HEAD使用時機: 確認你的本地分支指向的確切 commit
指令說明:
git rev-parse: 將引用轉換為完整的 commit hashHEAD: 當前分支的最新提交
預期輸出:
d8d9535e7503b8aeb9976e6e368188ba32305c6e為什麼要記錄完整 hash:
- 提供給事故處理者驗證
- 確保恢復到正確的 commit
- 作為恢復操作的審計記錄
# 步驟 2.1.3: 確認當前分支
git branch使用時機: 確認你在正確的分支上
指令說明:
git branch: 列出所有本地分支- 當前分支會有 標記
預期輸出:
main
* scenario3-test ← 有 * 標記的是當前分支
feature-x
關鍵檢查:
- ✅ 確認 標記在事故分支上(例如
scenario3-test) - ❌ 如果不是,請不要切換分支,先回報當前狀態
2.2 事故處理者驗證回報
使用時機: 收到團隊成員的回報後
驗證清單:
- [ ] 該成員的
git log輸出包含所有遺失的提交 - [ ] 提交的順序和內容正確
- [ ] 最新的 commit 是被覆蓋前的正確狀態
- [ ] 該成員在正確的分支上
如果驗證通過,進入步驟 3
步驟 3:團隊成員執行恢復操作
⚠️ 關鍵警告: 以下操作由擁有完整歷史的團隊成員執行,不是事故處理者!
3.1 建立安全備份
git branch backup-before-fix-$(date +%Y%m%d-%H%M%S)使用時機: 執行任何恢復操作之前的第一步
指令說明:
git branch: 建立新分支backup-before-fix-$(date +%Y%m%d-%H%M%S): 分支名稱backup-before-fix-: 前綴,表示這是恢復前的備份$(date +%Y%m%d-%H%M%S): 自動插入當前日期時間(例如:20251017-143052)
預期輸出: (通常沒有輸出,表示成功)
驗證備份已建立:
git branch -v | grep backup預期輸出:
backup-before-fix-20251017-143052 d8d9535 feat: Developer C - 資料分析儀表板為什麼要備份:
- 如果恢復操作失敗,可以重新嘗試
- 作為審計記錄,證明執行了備份
- 提供心理安全感,降低操作壓力
3.2 最後確認檢查
使用時機: 備份完成後,執行 force push 之前
# 確認 1: 再次檢查當前分支
git branch必須確認: 當前分支(有 * 標記)是事故分支
# 確認 2: 檢查提交歷史
git log --oneline -5必須確認:
- 最新的 commit 包含所有應該保留的工作
- 沒有看到錯誤的 commit
# 確認 3: 查看當前 HEAD 指向
git rev-parse HEAD必須確認: 這個 hash 與之前記錄的一致
3.3 執行恢復 Force Push
git push --force origin <分支名稱>使用時機: 完成所有確認後,準備恢復遠端分支
指令說明:
git push: 推送到遠端-force: 強制推送,覆蓋遠端的錯誤狀態origin: 遠端儲存庫名稱<分支名稱>: 要恢復的分支(例如scenario3-test、main)
實際範例:
# 恢復 scenario3-test 分支
git push --force origin scenario3-test
# 恢復 main 分支
git push --force origin main預期輸出:
Enumerating objects: 86, done.
Counting objects: 100% (86/86), done.
Delta compression using up to 8 threads
Compressing objects: 100% (26/26), done.
Writing objects: 100% (69/69), 6.99 KiB | 6.99 MiB/s, done.
Total 69 (delta 47), reused 65 (delta 43), pack-reused 0
To gitlab.com:james-berget/git_demo.git
+ 8afeb60...d8d9535 scenario3-test -> scenario3-test (forced update)關鍵資訊解析:
+符號: 表示這是強制更新8afeb60...d8d9535: 從錯誤的 commit 恢復到正確的 commit(forced update): 確認這是強制更新
⚠️ 為什麼使用 –force 而不是 –force-with-lease:
-force-with-lease的問題:
# ❌ 這個命令可能會失敗
git push --force-with-lease origin scenario3-test
# 錯誤: ! [rejected] scenario3-test -> scenario3-test (stale info)原因:
-force-with-lease會檢查遠端分支是否與本地的遠端追蹤分支一致- 在情境三中,遠端已經被覆蓋,與團隊成員本地的追蹤分支不一致
- 使用
-force-with-lease會被拒絕,無法完成恢復 -force的正當性:- 我們確定遠端分支已經損壞
- 我們確認本地分支有完整的正確歷史
- 這是緊急恢復操作,必須覆蓋遠端的錯誤狀態
- 已經建立了備份分支,有安全保障
步驟 4:驗證恢復結果
4.1 事故處理者驗證遠端
使用時機: 團隊成員完成 force push 後立即執行
git fetch origin使用時機: 更新本地的遠端追蹤分支資訊
指令說明:
git fetch origin: 從遠端下載最新的分支資訊- 不會改變你的工作目錄或當前分支
- 只是更新本地的遠端追蹤分支(
origin/main、origin/scenario3-test等)
預期輸出:
From gitlab.com:james-berget/git_demo
+ 8afeb60...d8d9535 scenario3-test -> origin/scenario3-test (forced update)關鍵資訊:
+符號: 遠端分支被強制更新8afeb60...d8d9535: 從錯誤狀態恢復到正確狀態- 這個輸出確認遠端已經被成功恢復
git log origin/<分支名稱> --oneline -10
使用時機: 確認遠端分支現在有正確的提交歷史
指令說明:
git log origin/<分支名稱>: 顯示遠端分支的提交歷史-oneline: 簡潔格式,每個提交一行10: 顯示最近 10 個提交
範例:
git log origin/scenario3-test --oneline -10預期輸出:
d8d9535 (origin/scenario3-test) feat: Developer C - 資料分析儀表板
7848581 feat: Developer B - 訂單處理系統
8cf0e5d feat: Developer A - 使用者認證系統
34d3940 test: add synthetic record #15
...驗證要點:
- 所有遺失的提交都已經回來
- 提交順序正確
- 沒有看到錯誤的 commit
git rev-parse origin/<分支名稱>使用時機: 精確驗證遠端分支指向的 commit hash
指令說明:
git rev-parse: 將引用轉換為完整的 commit hashorigin/<分支名稱>: 遠端追蹤分支
範例:
git rev-parse origin/scenario3-test預期輸出:
d8d9535e7503b8aeb9976e6e368188ba32305c6e驗證方式:
- 將這個 hash 與團隊成員回報的 hash 比對
- 應該完全一致(或至少前 7 個字元一致)
4.2 同步本地分支
使用時機: 確認遠端已經正確恢復後
git reset --hard origin/<分支名稱>使用時機: 將本地分支重置為遠端的狀態
指令說明:
git reset --hard: 重置當前分支並清除工作目錄的所有變更origin/<分支名稱>: 重置到遠端追蹤分支的狀態
⚠️ 警告:
-hard會永久刪除所有未提交的變更- 執行前確保沒有重要的本地修改
- 如果有未提交的工作,先執行
git stash save "備份"
範例:
git reset --hard origin/scenario3-test預期輸出:
HEAD is now at d8d9535 feat: Developer C - 資料分析儀表板git log --oneline -5使用時機: 驗證本地分支已經同步
預期輸出:
d8d9535 (HEAD -> scenario3-test, origin/scenario3-test) feat: Developer C - 資料分析儀表板
7848581 feat: Developer B - 訂單處理系統
8cf0e5d feat: Developer A - 使用者認證系統
34d3940 test: add synthetic record #15
212b5e8 test: add synthetic record #14驗證要點:
HEAD -> scenario3-test和origin/scenario3-test指向同一個 commit- 所有應該存在的提交都在歷史中
4.3 驗證檔案已恢復
ls -la使用時機: 快速確認關鍵檔案是否存在
範例:
# 列出特定檔案
ls -la scenario3_*.txt預期輸出:
scenario3_developer_A_feature.txt
scenario3_developer_B_feature.txt
scenario3_developer_C_feature.txt驗證要點:
- 所有應該存在的檔案都已恢復
- 錯誤的檔案已經消失(如果有的話)
步驟 5:通知團隊並協助同步
5.1 發送恢復完成通知
使用時機: 驗證完成後立即發送
在團隊頻道發送以下訊息:
恢復完成 - Force Push 事故已解決
分支 [分支名稱] 已成功恢復
恢復資訊:
- 事故發生時間: [時間]
- 恢復完成時間: [時間]
- 總耗時: [例如: 10 分鐘]
- 恢復的提交數: [例如: 3 個]
- 協助成員: [感謝提供完整歷史的成員名字]
恢復的提交:
- d8d9535: Developer C - 資料分析儀表板
- 7848581: Developer B - 訂單處理系統
- 8cf0e5d: Developer A - 使用者認證系統
所有人請立即同步:
步驟 1: 保存當前工作(如果有未提交的變更)
git stash save "備份-恢復前"
步驟 2: 更新遠端資訊
git fetch origin
步驟 3: 重置本地分支
git reset --hard origin/[分支名稱]
步驟 4: 驗證歷史完整性
git log --oneline -10
步驟 5: 恢復之前保存的工作(如果有)
git stash pop
⚠️ 如有任何問題或錯誤,請立即回報
⚠️ 請確認你的提交都在歷史中5.2 團隊成員同步指令詳解
給所有團隊成員的詳細指示:
# 步驟 1: 保存當前工作(如果有未提交的變更)
git stash save "備份-恢復前"使用時機: 如果你有未提交的變更需要保留
指令說明:
git stash save: 暫存當前的變更"備份-恢復前": 暫存的描述訊息
⚠️ 注意: 如果沒有未提交的變更,這個命令會顯示 “No local changes to save”,這是正常的。
# 步驟 2: 更新遠端資訊
git fetch origin使用時機: 所有人都必須執行
指令說明: 從遠端下載最新的分支資訊
預期輸出:
From gitlab.com:james-berget/git_demo
+ 8afeb60...d8d9535 scenario3-test -> origin/scenario3-test (forced update)# 步驟 3: 檢視差異(可選但建議)
git log HEAD..origin/<分支名稱> --oneline使用時機: 想要確認遠端有哪些提交是本地沒有的
指令說明:
HEAD..origin/<分支名稱>: 顯示遠端領先本地的提交- 這些就是恢復回來的提交
# 步驟 4: 重置本地分支
git reset --hard origin/<分支名稱>使用時機: 確認要同步到遠端的狀態
⚠️ 警告: 這會刪除所有未提交的變更!確保已經執行了 git stash。
# 步驟 5: 驗證歷史完整性
git log --oneline -10使用時機: 重置後立即驗證
驗證要點:
- 看到所有恢復的提交
- 確認你自己的提交(如果有)也在歷史中
# 步驟 6: 恢復之前保存的工作(如果有)
git stash pop使用時機: 如果步驟 1 執行了 git stash save
指令說明:
git stash pop: 恢復最近一次 stash 的變更- 如果有衝突,需要手動解決
情境三完整操作檢查清單
事故處理者清單:
- [ ] 確認本地和遠端都無法找回完整歷史
- [ ] 發送緊急求助訊息到團隊頻道
- [ ] 明確指示團隊成員不要執行
git pull - [ ] 收集團隊成員的回報
- [ ] 驗證回報成員的歷史完整性
- [ ] 選擇有完整歷史的成員執行恢復
執行恢復的團隊成員清單:
- [ ] 執行
git log --oneline -10確認有完整歷史 - [ ] 執行
git rev-parse HEAD記錄 commit hash - [ ] 執行
git branch確認在正確分支 - [ ] 執行
git branch backup-before-fix-$(date +%Y%m%d-%H%M%S)建立備份 - [ ] 再次確認當前分支正確
- [ ] 執行
git push --force origin <branch>恢復遠端
所有團隊成員清單:
- [ ] 執行
git stash save "備份-恢復前"保存本地變更 - [ ] 執行
git fetch origin更新遠端資訊 - [ ] 執行
git reset --hard origin/<branch>同步本地 - [ ] 執行
git log --oneline -10驗證歷史 - [ ] 執行
git stash pop恢復本地變更(如果有) - [ ] 確認自己的提交都在歷史中
- [ ] 向事故處理者確認同步成功
如果所有項目都勾選,恭喜你!成功從最困難的情境三中恢復了!!
如果連你的 reflog 都遺失了,不要絕望。只要有任何一位團隊成員在事故發生前拉取過最新的程式碼,他的電腦裡就有一份完整的歷史備份。
請他執行 git log 找到正確的 commit hash,然後你可以從他的電腦 git fetch,或者讓他建立恢復分支並推送到遠端。
記住,只要 commit 存在過,它幾乎永遠不會真正從 Git 中消失,只等你將它找回。

