Git 進階技巧全攻略:Interactive Rebase、Bisect、Worktree 與鉤子自動化
前端工程(更新於 2026年5月18日)
你只用了 Git 20% 的能力
大多數開發者日常只用 add、commit、push、pull、merge。Git 的真正威力在於:精確控制歷史、快速定位 Bug、並行多任務、自動化工作流程。
一、Interactive Rebase:重塑提交歷史
基本操作
git rebase -i HEAD~5
開啟編輯器顯示最近 5 個提交:
pick a1b2c3f feat: 新增使用者列表頁面
pick d4e5f6g fix: 修復列表排序問題
pick h7i8j9k feat: 新增搜尋功能
pick l0m1n2o chore: 更新依賴
pick p3q4r5s feat: 新增分頁元件
六種操作
| 命令 | 作用 | 使用場景 |
|---|---|---|
pick |
保留提交 | 預設 |
squash |
合併到上一個提交 | 多個小修復合為一個 |
fixup |
合併並捨棄訊息 | 同上,不保留訊息 |
reword |
修改提交訊息 | 訊息有錯字 |
edit |
暫停並修改提交 | 拆分或修改內容 |
drop |
捨棄提交 | 移除錯誤提交 |
實戰:整理功能分支
# 原始提交
pick abc1234 feat: 使用者模組 WIP
pick def5678 fix: 修復空指標
pick ghi9012 fix: 修復型別錯誤
pick jkl3456 feat: 新增搜尋
pick mno7890 chore: 格式化程式碼
# 整理後
pick abc1234 feat: 新增使用者模組
fixup def5678 # 合併到 abc1234
fixup ghi9012 # 合併到 abc1234
pick jkl3456 feat: 新增搜尋功能
drop mno7890 # 捨棄格式化提交
自動 fixup
# 建立 fixup 提交(標記目標提交)
git commit --fixup=abc1234
# 自動變基,fixup 提交會找到目標並合併
git rebase -i --autosquash
二、Git Bisect:二分查找 Bug 引入點
當 Bug 出現但不知道哪個提交引入時,bisect 用二分查找快速定位。
手動 Bisect
# 開始二分查找
git bisect start
# 標記目前版本有 Bug
git bisect bad
# 標記已知的好版本
git bisect good v2.0.0
# Git 自動 checkout 中間版本
# 測試後標記
git bisect good # 或 git bisect bad
# 重複直到找到引入 Bug 的提交
# Git 輸出:abc1234 is the first bad commit
# 結束查找
git bisect reset
自動化 Bisect
# 用腳本自動測試每個版本
git bisect start HEAD v2.0.0
git bisect run npm test
# 或自訂腳本
git bisect run ./scripts/test-bug.sh
#!/bin/bash
# scripts/test-bug.sh
npm run build
if curl -s http://localhost:3000/api/health | grep -q "ok"; then
exit 0 # good
else
exit 1 # bad
fi
效率:1000 個提交只需 10 次二分(log₂(1000) ≈ 10)。
三、Git Worktree:同時工作在多個分支
問題
正在 feature/A 上開發,突然需要緊急修復 hotfix/B——不想 stash,不想新建 clone。
解決
# 為 hotfix 建立工作樹
git worktree add ../hotfix-B hotfix/B
# 在 ../hotfix-B 目錄工作,不影響目前分支
cd ../hotfix-B
# 修復、提交、推送
git add . && git commit -m "fix: 緊急修復"
git push
# 回到原工作
cd ../main-project
# 繼續開發 feature/A,完全不受影響
# 清理工作樹
git worktree remove ../hotfix-B
管理工作樹
# 列出所有工作樹
git worktree list
# 鎖定工作樹(防止意外刪除)
git worktree lock ../hotfix-B
# 解鎖
git worktree unlock ../hotfix-B
| 對比 | git stash | git worktree | git clone |
|---|---|---|---|
| 磁碟佔用 | 0 | 僅差異檔案 | 全量 |
| 切換成本 | stash + checkout | cd 切目錄 | cd 切目錄 |
| 並行工作 | 不支援 | 支援 | 支援 |
| 共享 .git | 是 | 是 | 否 |
四、Git Hooks:自動化工作流程
客戶端鉤子
| 鉤子 | 觸發時機 | 用途 |
|---|---|---|
pre-commit |
git commit 前 |
程式碼檢查、格式化 |
prepare-commit-msg |
編輯提交訊息前 | 自動新增前綴 |
commit-msg |
提交訊息寫完後 | 校驗訊息格式 |
pre-push |
git push 前 |
執行測試 |
post-checkout |
切換分支後 | 安裝依賴 |
服務端鉤子
| 鉤子 | 觸發時機 | 用途 |
|---|---|---|
pre-receive |
接收推送前 | 權限校驗 |
update |
每個引用更新前 | 分支保護 |
post-receive |
接收推送後 | 觸發 CI/CD |
使用 Husky + lint-staged
npm install husky lint-staged --save-dev
npx husky init
// .husky/pre-commit
npx lint-staged
// package.json
{
"lint-staged": {
"*.{js,ts,tsx}": [
"eslint --fix",
"prettier --write"
],
"*.css": [
"stylelint --fix"
]
}
}
commitlint 校驗提交訊息
npm install @commitlint/cli @commitlint/config-conventional --save-dev
// commitlint.config.js
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [2, 'always', [
'feat', 'fix', 'docs', 'style', 'refactor',
'perf', 'test', 'build', 'ci', 'chore', 'revert',
]],
'subject-max-length': [2, 'always', 100],
},
};
# .husky/commit-msg
npx --no -- commitlint --edit $1
五、Git Stash 進階用法
多個 Stash
# 帶訊息的 stash
git stash push -m "WIP: 使用者列表搜尋功能"
# 列出所有 stash
git stash list
# stash@{0}: On feature/search: WIP: 使用者列表搜尋功能
# stash@{1}: On feature/order: WIP: 訂單詳情頁
# 應用特定 stash
git stash apply stash@{1}
# 部分暫存
git stash push -m "只暫存 CSS" -- '**/*.css'
從 Stash 建立分支
git stash branch feature/search stash@{0}
# 建立新分支並應用 stash,適合 WIP 變成正式分支
六、Git Log 進階查詢
搜尋提交內容
# 搜尋包含特定字串的提交
git log -S "function calculateTotal"
# 搜尋匹配正則的提交
git log -G "calculate.*Total"
# 搜尋特定檔案的歷史
git log --follow -- src/utils/calc.ts
# 檢視每次提交的檔案變更統計
git log --stat
# 檢視每次提交的具體差異
git log -p -- src/utils/calc.ts
格式化輸出
# 自訂格式
git log --format="%h %ad | %s%d [%an]" --date=short
# 輸出:
# a1b2c3f 2026-05-30 | feat: 新增搜尋功能 (HEAD -> main) [張三]
# d4e5f6g 2026-05-29 | fix: 修復排序問題 [李四]
檢視分支合併圖
git log --graph --oneline --all --decorate
七、Git Reflog:時光機
reflog 記錄 HEAD 的每一次移動,即使提交被「刪除」也能找回。
# 檢視操作歷史
git reflog
# a1b2c3f HEAD@{0}: commit: feat: 新功能
# d4e5f6g HEAD@{1}: rebase: 繼續變基
# h7i8j9k HEAD@{2}: reset: moving to HEAD~1
# l0m1n2o HEAD@{3}: commit: 被誤刪的提交
# 恢復誤刪的提交
git cherry-pick l0m1n2o
# 或直接回到某個狀態
git reset --hard HEAD@{3}
保留期:預設 90 天(gc.reflogExpire),未引用的提交 30 天。
八、實用別名設定
git config --global alias.lg "log --graph --oneline --all --decorate"
git config --global alias.last "log -1 HEAD --stat"
git config --global alias.unstage "reset HEAD --"
git config --global alias.amend "commit --amend --no-edit"
git config --global alias.wip "commit -m 'WIP'"
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.st status
使用:git lg、git last、git unstage file.ts 等。
#Git#版本控制#开发效率