🧩 Git 进阶技巧与最佳实践
1. 使用标签(Tag)标记版本
标签用于标记重要的版本节点,如发布版本。
创建标签
bash
# 创建轻量标签(只保存标签名)
git tag v1.0.0
# 创建附注标签(推荐,包含更多信息)
git tag -a v1.0.0 -m "发布版本 1.0.0"
# 为特定提交创建标签
git tag -a v1.0.0 commit-hash -m "版本 1.0.0"
# 创建带签名的标签
git tag -s v1.0.0 -m "签名的版本标签"
查看标签
bash
# 查看所有标签
git tag
# 查看特定标签信息
git show v1.0.0
# 按模式搜索标签
git tag -l "v1.*"
# 查看标签列表及提交信息
git tag -n
推送标签
bash
# 推送单个标签
git push origin v1.0.0
# 推送所有标签
git push origin --tags
# 推送所有附注标签
git push --follow-tags
删除标签
bash
# 删除本地标签
git tag -d v1.0.0
# 删除远程标签
git push origin --delete v1.0.0
# 或
git push origin :refs/tags/v1.0.0
检出标签
bash
# 检出标签(会进入分离 HEAD 状态)
git checkout v1.0.0
# 基于标签创建分支
git checkout -b release-v1.0.0 v1.0.0
语义化版本(Semantic Versioning)
遵循语义化版本规范:主版本号.次版本号.修订号
- 主版本号:不兼容的 API 修改
- 次版本号:向下兼容的功能性新增
- 修订号:向下兼容的问题修正
示例:v1.2.3、v2.0.0-beta.1
2. 查看历史与追踪问题
git log - 查看提交历史
bash
# 基础查看
git log
# 简洁一行显示
git log --oneline
# 图形化显示分支
git log --graph --oneline --all
# 查看最近 N 条
git log -n 5
# 查看特定时间范围
git log --since="2024-01-01" --until="2024-12-31"
# 查看特定作者的提交
git log --author="张三"
# 查看包含特定关键词的提交
git log --grep="登录"
# 查看特定文件的提交历史
git log -- filename.txt
# 查看两个提交之间的差异
git log commit1..commit2
# 统计信息
git log --stat
git log --shortstat
# 查看文件变更
git log --patch
git log -p
git blame - 查看文件每行的作者
bash
# 查看文件的每一行是谁修改的
git blame filename.txt
# 显示更详细的信息
git blame -w filename.txt # 忽略空白字符
git blame -L 10,20 filename.txt # 查看第 10-20 行
# 显示邮箱
git blame -e filename.txt
git grep - 在代码库中搜索
bash
# 在工作区搜索
git grep "搜索内容"
# 在特定提交中搜索
git grep "搜索内容" commit-hash
# 忽略大小写
git grep -i "搜索内容"
# 显示行号
git grep -n "搜索内容"
# 递归搜索(默认)
git grep -r "搜索内容"
# 只搜索特定文件类型
git grep "搜索内容" -- "*.js"
git bisect - 二分查找问题提交
用于快速定位引入 bug 的提交。
bash
# 开始二分查找
git bisect start
# 标记当前版本有问题
git bisect bad
# 标记某个旧版本没问题
git bisect good v1.0.0
# Git 会自动切换到中间版本
# 测试后标记 good 或 bad
git bisect good
# 或
git bisect bad
# 继续直到找到问题提交
# Git 会显示引入问题的提交
# 结束二分查找
git bisect reset
git reflog - 查看引用日志
reflog 记录了所有 HEAD 的移动历史,可以找回丢失的提交。
bash
# 查看引用日志
git reflog
# 查看特定分支的日志
git reflog show branch-name
# 恢复丢失的提交
git checkout commit-hash
git checkout -b recovered-branch
3. Rebase 的安全使用方法与风险
什么是 Rebase?
Rebase 可以将一系列提交重新应用到另一个基点上,使提交历史更加线性。
基本用法
bash
# 将当前分支变基到目标分支
git checkout feature-branch
git rebase main
# 交互式 rebase(推荐)
git rebase -i HEAD~3 # 编辑最近 3 个提交
# 变基到特定提交
git rebase commit-hash
# 变基到远程分支
git rebase origin/main
交互式 Rebase
bash
git rebase -i HEAD~3
# 会打开编辑器,显示:
pick abc123 提交信息1
pick def456 提交信息2
pick ghi789 提交信息3
# 可以修改为:
pick abc123 提交信息1
squash def456 提交信息2 # 合并到上一个提交
edit ghi789 提交信息3 # 编辑这个提交
drop jkl012 提交信息4 # 删除这个提交
交互式命令:
pick:保留提交reword:修改提交信息edit:编辑提交内容squash:合并到上一个提交fixup:合并但丢弃提交信息drop:删除提交
Rebase vs Merge
Merge:
- 保留完整的分支历史
- 创建合并提交
- 历史更复杂但更真实
Rebase:
- 线性历史,更清晰
- 不创建合并提交
- 历史被重写
bash
# Merge 示例
git checkout main
git merge feature-branch
# 历史:main -> feature -> merge commit
# Rebase 示例
git checkout feature-branch
git rebase main
git checkout main
git merge feature-branch
# 历史:main -> feature commits (线性)
Rebase 的风险与注意事项
⚠️ 风险:
- 重写历史:Rebase 会改变提交的哈希值
- 已推送的提交:不要对已推送到共享分支的提交进行 rebase
- 冲突处理:可能需要多次解决冲突
✅ 安全的使用场景:
- 本地分支的整理
- 合并到主分支前清理提交历史
- 个人功能分支
❌ 不安全的场景:
- 对已推送的共享分支进行 rebase
- 多人协作的公共分支
解决 Rebase 冲突
bash
# 如果在 rebase 过程中遇到冲突
git rebase main
# CONFLICT (content): Merge conflict in file.txt
# 解决冲突
# 编辑冲突文件
# 标记已解决
git add file.txt
# 继续 rebase
git rebase --continue
# 如果想放弃 rebase
git rebase --abort
Rebase 最佳实践
-
只在个人分支使用
bash# ✅ 安全:个人功能分支 git checkout feature/my-feature git rebase main # ❌ 危险:共享分支 git checkout main git rebase feature-branch # 不要这样做! -
使用
--onto进行复杂变基bash# 将 feature 分支变基到 main,但排除某些提交 git rebase --onto main old-base feature -
变基后强制推送(谨慎)
bash# 如果确定要重写远程分支历史 git push --force-with-lease origin feature-branch # 比 --force 更安全,会检查远程是否有新提交
4. 常见错误与救命指令
撤销误删分支
bash
# 方法 1:使用 reflog 找回
git reflog
git checkout -b recovered-branch commit-hash
# 方法 2:如果知道分支名
git checkout -b deleted-branch origin/deleted-branch
找回丢失的 commit
bash
# 1. 查看 reflog
git reflog
# 2. 找到丢失的提交哈希
git checkout commit-hash
# 3. 创建新分支保存
git checkout -b recovered-commit
# 4. 或者直接重置当前分支
git reset --hard commit-hash
清理混乱的提交记录
bash
# 方法 1:交互式 rebase 整理
git rebase -i HEAD~5
# 在编辑器中整理提交
# 方法 2:重置到某个干净的提交
git reset --hard clean-commit-hash
# 方法 3:创建新分支重新开始
git checkout -b clean-branch clean-commit
撤销误提交到暂存区
bash
# 撤销单个文件
git restore --staged filename.txt
# 撤销所有文件
git restore --staged .
撤销工作区修改
bash
# 撤销单个文件
git restore filename.txt
# 撤销所有文件(危险!)
git restore .
修改最近的提交
bash
# 修改提交信息
git commit --amend -m "新的提交信息"
# 添加文件到最近提交
git add forgotten-file.txt
git commit --amend --no-edit
撤销已推送的提交(安全方式)
bash
# 使用 revert(推荐)
git revert HEAD
git push origin main
# 如果确定要重写历史(危险!)
git reset --hard HEAD~1
git push --force-with-lease origin main
清理未跟踪的文件
bash
# 查看将要删除的文件
git clean -n
# 删除未跟踪的文件
git clean -f
# 删除未跟踪的文件和目录
git clean -fd
# 交互式删除
git clean -i
恢复误删的文件
bash
# 从最后一次提交恢复
git checkout HEAD -- filename.txt
# 从特定提交恢复
git checkout commit-hash -- filename.txt
急救命令速查
bash
# 查看当前状态
git status
git log --oneline -10
# 查看所有操作历史
git reflog
# 查看差异
git diff
git diff --staged
# 撤销工作区修改
git restore filename.txt
# 撤销暂存区
git restore --staged filename.txt
# 修改最近提交
git commit --amend
# 放弃当前合并/变基
git merge --abort
git rebase --abort
# 重置到某个状态
git reset --hard commit-hash
高级技巧
子模块(Submodule)
bash
# 添加子模块
git submodule add https://github.com/user/repo.git path/to/submodule
# 克隆包含子模块的项目
git clone --recursive https://github.com/user/main-repo.git
# 更新子模块
git submodule update --init --recursive
钩子(Hooks)
bash
# 查看可用钩子
ls .git/hooks/
# 创建 pre-commit 钩子示例
#!/bin/sh
# .git/hooks/pre-commit
npm test
别名(Alias)
bash
# 创建常用别名
git config --global alias.st status
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit
git config --global alias.unstage 'reset HEAD --'
git config --global alias.last 'log -1 HEAD'
git config --global alias.visual '!gitk'
常见问题
Q: 如何查看某个文件的完整历史?
A: 使用 git log --follow --all -- filename.txt
Q: Rebase 和 Merge 应该用哪个?
A: 个人分支用 rebase 保持整洁,合并到主分支用 merge 保留历史。
Q: 如何撤销一个已推送的提交?
A: 使用 git revert 创建新提交来撤销,这是最安全的方式。
Q: 如何查看两个分支的差异?
A: 使用 git diff branch1..branch2 或 git log branch1..branch2
下一步 :学习 推荐团队实践