iT邦幫忙

2025 iThome 鐵人賽

DAY 9
0
自我挑戰組

30天 Git 版本控制實戰筆記系列 第 19

Day 19:錯誤修復與資料救援 - 成為 Git 救火隊長

  • 分享至 

  • xImage
  •  

今日目標
• 學習處理常見的 Git 錯誤
• 掌握資料救援技巧
• 能夠撤銷錯誤的操作
• 成為團隊的 Git 問題解決專家
為什麼需要學習救援?
職場真實情況:
😱 常見的災難:
同事A:「我不小心刪除了重要檔案!」
同事B:「我 commit 錯分支了!」
同事C:「我把 main 分支搞亂了!」
實習生:「我把專案砍掉了...」

如果不會救援 → 😰 資料遺失,專案停擺
會救援技巧 → 😎 5 分鐘內恢復,英雄救美
Git 的安全機制:
好消息:Git 幾乎不會真正刪除資料!

即使你:

  • 刪除了分支
  • reset 到舊版本
  • 清空了檔案
  • 誤操作 rebase

在一定時間內(通常 30 天)都可以救回來!


操作步驟
步驟1:理解 Git 的安全網 - Reflog
什麼是 Reflog?
Reflog = Git 的「黑盒子」
記錄所有 HEAD 的移動歷史

就像:

  • 瀏覽器歷史記錄
  • 系統還原點
  • 時光機
    查看 Reflog:

查看所有操作記錄

git reflog

輸出範例:

a1b2c3d (HEAD -> main) HEAD@{0}: commit: feat: 新增功能

e4f5g6h HEAD@{1}: reset: moving to HEAD~1

i7j8k9l HEAD@{2}: commit: fix: 修復 bug

m1n2o3p HEAD@{3}: checkout: moving from feature to main

查看最近 20 條記錄

git reflog -20

查看特定分支的 reflog

git reflog show main
步驟2:救援誤刪的 Commit
情境1:不小心 reset --hard 了

模擬誤操作

echo "重要內容" > important.txt
git add important.txt
git commit -m "feat: 重要功能"

不小心 reset 了

git reset --hard HEAD~1

😱 commit 不見了!

救援方法

1. 查看 reflog

git reflog

2. 找到被 reset 前的 commit

假設是 a1b2c3d

3. 恢復到那個 commit

git reset --hard a1b2c3d

✅ 救回來了!

情境2:刪除了分支

建立並切換分支

git checkout -b feature/important
echo "開發中..." > work.txt
git add work.txt
git commit -m "feat: 開發中的功能"

切回 main

git checkout main

不小心刪除分支

git branch -D feature/important

😱 分支被刪了!

救援方法

1. 查看 reflog

git reflog

2. 找到分支的最後一個 commit

假設是 b2c3d4e

3. 重新建立分支指向那個 commit

git branch feature/important b2c3d4e

✅ 分支救回來了!

或直接切換到那個 commit

git checkout -b feature/important b2c3d4e
步驟3:撤銷錯誤的 Commit
方法1:使用 reset(改寫歷史)

撤銷最後一個 commit,保留變更

git reset --soft HEAD~1

檔案回到暫存區

撤銷最後一個 commit,變更回到工作目錄

git reset --mixed HEAD~1

或簡寫:git reset HEAD~1

撤銷最後一個 commit,完全刪除變更

git reset --hard HEAD~1

⚠️ 危險!變更會遺失

撤銷多個 commit

git reset --soft HEAD~3
方法2:使用 revert(保留歷史)

建立一個新 commit 來撤銷之前的 commit

git revert HEAD

撤銷特定 commit

git revert a1b2c3d

撤銷多個 commit

git revert HEAD~3..HEAD

撤銷但不立即 commit

git revert -n HEAD
reset vs revert 比較:
git reset:

  • 改寫歷史
  • 適合本地未 push 的 commit
  • 不留痕跡

git revert:

  • 保留歷史
  • 適合已 push 的 commit
  • 新增一個反向 commit
    步驟4:修改最後一次 Commit
    修改 commit 訊息:

修改最後一次 commit 的訊息

git commit --amend -m "fix: 修正後的訊息"

在編輯器中修改

git commit --amend
加入遺漏的檔案:

發現漏了一個檔案

echo "補充內容" > forgot.txt
git add forgot.txt

加入到最後一次 commit

git commit --amend --no-edit

--no-edit 表示不修改 commit 訊息

修改作者資訊:

修改最後一次 commit 的作者

git commit --amend --author="正確名字 email@example.com"
步驟5:救援誤刪的檔案
情境1:檔案還沒 commit

刪除了檔案

rm important.txt

從暫存區恢復

git restore important.txt

或舊語法:git checkout -- important.txt

如果已經 git add 了

git restore --staged important.txt
git restore important.txt
情境2:檔案已經 commit

查找檔案最後存在的 commit

git log --all --full-history -- important.txt

從特定 commit 恢復檔案

git restore --source=a1b2c3d important.txt

或使用 checkout

git checkout a1b2c3d -- important.txt
情境3:找不到檔案在哪個 commit

搜尋包含特定內容的 commit

git log -S "重要內容" --all

查看該 commit 的檔案

git show a1b2c3d:important.txt
步驟6:處理合併衝突後悔
放棄合併:

正在合併中遇到衝突

git merge feature/branch

衝突產生...

放棄這次合併

git merge --abort

回到合併前的狀態

放棄 rebase:

正在 rebase 遇到問題

git rebase main

產生問題...

放棄 rebase

git rebase --abort

回到 rebase 前的狀態

步驟7:救援被覆蓋的 Stash

查看所有 stash(包括被刪除的)

git fsck --unreachable | grep commit | cut -d ' ' -f3 | xargs git log --merges --no-walk --grep=WIP

查看特定 commit 的內容

git show

如果確認是需要的,建立分支

git branch recovered-stash


常見災難救援指南
災難1:不小心 git push -f

😱 強制推送覆蓋了遠端

git push -f origin main

救援步驟:

1. 找到被覆蓋前的 commit

git reflog

找到推送前的 commit,例如 a1b2c3d

2. 恢復本地

git reset --hard a1b2c3d

3. 再次強制推送(如果有權限)

git push -f origin main

4. 如果其他人已經 pull 了錯誤版本

通知團隊:大家都要 reset 到正確版本

災難2:錯誤的 rebase

😱 rebase 後發現搞砸了

git rebase main

救援步驟:

1. 查看 rebase 前的狀態

git reflog

2. 找到 rebase 前的位置

例如:HEAD@{5}: rebase (start)

前一個就是 rebase 前的狀態

3. 恢復

git reset --hard HEAD@{5}

✅ 回到 rebase 前

災難3:誤刪整個 .git 資料夾

😱 不小心刪除了 .git

rm -rf .git

救援步驟:

如果有遠端備份

git clone https://github.com/你的帳號/專案.git temp
cp -r temp/.git .
rm -rf temp

如果沒有遠端

😭 資料遺失,無法救援

這就是為什麼要常 push 的原因!

災難4:合併了不該合併的東西

😱 合併後才發現問題

git merge feature/bad-branch

救援方法1:使用 revert

git revert -m 1 HEAD

-m 1 表示保留第一個父節點(main)

救援方法2:使用 reset(如果還沒 push)

git reset --hard HEAD~1


預防勝於治療
✅ 最佳安全實踐:

1. 常常 commit

小步快跑,隨時可以回退

2. 定期 push

遠端備份最安全

git push origin main

3. 使用分支

在分支上實驗,不怕弄壞

git checkout -b experiment

4. 危險操作前先備份

git branch backup-$(date +%Y%m%d)

5. 使用 --dry-run 預覽

git clean -fd --dry-run

6. 重要操作前檢查

git status
git log --oneline -5
建立安全習慣:

建立每日備份腳本

cat > daily-backup.sh << 'EOF'
#!/bin/bash
DATE=$(date +%Y%m%d)
BRANCH=$(git branch --show-current)

建立備份分支

git branch backup-$BRANCH-$DATE

echo "✅ 已建立備份分支: backup-$BRANCH-$DATE"
EOF

chmod +x daily-backup.sh


救援工具箱
常用救援指令速查:

查看歷史

git reflog # 查看操作記錄
git log --all --full-history # 查看完整歷史

恢復 commit

git reset --hard # 恢復到指定 commit
git cherry-pick # 撿回特定 commit

恢復檔案

git restore # 恢復工作目錄
git restore --staged # 取消暫存
git restore --source= # 從舊版本恢復

恢復分支

git branch # 重建分支

撤銷操作

git reset --soft HEAD~1 # 撤銷 commit,保留變更
git reset --hard HEAD~1 # 撤銷 commit,刪除變更
git revert HEAD # 建立反向 commit

放棄操作

git merge --abort # 放棄合併
git rebase --abort # 放棄 rebase


實戰演練
練習1:模擬意外並救援

1. 建立測試環境

mkdir git-rescue-practice
cd git-rescue-practice
git init

2. 建立一些提交

echo "Version 1" > file.txt
git add file.txt
git commit -m "v1"

echo "Version 2" >> file.txt
git add file.txt
git commit -m "v2"

echo "Version 3" >> file.txt
git add file.txt
git commit -m "v3"

3. 模擬災難

git reset --hard HEAD~2

😱 v2 和 v3 不見了

4. 救援

git reflog

找到 v3 的 commit hash

git reset --hard

✅ 救回來了


今日重點回顧
• ✅ 理解 Git 的安全機制(Reflog)
• ✅ 學會救援誤刪的 commit 和分支
• ✅ 掌握撤銷錯誤操作的方法
• ✅ 能夠處理各種災難情況
核心指令總結
git reflog # 查看操作歷史
git reset --hard # 恢復到指定狀態
git restore # 恢復檔案
git branch # 恢復分支
git revert # 安全地撤銷
git commit --amend # 修改最後一次 commit
git merge --abort # 放棄合併
git rebase --abort # 放棄 rebase


上一篇
Day 18:Git 效能優化 - 讓 Git 飛快運行
系列文
30天 Git 版本控制實戰筆記19
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言