Git 那些不太常用但非常实用的命令

Git 那些不太常用但非常实用的命令

前言

在日常开发中,我们经常使用 git addgit commitgit push 等基础命令。但 Git 还提供了许多强大而实用的命令,虽然不太常用,但在特定场景下能极大提升工作效率。本文将介绍几个这样的命令,帮助你更好地利用 Git 的强大功能。


1. git worktree - 多工作目录管理

什么是 git worktree?

git worktree 允许你在同一个仓库中创建多个工作目录,每个工作目录可以检出不同的分支。这对于需要同时处理多个分支的场景非常有用。

为什么需要 git worktree?

传统方式的痛点:

  • 需要频繁切换分支时,会丢失未提交的更改
  • 无法同时查看和编辑不同分支的代码
  • 切换分支时可能需要重新构建项目,耗时较长

git worktree 的优势:

  • 可以在不同目录同时工作于不同分支
  • 每个工作树独立,互不干扰
  • 共享同一个 .git 仓库,节省磁盘空间

基本用法

创建新的工作树
bash 复制代码
# 在指定目录创建新的工作树,并检出指定分支
git worktree add <path> <branch>

# 示例:在 ../myproject-feature 目录创建新工作树,检出 feature/new-ui 分支
git worktree add ../myproject-feature feature/new-ui

# 如果分支不存在,可以创建新分支
git worktree add ../myproject-hotfix -b hotfix/critical-bug
列出所有工作树
bash 复制代码
git worktree list

输出示例:

bash 复制代码
/Users/pfinal/myproject                 abc1234 [main]
/Users/pfinal/myproject-feature         def5678 [feature/new-ui]
/Users/pfinal/myproject-hotfix          ghi9012 [hotfix/critical-bug]
删除工作树
bash 复制代码
# 删除工作树(需要先删除工作目录)
rm -rf ../myproject-feature
git worktree remove ../myproject-feature

# 或者使用 prune 自动清理无效的工作树
git worktree prune
移动工作树
bash 复制代码
git worktree move <old-path> <new-path>

实际应用场景

场景 1:同时开发新功能和修复 Bug

bash 复制代码
# 主目录用于开发新功能
cd /path/to/project
git checkout feature/new-feature

# 创建新工作树用于修复紧急 Bug
git worktree add ../project-hotfix hotfix/urgent-fix
cd ../project-hotfix
# 现在可以同时编辑两个分支的代码

场景 2:代码审查时对比不同版本

bash 复制代码
# 主目录保持当前开发分支
# 创建工作树查看 PR 分支
git worktree add ../project-pr origin/feature/pr-branch

场景 3:长期维护多个版本

bash 复制代码
# 主目录:最新开发版本
# 工作树 1:生产版本
git worktree add ../project-prod v1.0.0

# 工作树 2:测试版本
git worktree add ../project-test v1.1.0-beta

注意事项

  • 每个工作树必须检出不同的分支
  • 不能删除包含未提交更改的工作树
  • 所有工作树共享同一个 .git 仓库
  • 删除工作树时,需要先删除目录再运行 git worktree remove

2. git reflog - 找回"丢失"的提交

什么是 reflog?

reflog 记录了 HEAD 和分支引用的所有变更历史,即使提交已经被"删除",也能通过 reflog 找回。

使用场景

场景:误删分支或重置提交

bash 复制代码
# 查看 reflog 历史
git reflog

# 输出示例:
# abc1234 HEAD@{0}: checkout: moving from main to feature
# def5678 HEAD@{1}: commit: Add new feature
# ghi9012 HEAD@{2}: reset: moving to HEAD~1
# jkl3456 HEAD@{3}: commit: Fix bug

# 恢复到之前的某个状态
git checkout HEAD@{2}  # 恢复到 reset 之前的状态

# 或者恢复已删除的分支
git branch recovered-branch HEAD@{1}

高级用法

bash 复制代码
# 查看特定分支的 reflog
git reflog show <branch-name>

# 查看最近 10 条记录
git reflog -10

# 查看特定时间范围的记录
git reflog --since="2 days ago"

3. git bisect - 二分查找定位 Bug

什么是 git bisect?

git bisect 使用二分查找算法,帮助你快速定位引入 Bug 的提交。

使用流程

bash 复制代码
# 1. 开始二分查找
git bisect start

# 2. 标记当前版本为"坏"的(有 Bug)
git bisect bad

# 3. 标记某个已知好的版本(没有 Bug)
git bisect good <commit-hash>
# 或者
git bisect good v1.0.0

# 4. Git 会自动检出中间的提交,你测试后标记好坏
git bisect good  # 如果这个版本没问题
git bisect bad   # 如果这个版本有问题

# 5. 重复步骤 4,直到找到引入 Bug 的提交

# 6. 结束二分查找,返回原分支
git bisect reset

自动化 bisect

bash 复制代码
# 使用脚本自动测试
git bisect start HEAD v1.0.0
git bisect run npm test

# Git 会自动运行测试脚本,根据退出码判断好坏
# 退出码 0 = good,非 0 = bad

实际示例

bash 复制代码
# 假设 Bug 在最近 100 个提交中引入
git bisect start
git bisect bad                    # 当前版本有 Bug
git bisect good HEAD~100          # 100 个提交前是好的

# Git 检出第 50 个提交,你测试后发现没问题
git bisect good

# Git 检出第 75 个提交,你测试后发现有问题
git bisect bad

# 继续这个过程,通常只需 log2(n) 次测试就能找到问题提交

4. git stash - 暂存更改的进阶用法

基础用法回顾

bash 复制代码
# 暂存当前更改
git stash

# 恢复暂存的更改
git stash pop

# 查看所有暂存
git stash list

进阶用法

给暂存添加描述
bash 复制代码
git stash save "WIP: 正在开发登录功能"
暂存特定文件
bash 复制代码
# 只暂存部分文件
git stash push -m "保存 UI 更改" -- src/components/Button.tsx src/styles/
暂存时保留未跟踪的文件
bash 复制代码
# 默认不暂存未跟踪的文件,使用 -u 包含它们
git stash -u
# 或者
git stash --include-untracked
暂存时保留索引(已 add 的文件)
bash 复制代码
# 保留已暂存的文件在索引中
git stash --keep-index
应用特定的暂存
bash 复制代码
# 查看暂存列表
git stash list
# stash@{0}: WIP on main: abc1234 Fix bug
# stash@{1}: WIP on feature: def5678 Add feature

# 应用特定的暂存(不删除)
git stash apply stash@{1}

# 应用并删除
git stash pop stash@{1}
创建暂存分支
bash 复制代码
# 从暂存创建新分支
git stash branch new-feature-branch

5. git cherry-pick - 选择性应用提交

基本用法

bash 复制代码
# 将其他分支的提交应用到当前分支
git cherry-pick <commit-hash>

# 应用多个提交
git cherry-pick <commit1> <commit2> <commit3>

# 应用一个范围的提交
git cherry-pick <start-commit>..<end-commit>
# 注意:不包含 start-commit,只包含 end-commit

# 包含起始提交
git cherry-pick <start-commit>^..<end-commit>

实际场景

场景:将 hotfix 分支的修复应用到 main 分支

bash 复制代码
# 在 hotfix 分支找到修复提交的 hash
git log hotfix/bug-fix
# commit abc1234: Fix critical security issue

# 切换到 main 分支
git checkout main

# 应用这个提交
git cherry-pick abc1234

高级选项

bash 复制代码
# 只应用更改,不自动提交
git cherry-pick -n <commit-hash>
# 或者
git cherry-pick --no-commit <commit-hash>

# 编辑提交信息
git cherry-pick -e <commit-hash>

# 如果遇到冲突,继续 cherry-pick
git cherry-pick --continue

# 放弃 cherry-pick
git cherry-pick --abort

6. git submodule - 子模块管理

什么是 submodule?

Submodule 允许你将一个 Git 仓库作为另一个 Git 仓库的子目录,常用于管理项目依赖。

基本操作

添加子模块
bash 复制代码
git submodule add <repository-url> <path>

# 示例
git submodule add https://github.com/user/library.git libs/external-library
克隆包含子模块的项目
bash 复制代码
# 方法 1:递归克隆
git clone --recursive <repository-url>

# 方法 2:先克隆,再初始化子模块
git clone <repository-url>
git submodule init
git submodule update

# 或者合并执行
git submodule update --init --recursive
更新子模块
bash 复制代码
# 更新所有子模块到最新提交
git submodule update --remote

# 更新特定子模块
git submodule update --remote libs/external-library
删除子模块
bash 复制代码
# 1. 删除 .gitmodules 中的条目
git rm --cached libs/external-library

# 2. 删除 .git/modules 中的目录
rm -rf .git/modules/libs/external-library

# 3. 删除工作目录
rm -rf libs/external-library

# 4. 提交更改
git commit -m "Remove submodule"

7. git filter-branch / git filter-repo - 重写历史

git filter-branch(已弃用,但仍有参考价值)

bash 复制代码
# 从所有提交中删除某个文件
git filter-branch --tree-filter 'rm -f passwords.txt' HEAD

# 修改所有提交的邮箱
git filter-branch --env-filter '
OLD_EMAIL="old@example.com"
CORRECT_NAME="Your Name"
CORRECT_EMAIL="new@example.com"

if [ "$GIT_COMMITTER_EMAIL" = "$OLD_EMAIL" ]
then
    export GIT_COMMITTER_NAME="$CORRECT_NAME"
    export GIT_COMMITTER_EMAIL="$CORRECT_EMAIL"
fi
if [ "$GIT_AUTHOR_EMAIL" = "$OLD_EMAIL" ]
then
    export GIT_AUTHOR_NAME="$CORRECT_NAME"
    export GIT_AUTHOR_EMAIL="$CORRECT_EMAIL"
fi
' --tag-name-filter cat -- --branches --tags

git filter-repo(推荐使用)

git filter-repogit filter-branch 的现代替代品,更快更安全。

bash 复制代码
# 安装(需要单独安装)
pip install git-filter-repo

# 删除文件
git filter-repo --path passwords.txt --invert-paths

# 重写路径
git filter-repo --path-rename old/path:new/path

# 修改提交信息
git filter-repo --message-callback 'return message.replace(b"old", b"new")'

⚠️ 警告: 这些命令会重写 Git 历史,使用前请备份仓库!


8. git blame - 代码责任追踪

基本用法

bash 复制代码
# 查看文件的每一行是谁修改的
git blame <file>

# 查看特定行的详细信息
git blame -L <start-line>,<end-line> <file>

# 示例:查看第 10-20 行
git blame -L 10,20 src/utils.js

高级选项

bash 复制代码
# 忽略空白更改
git blame -w <file>

# 显示更详细的信息
git blame -C -C -C <file>  # 检测代码移动和复制

# 查看特定版本的 blame
git blame <commit> -- <file>

实际应用

bash 复制代码
# 找出谁引入了某个 Bug
git blame -L 42,42 src/buggy-file.js

# 查看代码的演变历史
git log -p -L 42,42:src/buggy-file.js

9. git log 的高级用法

图形化显示

bash 复制代码
# 显示分支图
git log --oneline --graph --all

# 更美观的图形
git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --all

搜索提交

bash 复制代码
# 按作者搜索
git log --author="John"

# 按提交信息搜索
git log --grep="bug fix"

# 按文件搜索
git log -- <file-path>

# 按代码内容搜索(pickaxe)
git log -S "functionName"  # 查找添加或删除该字符串的提交
git log -G "regex"         # 使用正则表达式

时间范围

bash 复制代码
# 最近一周的提交
git log --since="1 week ago"

# 特定日期范围
git log --since="2024-01-01" --until="2024-01-31"

# 最近 N 个提交
git log -10

统计信息

bash 复制代码
# 显示每个文件的更改统计
git log --stat

# 显示详细的代码更改
git log -p

# 显示简短的统计
git log --shortstat

10. git clean - 清理未跟踪的文件

基本用法

bash 复制代码
# 预览将要删除的文件(干运行)
git clean -n

# 删除未跟踪的文件
git clean -f

# 删除未跟踪的文件和目录
git clean -fd

# 交互式删除
git clean -i

高级选项

bash 复制代码
# 只删除特定类型的文件
git clean -f "*.log"

# 排除某些文件
git clean -fd --exclude="*.tmp"

# 删除被忽略的文件(.gitignore 中的文件)
git clean -fX

# 删除所有未跟踪的文件,包括被忽略的
git clean -fx

11. git rerere - 重用已解决的冲突

什么是 rerere?

rerere (Reuse Recorded Resolution) 可以记住你如何解决冲突,当相同冲突再次出现时自动应用之前的解决方案。

启用 rerere

bash 复制代码
# 全局启用
git config --global rerere.enabled true

# 或者只对当前仓库启用
git config rerere.enabled true

使用场景

场景:长期分支合并

bash 复制代码
# 1. 启用 rerere
git config rerere.enabled true

# 2. 合并分支,解决冲突
git merge feature-branch
# 手动解决冲突...

# 3. 提交
git commit

# 4. 如果之后再次遇到相同的冲突,Git 会自动应用之前的解决方案

12. git notes - 为提交添加注释

基本用法

bash 复制代码
# 为提交添加注释
git notes add <commit-hash>

# 查看注释
git notes show <commit-hash>

# 编辑注释
git notes edit <commit-hash>

# 删除注释
git notes remove <commit-hash>

实际应用

bash 复制代码
# 为提交添加代码审查注释
git notes add -m "Reviewed by John, approved" abc1234

# 添加性能测试结果
git notes add -m "Performance: 1000 req/s" def5678

# 查看带注释的日志
git log --show-notes=*

总结

这些 Git 命令虽然不常用,但在特定场景下能显著提升工作效率:

  • git worktree - 多分支并行开发
  • git reflog - 找回"丢失"的提交
  • git bisect - 快速定位 Bug
  • git stash - 灵活的暂存管理
  • git cherry-pick - 选择性应用提交
  • git submodule - 管理项目依赖
  • git filter-repo - 重写历史(谨慎使用)
  • git blame - 代码责任追踪
  • git log - 强大的提交查询
  • git clean - 清理工作区
  • git rerere - 自动解决重复冲突
  • git notes - 为提交添加元数据

掌握这些命令,能让你在复杂的开发场景中游刃有余。建议在实际项目中逐步尝试使用,积累经验。


延伸阅读


最后更新:2024年

相关推荐
Victor3564 小时前
MongoDB(2)MongoDB与传统关系型数据库的主要区别是什么?
后端
JaguarJack4 小时前
PHP 应用遭遇 DDoS 攻击时会发生什么 从入门到进阶的防护指南
后端·php·服务端
BingoGo4 小时前
PHP 应用遭遇 DDoS 攻击时会发生什么 从入门到进阶的防护指南
后端
Victor3564 小时前
MongoDB(3)什么是文档(Document)?
后端
牛奔6 小时前
Go 如何避免频繁抢占?
开发语言·后端·golang
想用offer打牌11 小时前
MCP (Model Context Protocol) 技术理解 - 第二篇
后端·aigc·mcp
KYGALYX12 小时前
服务异步通信
开发语言·后端·微服务·ruby
掘了12 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
爬山算法13 小时前
Hibernate(90)如何在故障注入测试中使用Hibernate?
java·后端·hibernate
Moment13 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端