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#版本控制#开发效率