7 个让你看起来像巫师的 Git 命令

发布: (2026年2月7日 GMT+8 22:00)
14 分钟阅读
原文: Dev.to

Source: Dev.to

你知道到底是什么把那些看起来好像很懂的开发者和每天只会去 Google “how to undo git commit” 的人区分开来吗?
这并不是因为懂得花哨的算法或记住设计模式,而是因为你对 Git 的了解已经超越了 addcommitpush,以及慌乱中搜索合并冲突。

我说的就是那些能让你的结对编程伙伴停下来惊呼:“等等,你真的能做到吗?”的命令。那些深层技巧能把 30 分钟的灾难恢复变成 10 秒的炫技。

Source:

1. git reflog – 你不知道的撤销按钮

每个开发者都有这样的时刻:把代码强制推送到错误的分支,执行了 git reset --hard 后看着自己的工作消失,或者在 rebase 之后发现提交历史变成了抽象艺术。

你以为它已经没了。其实没有。

git reflog 是 Git 的飞行记录仪。它会记录 HEAD 曾经指向的每一次位置,即使这些位置已经不在任何分支上。被删除的提交、被放弃的 rebase、强推导致的“牺牲品”——它们全部都在里面。

场景:你刚刚执行了 git reset --hard HEAD~3,立刻意识到把错误的提交给删掉了。胃里一阵翻江倒海,三小时的工作瞬间消失。

# 查看 HEAD 曾经指向的所有位置
git reflog

输出类似:

a1b2c3d HEAD@{0}: reset: moving to HEAD~3
f4e5d6c HEAD@{1}: commit: implement payment webhook
7g8h9i0 HEAD@{2}: commit: add Stripe integration
j1k2l3m HEAD@{3}: commit: refactor checkout flow

只要……回到过去。

git reset --hard f4e5d6c

就这么简单。你的提交又回来了。毫不费力。当其他人惊慌失措、重新克隆仓库时,你已经像时间旅行者一样轻松恢复了历史。

专业提示:Reflog 条目默认在 90 天后过期,所以别等到三个月后才发现需要恢复某些内容。

2. git bisect – 让 Git 为你找出 bug

想象一下:你的 CI 通过,测试也通过,但在最近的 47 次提交中,登录页在 Firefox 上开始倒置渲染。没有人知道是哪一次提交导致的。

你可以像动物一样一个一个地检出每个提交。或者让 Git 自动在历史记录中进行二分查找。

# 开始查找
git bisect start

# 将当前(出错)状态标记为坏
git bisect bad

# 标记一个已知的好提交(比如上周的发布标签)
git bisect good v2.3.1

Git 会检出中间的提交。你进行测试。

# 如果它坏了:
git bisect bad

# 如果它正常:
git bisect good

重复上述操作。Git 会在 log₂(n) 步内缩小范围。

47 次提交? 只需要大约 6 次检查,而不是 47 次。

如果在好状态和坏状态之间有 1 000 次提交,你大约只需 10 步就能找到罪魁祸首。它实际上在你的提交历史上做了一次二分搜索。这才是真正有用的计算机科学™。

**进阶用法:**如果你有一个可以自动判断好坏的测试脚本:

git bisect start HEAD v2.3.1
git bisect run ./test-login-page.sh

去喝杯咖啡吧。等你回来时,Git 已经找到了导致问题的确切提交,你只需指向那个有罪的提交,就能像终端里的福尔摩斯一样。

3. git stash -p – 外科手术式的暂存

大家都知道 git stash。但大多数人把它当作大锤子来用:把所有改动都暂存,然后祈祷它能完好无损地恢复。

-p 参数(patch 的缩写)让你交互式地选择 哪些 块要暂存。适用于你同时在处理两件事(别装作不知道)的场景,需要只提交其中一部分而不包括另一部分。

场景: 你正进行一个功能的开发,但在途中发现并修复了一个 bug。你想现在就提交这个 bug‑fix,然后继续开发功能。

# 交互式挑选要暂存的内容
git stash -p

Git 会一次展示一个改动块:

Stash this hunk [y,n,q,a,d,s,e,?]?
  y = stash this hunk
  n = keep this hunk (don’t stash)
  s = split into smaller hunks
  q = quit (done selecting)

此时你的工作目录只剩下 bug‑fix。

git add -A && git commit -m "fix: null check on user session"

把功能的工作恢复回来:

git stash pop

s 选项是秘密武器:当 Git 把两个改动合并成一个块时,它可以把该块再拆分成更小的块。对工作树进行精确的外科手术。

额外组合:

git stash -p -m "WIP: auth refactor"

让你既可以选择性地暂存,又可以为暂存项命名,避免三天后玩“哪个暂存是哪一个?”的轮盘赌。

Source:

4. git rebase -i – 像你本来想的那样重写历史

交互式 rebase 是唯一最强大的 Git 命令,也是大多数人最害怕的。别再害怕了。它不过是编辑一个 TODO 列表。

你可以把提交压缩(squash)在一起、重新排序、重新编写提交信息、完全丢弃提交,或者就地编辑它们。它就是在文本编辑器里操作你的提交历史,而你就是那个文件的“神”。

场景: 你在实现一个功能时做了 6 次提交,其中三次是 “fix typo”(修正拼写错误)、“WIP”(进行中)和 “actually fix the thing I said I fixed”(实际上修复了我说过要修的东西)。你不想让这些出现在永久记录里。

# 交互式地 rebase 最近的 6 次提交
git rebase -i HEAD~6

编辑器打开后显示:

pick a1b2c3d add user authentication
pick d4e5f6g WIP: trying stuff
pick h7i8j9k fix typo in auth middleware
pick l0m1n2o actually implement auth middleware
pick p3q4r5s add auth tests
pick t6u7v8w fix test assertion

将其改为:

pick a1b2c3d add user authentication
squash d4e5f6g WIP: trying stuff
squash h7i8j9k fix typo in auth middleware
squash l0m1n2o actually implement auth middleware
pick p3q4r5s add auth tests
fixup t6u7v8w fix test assertion

保存并关闭。现在你拥有了一段干净、专业的历史。

  • squash 将提交合并到前一个提交,并允许你重新编写提交信息。
  • fixup 在不提示新信息的情况下合并提交。

5. git cherry-pick:从其他分支偷取

有时你只需要另一个分支上的单个提交。不是合并,也不是变基——只要同事在 develop 上推送的那个紧急修复,而你现在迫切需要在你的功能分支上使用它。

# 通过哈希值抓取特定提交
git cherry-pick a1b2c3d
# 需要多个提交?可以。
git cherry-pick a1b2c3d f4e5d6c
# 只挑选更改而不提交(仅将更改暂存)
git cherry-pick --no-commit a1b2c3d

实际会出现的场景: 生产环境出问题了。修复已经在 develop 分支中,但它被埋在 30 条其他尚未准备好上线的提交之下。你只需要这个修复,而不是那 30 条其他内容。

git checkout main
git cherry-pick d4e5f6a   # 只挑选热修复的提交
git push origin main

注意: Cherry‑pick 会创建一个提交,内容相同但哈希不同。如果以后合并源分支,Git 通常能智能处理,但有时会出现看似重复的冲突。这就是权衡所在——值得。

6. git log -S: 搜索整个历史

git log 本身很无聊。git log --oneline 稍微好一点。但 git log -S 就像带搜索栏的时光机。

-S 标志(称为 pickaxe)会在历史中每个 diff 的 内容 中搜索——而不是提交信息,而是实际的代码改动。它会找到添加或删除特定字符串的提交。

情景: 有人删除了 validatePayment() 函数。没人知道何时删除的,也没人知道为什么删除,git blame 也帮不上忙,因为自那以后文件已经重构了六次。

# 查找每个添加或删除 "validatePayment" 的提交
git log -S "validatePayment" --oneline

示例输出

f4e5d6c remove legacy payment validation
a1b2c3d refactor: extract payment validation
9z8y7x6 add payment validation to checkout
# 想看实际的 diff 吗?
git log -S "validatePayment" -p
# 使用正则表达式搜索
git log -G "validate.*Payment" --oneline
  • -S 查找出现次数发生变化的提交。
  • -G 查找字符串出现在 diff 中的提交(即使出现次数没有变化)。

对于大多数调查工作,-S 是你想要的。

没人提及的强大组合

git log --all --oneline --graph --decorate

这会在终端直接显示分支拓扑的可视化图。把它设为别名 git lg,你几乎不再需要 GUI Git 客户端(好吧,有时会用,但频率大大降低)。

7. git worktree:一次在两个地方

这个功能真的被低估了。git worktree 让你能够在不同目录中 同时 检出多个分支,所有目录共享同一个 .git 数据。再也不需要 stash, 再也不需要把仓库克隆两遍, 再也不需要为了切分支而提交半成品代码。

场景: 你正埋头在一个特性分支上。项目经理发来信息:“main 上有严重 bug,必须立刻修复”。你到处都有未暂存的实验代码,真的不想把这些东西全部 stash。

# 为热修复创建一个新的 worktree,检出 main
git worktree add ../hotfix-login main

此时你的目录结构如下:

/projects/myapp          → 你的特性分支(保持不变)
/projects/hotfix-login → main 分支,准备修复
cd ../hotfix-login
# 修复 bug,提交,推送。你的特性分支完全不受影响。

完成后,清理工作:

cd ../myapp
git worktree remove ../hotfix-login

这比 git stash 用于上下文切换要好得多。你的特性分支保持原样——脏文件、打开的编辑器标签页,全部不变。热修复则在一个完全独立的目录中进行。

我几乎每天在代码评审时也会用它。可以在单独的 worktree 中检出同事的分支,运行、调试,而自己的工作保持不受影响。彻底改变游戏规则。

实际的高手操作

这些命令都不是“高级”的。它们都写在文档里,已经存在多年。之所以让你看起来像个巫师,是因为大多数开发者从不去学习 addcommitpushpull 之外的东西,遇到合并冲突就慌忙搜索。

你今天不必全部记住。挑一个就行。下次遇到 Git 烂摊子时,尝试使用它,而不是直接删库重新克隆。这就是升级的方式:一次一次的 “哎呀” 时刻。

有哪条 Git 小技巧帮过你吗? 在评论里留下吧。我一直在寻找新的法术。 🧙‍♂️

0 浏览
Back to Blog

相关文章

阅读更多 »

使用 Git Alias 成为高手

《Use Git Alias To Become Pro》的封面图片:https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-up...