Git中文社区

进阶技巧

这一章收了几个平时用得不多、但遇到特定问题时很好用的命令:挑选提交、找回误删的提交、定位引入 Bug 的版本等。

git cherry-pick:挑选提交

想把另一个分支上的某个提交应用到当前分支,而不是合并整个分支?用 cherry-pick:

# 把指定提交应用到当前分支
git cherry-pick a1b2c3d

# 挑选多个提交
git cherry-pick a1b2c3d e4f5g6h

# 挑选一个范围(不含 A,包含 B)
git cherry-pick A..B

# 只应用修改,不自动提交
git cherry-pick -n a1b2c3d

典型场景:在开发分支上修复了一个 Bug,需要同步到发布分支。

遇到冲突时,解决后执行 git cherry-pick --continue,或用 --abort 放弃。

git reflog:后悔药

reflog 记录了 HEAD 和分支指针的每一次变动,包括 commit、reset、rebase、checkout 等。它是恢复"丢失"数据的最后一道防线:

git reflog
# e4f5g6h HEAD@{0}: rebase (finish): returning to refs/heads/feature
# a1b2c3d HEAD@{5}: commit: 添加登录接口

# 恢复误删的分支
git branch recovered-branch a1b2c3d

# 回到 rebase 之前的状态
git reset --hard HEAD@{5}

注意

reflog 只保存在本地,不会被推送;条目默认保留 90 天。

git bisect:二分查找 Bug

某个功能以前正常,现在坏了,但中间有上百个提交,不知道是哪一个引入的问题?git bisect 可以用二分法快速定位:

# 开始二分查找
git bisect start

# 标记当前版本是坏的
git bisect bad

# 标记一个已知正常的版本
git bisect good v1.0.0

# Git 会检出中间的一个提交,测试后告诉 Git 结果
git bisect good   # 或 git bisect bad

# 重复上面的步骤,直到 Git 找到第一个坏提交
# a1b2c3d is the first bad commit

# 结束,回到原来的分支
git bisect reset

如果有自动化测试脚本,还可以让 Git 全自动完成:

git bisect run npm test

100 个提交最多只需要测试 7 次左右。

git worktree:同时检出多个分支

需要在修复 Bug 的同时保留当前开发环境不动?worktree 允许一个仓库同时拥有多个工作区:

# 在 ../hotfix 目录检出 hotfix 分支
git worktree add ../hotfix hotfix

# 基于 main 新建分支并检出
git worktree add -b feature-x ../feature-x main

# 列出所有工作区
git worktree list

# 删除工作区
git worktree remove ../hotfix

相比再克隆一份仓库,worktree 共享同一个 .git 数据库,节省空间且提交互通。

git grep:在仓库中搜索

# 在已跟踪的文件中搜索
git grep "TODO"

# 显示行号
git grep -n "getUserInfo"

# 在某个历史版本中搜索
git grep "apiKey" v1.0.0

修改历史中的作者信息

如果之前的提交用错了邮箱:

# 修改最后一次提交的作者
git commit --amend --author="张三 <[email protected]>" --no-edit

# 修改最近多个提交:交互式变基,把需要修改的标记为 edit
git rebase -i HEAD~5
# 每停一次执行:
git commit --amend --reset-author --no-edit
git rebase --continue

从历史中彻底删除文件

误提交了大文件或敏感信息,需要从所有历史中清除。官方推荐使用 git filter-repo:

# 安装
pip install git-filter-repo

# 从所有历史中删除某个文件
git filter-repo --path secrets.json --invert-paths

# 删除大于 10MB 的文件
git filter-repo --strip-blobs-bigger-than 10M

警告

这会改写整个仓库的历史,所有提交哈希都会改变。执行后需要强制推送,并通知所有协作者重新克隆。泄露的密钥仍需立即更换。

Git LFS:管理大文件

Git 不擅长管理大型二进制文件(设计稿、视频、模型等)。Git LFS 会把大文件存储在单独的服务器上,仓库中只保存指针:

git lfs install
git lfs track "*.psd"
git add .gitattributes
git add design.psd
git commit -m "添加设计稿"

Git Hooks:钩子

Git 可以在特定事件发生时自动执行脚本,脚本位于 .git/hooks/ 目录:

钩子触发时机常见用途
pre-commit提交前运行代码检查、格式化
commit-msg编写提交说明后校验提交说明格式
pre-push推送前运行测试
post-merge合并后自动安装依赖

.git/hooks 不会被提交到仓库。前端项目中常用 husky 等工具在团队内共享钩子配置。

签名提交

为了证明提交确实来自你本人,可以对提交进行签名。新版 Git 支持直接使用 SSH 密钥签名:

git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub
git config --global commit.gpgsign true

把同一个公钥作为 Signing Key 添加到 GitHub 后,提交旁会显示 "Verified" 标记。