今日目標
• 處理常見 Git 錯誤
• 救回誤刪的資料
• 解決複雜的合併問題
• 掌握進階恢復技巧
一、檔案救援
情境 1:誤刪檔案(還沒 commit)
rm important.txt
git restore important.txt
git restore --source=HEAD important.txt
git restore src/
git restore .
情境 2:誤刪 Commit
git reset --hard HEAD~3 # 刪除了最近 3 個 commits
git reflog
git reset --hard def456
git reset --hard HEAD@{1}
git log --oneline
情境 3:刪除了分支
git branch -D feature-important
git reflog | grep feature-important
git branch feature-important abc123
git fsck --lost-found
git show abc123 # 確認是不是要找的
git branch feature-important abc123
情境 4:檔案改壞了想回到之前版本
git log -- path/to/file.js
git restore --source=abc123 -- path/to/file.js
git checkout abc123 -- path/to/file.js
二、Commit 問題
情境 1:Commit 訊息寫錯
git commit --amend -m "正確的訊息"
git rebase -i HEAD~3
情境 2:Commit 到錯誤的分支
git branch feature-xyz # 建立新分支(指向當前 commit)
git reset --hard HEAD~1 # main 回退
git checkout feature-xyz # 切到新分支
git checkout feature-xyz
git cherry-pick main # 複製 main 的最後 commit
git checkout main
git reset --hard HEAD~1 # main 回退
情境 3:想拆分一個 commit
git rebase -i HEAD~3
git reset HEAD^
git add file1.js
git commit -m "功能 A"
git add file2.js
git commit -m "功能 B"
git rebase --continue
情境 4:想合併多個 commits
git rebase -i HEAD~5
pick abc123 feat: 功能 1
fixup def456 fix: 修正錯字 # 改成 fixup
fixup ghi789 fix: 又修正 # 改成 fixup
pick jkl012 feat: 功能 2
pick abc123 feat: 功能 1
squash def456 fix: 修正錯字
三、合併衝突進階處理
複雜衝突的處理策略
git status
git diff
git mergetool
git checkout --ours path/to/file.js
git checkout --theirs path/to/file.js
vim path/to/file.js
git add path/to/file.js
git commit
Rebase 衝突處理
git rebase main
vim file.js
git add file.js
git rebase --continue
git rebase --abort
git merge main
避免重複解決相同衝突
git config --global rerere.enabled true
四、遠端倉庫問題
情境 1:Push 被拒絕
git pull origin main
git push origin main
git pull --rebase origin main
git push origin main
git push --force-with-lease origin main
情境 2:Clone 或 Pull 超級慢
git clone --depth 1 https://github.com/user/repo.git
git clone --single-branch --branch main https://github.com/user/repo.git
git config --global http.proxy http://proxy:port
情境 3:遠端分支已刪除但本地還在
git branch -r
git fetch --prune
git fetch -p
git branch -d feature-old
情境 4:改了遠端 URL
git remote -v
git remote set-url origin https://github.com/new-url/repo.git
git remote remove origin
git remote add origin https://github.com/new-url/repo.git
git remote -v
五、工作區狀態問題
情境 1:改了很多檔案想全部丟棄
git restore .
git checkout -- .
git restore --staged .
git restore .
git reset --hard HEAD
git clean -fd
git clean -n
情境 2:Stash 相關問題
git stash push -u -m "描述"
git stash list
git stash show stash@{0}
git stash show -p stash@{0} # 顯示 diff
git stash apply stash@{2}
git stash pop stash@{0}
git stash drop stash@{0}
git stash clear
git stash branch new-branch stash@{0}
情境 3:Detached HEAD 狀態
git branch temp-branch
git checkout main
git merge temp-branch
git checkout main
git cherry-pick abc123
git checkout main
六、效能和空間問題
情境 1:倉庫太大
du -sh .git
git rev-list --objects --all |
git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' |
awk '/^blob/ {print substr($0,6)}' |
sort --numeric-sort --key=2 |
tail -10
java -jar bfg.jar --strip-blobs-bigger-than 50M
git reflog expire --expire=now --all
git gc --prune=now --aggressive
pip install git-filter-repo
git filter-repo --strip-blobs-bigger-than 50M
情境 2:加速 Git 操作
git config core.fsmonitor true
git config core.untrackedCache true
git gc --aggressive
git prune
git fetch --depth=1
git clone --filter=blob:none https://github.com/user/repo.git
七、權限和認證問題
情境 1:SSH 連線失敗
ssh -T git@github.com
ssh -vT git@github.com
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub
情境 2:HTTPS 認證問題
git credential-cache exit
git config --global --unset credential.helper
git config --global credential.helper cache
git config --global credential.helper osxkeychain
八、進階恢復技巧
使用 Git Reflog 救援
git reflog
git reset --hard HEAD@{2}
git reflog show feature-branch
git config gc.reflogExpire "180 days"
找回已刪除的內容
git log -S "要找的內容" --all
git log --grep="關鍵字" --all
git log --all --full-history -- path/to/deleted/file
git checkout ^ -- path/to/deleted/file
git fsck --lost-found
完全搞砸了怎麼辦
cp -r .git .git.backup
cd ..
git clone repo-clean
cd repo-clean
git --git-dir=../repo/.git.backup reflog
git cherry-pick abc123
rm -rf ../repo/.git.backup
九、常見錯誤訊息解析
十、預防勝於治療
git push origin main
git push origin develop
git config --global alias.pushf 'push --force-with-lease'
git gc --auto
git prune
git branch backup-$(date +%Y%m%d)
快速參考:救援指令速查表
git restore # 恢復檔案
git restore --source= # 從特定版本恢復
git reflog # 查看所有操作
git reset --hard HEAD@{n} # 回到某個時間點
git cherry-pick # 複製 commit
git fsck --lost-found # 找懸空的 commits
git branch # 重建分支
git checkout --ours # 使用我們的版本
git checkout --theirs # 使用他們的版本
git mergetool # 使用合併工具
git clean -fd # 刪除未追蹤檔案
git reset --hard HEAD # 丟棄所有變更
git fetch --prune # 清理已刪除的遠端分支
git remote set-url origin # 更改 remote URL
今日重點回顧
✅ 核心技能:
檔案救援
Commit 處理
衝突解決
遠端問題
進階恢復
記住:
立即行動
□ 查看你的 reflog
□ 練習 restore 和 reset
□ 建立一個測試 repo 練習救援
□ 設定 rerere
□ 建立備份 alias
□ 練習 interactive rebase
□ 測試各種救援情境
mkdir git-rescue-practice
cd git-rescue-practice
git init
echo "v1" > file.txt
git add file.txt
git commit -m "v1"
echo "v2" > file.txt
git commit -am "v2"
echo "v3" > file.txt
git commit -am "v3"
git reset --hard HEAD~2
git reflog
git reset --hard
常見問題 FAQ
Q1: 什麼情況下資料真的救不回來?
救不回的情況:
❌ 從未 commit 過的檔案被刪除
❌ reflog 已過期(預設 90 天)
❌ git gc 清除了懸空物件
❌ 檔案系統損壞
救得回的情況:
✅ 任何曾經 commit 的內容
✅ reflog 期限內的操作
✅ 「刪除」的分支
✅ reset/rebase 後的 commits
Q2: git reset 的三種模式有什麼差別?
git reset --soft HEAD~1
git reset HEAD~1
git reset --hard HEAD~1
Q3: 什麼時候該用 rebase,什麼時候用 merge?
用 Rebase:
✅ 自己的 feature 分支
✅ 想要線性歷史
✅ 整理 commits
用 Merge:
✅ 公開的分支(main, develop)
✅ 保留完整歷史
✅ 團隊協作
黃金法則:
永遠不要 rebase 已推送的公開分支!
Q4: force push 什麼時候可以用?
可以用的情況:
✅ 自己的 feature 分支
✅ 整理完歷史後
✅ 確定沒有其他人在用這個分支
絕對不要:
❌ 公開的分支(main, develop)
❌ 團隊共用的分支
❌ 不確定的時候
更安全的做法:
git push --force-with-lease
實用工具
git config --global alias.undo 'reset --soft HEAD~1'
git config --global alias.unstage 'restore --staged'
git config --global alias.last 'log -1 HEAD'
git config --global alias.visual 'log --graph --oneline --all'
git config --global alias.cleanup 'clean -fd'
git undo # 撤銷最後一次 commit
git unstage . # 取消 staging
git last # 查看最後一次 commit
git visual # 視覺化歷史