恭喜你!已经掌握了 Git 的基础操作,现在是时候解锁「高级技能」了~ 本章的工具就像游戏里的「终极装备」,能帮你解决复杂场景下的问题:比如精准定位 bug、优雅修改提交历史、高效管理子项目等。
这些工具可能不是日常必备,但关键时刻能帮你少走 N 多弯路!我们会用最通俗的例子 + 实操代码,让初学者也能轻松拿捏,从此告别「Git 操作慌」~
引用日志
祖先引用
提交范围
1. 短 SHA-1 – 不用记完整哈希值 ✍️
Git 的提交哈希值(SHA-1)是 40 位的长字符串,记不住也不用慌!Git 支持用前 4 位以上的唯一前缀代替完整哈希。
git log –abbrev-commit –pretty=oneline
# 输出示例:ca82a6d 修改版本号
# 085bb3b 删除无用测试代码# 用短哈希查看提交详情(只要前缀唯一即可)
git show ca82a6d # 等同于 git show 完整 40 位哈希
2. 引用日志(reflog)- 时光机回溯 🕰️
不小心删了分支、重置错了提交?别慌!reflog 会记录你本地仓库的所有操作(HEAD 和分支的变动),帮你找回丢失的提交。
git reflog
# 输出示例:734713b HEAD@{0}: commit: 修复 refs 处理
# d921970 HEAD@{1}: merge: 合并 phedders/rdocs
# 1c002dd HEAD@{2}: commit: 添加 blame 和 merge 功能# 查看 3 天前 master 分支的状态
git show master@{3.days.ago}
# 恢复到某个历史状态(比如找回误删的提交)
git checkout HEAD@{2} # 切换到第 3 条记录的状态
3. 祖先引用 – 快速定位父提交 👨👩👧👦
想查看某个提交的父提交、祖父提交?用 ^ 和~ 符号就能快速定位,不用翻日志!
git show HEAD^
git show HEAD~1# HEAD~2:当前提交的祖父提交(第一个父提交的第一个父提交)
git show HEAD~2
# 合并提交有多个父提交,用 ^2 查看第二个父提交
git show d921970^2 # 查看 d921970 提交的第二个父提交
类比理解 :HEAD^ 就像“爸爸”,HEAD~2 就像“爷爷”,合并提交的 ^2 就像“继父”~ 轻松记住!
4. 提交范围 – 筛选特定提交集合 📦
想知道两个分支的差异、某个时间段的提交?用提交范围语法就能精准筛选!
git log master..experiment # 查看 experiment 分支独有的提交# 三点(A…B):A 和 B 分支互不包含的提交(两边都有的不显示)
git log master…experiment –left-right # –left-right 显示属于哪个分支
# 多个条件组合:显示 refA 或 refB 有但 refC 没有的提交
git log refA refB ^refC # 等同于 git log refA refB –not refC
部分暂存
git stash
git clean
1. 交互式暂存 – 精细化控制提交内容 ✨
改了多个文件,想把不同修改分到不同提交?交互式暂存帮你实现!不用一次性暂存所有修改~
git add -i # 或 git add –interactive# 进入交互界面后,输入对应数字操作:
# 1: status – 查看状态
# 2: update – 暂存文件
# 3: revert – 取消暂存
# 5: patch – 部分暂存(只暂存文件的某部分)
# 6: diff – 查看暂存的差异
# 7: quit – 退出
重点:部分暂存(patch 模式)
同一个文件改了两处,想把一处先提交,另一处后续再处理?用 patch 模式精准暂存!
git add -p # 或 git add –patch# 对每个修改块(hunk)选择操作:
# y – 暂存这个块
# n – 不暂存
# a – 暂存当前文件的所有块
# d – 不暂存当前文件的所有块
# s – 拆分当前块(把大修改拆成小的)
# ? – 查看帮助
2. git stash – 临时储藏修改 🧳
正在改代码,突然要切换分支修 bug?不想提交半成品?用 stash 把当前修改临时储藏起来,干净切换!
git stash # 等同于 git stash save# 查看储藏列表
git stash list # 输出:stash@{0}: WIP on master: 049d078 添加索引文件
# 应用最新的储藏(应用后不删除储藏)
git stash apply
# 应用某个特定储藏
git stash apply stash@{1}
# 应用并删除储藏(常用!)
git stash pop
# 储藏时保留暂存的内容(只储藏未暂存的)
git stash –keep-index
# 储藏未跟踪的文件(比如新建的文件)
git stash -u # 或 git stash –include-untracked
进阶:从储藏创建分支
储藏的修改应用时冲突了?直接从储藏创建分支,在新分支里解决冲突更安全!
3. git clean – 清理工作区 🧹
工作区有很多编译产物、临时文件?用 git clean 快速清理未跟踪的文件和目录~
git clean -n -d # -d 包括目录,-n 不实际删除# 强制清理未跟踪的文件和目录
git clean -f -d # -f 强制清理
# 清理包括.gitignore 里的文件(比如编译后的.o 文件)
git clean -f -d -x
# 交互式清理(逐个确认)
git clean -i -x
交互式 rebase
合并提交
拆分提交
filter-branch
1. amend 提交 – 修正最后一次提交 ✨
提交后发现漏改了文件、提交信息写错了?用 amend 快速修正,不用多建一个提交!
git commit –amend # 会打开编辑器修改提交信息# 漏加文件,补充到最后一次提交
git add 漏加的文件
git commit –amend # 保持原有提交信息,只更新提交内容
2. 交互式 rebase – 批量改写历史 📝
想修改多个提交的信息、合并提交、删除提交?交互式 rebase 是终极工具!
git rebase -i HEAD~3# 执行后会打开编辑器,显示提交列表,每行开头是操作指令:
# pick:保留该提交
# reword:保留提交,修改提交信息
# edit:保留提交,暂停允许修改(比如加文件)
# squash:合并到前一个提交
# fixup:合并到前一个提交,丢弃当前提交信息
# drop:删除该提交
场景 1:合并多个提交(squash)
把多个零散的“修复 bug”“优化代码”提交合并成一个清晰的提交:
# 示例:
# pick f7f3f6d 初始修改
# squash 310154e 修复 bug1
# squash a5f4a0d 优化代码# 保存后会打开编辑器,合并提交信息
# 最终会变成一个提交,包含所有修改
场景 2:拆分提交(edit)
把一个包含多个功能的大提交,拆分成多个小提交:
git rebase -i HEAD~3# 2. 执行后会暂停在该提交,重置该提交的修改
git reset HEAD^
# 3. 分次暂存和提交
git add 功能 1 相关文件
git commit -m “ 实现功能 1 ”
git add 功能 2 相关文件
git commit -m “ 实现功能 2 ”
# 4. 继续完成 rebase
git rebase –continue
3. filter-branch – 批量改写历史(进阶)🔧
需要全局修改历史(比如删除敏感文件、修改所有提交的邮箱)?用 filter-branch,谨慎使用!
git filter-branch –tree-filter ‘rm -f passwords.txt’ HEAD# 把 trunk 目录设为项目根目录(清理导入的代码)
git filter-branch –subdirectory-filter trunk HEAD
# 全局修改提交邮箱(替换旧邮箱为新邮箱)
git filter-branch –commit-filter ‘
if [“$GIT_AUTHOR_EMAIL” = “ 旧邮箱 @example.com”]; then
GIT_AUTHOR_EMAIL=” 新邮箱 @example.com”
git commit-tree “$@”
else
git commit-tree “$@”
fi
‘ HEAD
三方合并
撤销合并
rerere
1. 忽略空白冲突 – 解决格式差异导致的冲突 📄
有人把空格改成制表符、换行格式不一样,导致大量“假冲突”?合并时忽略空白差异即可!
git merge -Xignore-space-change 分支名
# 或忽略所有空白(更彻底)
git merge -Xignore-all-space 分支名
2. 三方合并 – 手动处理复杂冲突 🧩
冲突太复杂,Git 自动合并失败?手动提取三方文件(自己的版本、对方的版本、共同祖先版本),手动合并!
git show :1: 文件名 > 文件名.common # 共同祖先版本
git show :2: 文件名 > 文件名.ours # 自己的版本
git show :3: 文件名 > 文件名.theirs # 对方的版本# 手动编辑文件,合并后替换原文件
vim 文件名
git add 文件名
git commit -m “ 解决合并冲突 ”
3. 撤销合并 – 合并错了怎么办?🚫
合并后发现代码有问题,想撤销合并?分两种情况:
git merge –abort # 撤销合并,回到合并前状态# 情况 2:已经提交了合并 commit
# 方法 1:reset(本地仓库,未推送远程)
git reset –hard HEAD^ # 回到合并前的提交
# 方法 2:revert(已推送远程,推荐!)
git revert -m 1 HEAD # -m 1 表示保留第一个父提交(自己的分支)
4. rerere – 重复冲突自动解决 🤖
经常合并同一个分支,每次都遇到相同的冲突?开启 rerere,Git 会记住你的解决方式,下次自动解决!
git config –global rerere.enabled true# 之后遇到冲突并解决后,Git 会自动记录解决方案
# 下次再遇到相同冲突时,自动应用之前的解决方式
添加子模块
更新子模块
克隆含子模块的仓库
1. 添加子模块 – 引入外部项目 📥
项目需要依赖另一个 Git 仓库(比如自己写的工具库)?用子模块引入,保持两个项目独立,又能方便使用!
git submodule add https://github.com/chaconinc/DbConnector DbConnector# 添加后会生成两个文件,需要提交到仓库
git add .gitmodules DbConnector
git commit -m “ 添加 DbConnector 子模块 ”
.gitmodules 文件:记录子模块的 URL 和本地路径,必须提交;DbConnector:子模块目录,Git 会跟踪其提交哈希,不跟踪内部文件。
2. 克隆含子模块的仓库 📦
克隆别人的仓库,发现子模块目录是空的?需要初始化并更新子模块:
git clone –recursive https://github.com/ 用户名 / 项目名.git# 方法 2:先克隆主仓库,再手动初始化
git clone https://github.com/ 用户名 / 项目名.git
cd 项目名
git submodule init # 初始化子模块配置
git submodule update # 拉取子模块代码
3. 更新子模块 – 同步上游修改 🔄
子模块的上游仓库更新了,想同步到主项目?
cd DbConnector
git pull origin master
cd ..# 或在主项目根目录,一键更新所有子模块
git submodule update –remote # 拉取子模块的远程最新代码
# 提交子模块的更新(主项目会跟踪子模块的最新哈希)
git add DbConnector
git commit -m “ 更新 DbConnector 子模块到最新版本 ”
4. 子模块的坑与技巧 ⚠️
- 切换分支时,子模块目录可能残留:用 git clean -fd 清理
- 子模块默认处于“分离头指针”状态:进入子模块 checkout 分支后再修改
- 推送主项目前,先推送子模块:避免主项目引用了子模块未推送的提交
- 批量操作子模块:git submodule foreach ‘git pull’(所有子模块执行 git pull)
场景 1:定位 bug 引入的提交(二分查找)🐛
代码突然出 bug,不知道哪个提交搞坏的?用 git bisect 二分查找,快速定位!
git bisect start# 标记当前版本为坏提交
git bisect bad
# 标记已知的好提交(比如 v1.0 版本)
git bisect good v1.0
# Git 会自动切换到中间提交,测试是否有 bug
# 有 bug:git bisect bad
# 没 bug:git bisect good
# 重复测试,直到 Git 找到第一个坏提交
# 结束查找,回到当前分支
git bisect reset
场景 2:搜索代码和提交 🕵️
想找某个函数在哪里定义、哪个提交修改了某行代码?用 Git 的搜索工具!
git grep -n “gmtime_r”# 搜索所有提交中的字符串(查找哪个提交添加了该字符串)
git log -S “gmtime_r” –oneline
# 查看某行代码的修改历史(-L 行范围: 文件名)
git log -L 12,22:lib/simplegit.rb
场景 3:离线分享代码(bundle)📤
没有网络,想把代码分享给同事?用 git bundle 打包成一个文件,拷贝即可!
git bundle create repo.bundle HEAD master# 只打包最近 3 个提交(适合增量分享)
git bundle create commits.bundle master^..master
# 同事接收后,克隆打包文件
git clone repo.bundle 新项目名
# 应用增量打包
git fetch commits.bundle master:new-branch
- 版本选择:用短 SHA-1、reflog、祖先引用快速定位提交
- 暂存与储藏:交互式暂存精细化控制提交,stash 临时保存修改,clean 清理垃圾文件
- 改写历史:amend 修正最后一次提交,交互式 rebase 批量优化历史,filter-branch 全局修改(谨慎使用)
- 合并冲突:忽略空白冲突、手动三方合并、rerere 自动解决重复冲突
- 子模块:管理外部依赖,注意初始化和更新流程
要不要我帮你整理一份 Git 高级工具速查手册 ?包含常用命令、场景化用法、避坑指南,打印出来就能随时查阅,遇到复杂问题直接翻~