很长一段时间里,我以为 Git 就是三句话的事:

git add .
git commit -m "update"
git push

日复一日,年复一年,我一直这么用,从没出过什么大问题——直到有一次,我亲眼看着一位资深同事,在没有打开浏览器查任何资料的情况下,淡定地恢复了被删掉的提交,理清了半年的混乱历史,还撤销了一次失败的合并。

而我那段时间正在搜索引擎里敲:"如何撤销上一次提交但保留修改"。

那一刻我突然意识到:大多数开发者对 Git 的了解,只够"活下去";真正厉害的人,是理解 Git 到底是怎么运作的。

于是我把自己后来才搞懂、却恨不得早点知道的那些 Git 习惯和技巧,整理成了这篇文章。


先搞懂一件事:Git 不是备份工具,是时间机器

很多人(包括过去的我)把 Git 当成一个"存档系统":改代码 → 提交 → 推送,仅此而已。

但其实 Git 更像是你项目从诞生到现在的完整时间线。一旦想明白这一点,很多命令瞬间就不再陌生、不再可怕了——因为它们本质上都是在"时间线"上做事:查看某一刻、回到某一刻、合并几条时间线。


14 个让我"开窍"的 Git 习惯

1. git status:被严重低估的第一命令

听起来很基础,但我多年都懒得用。现在我养成了习惯:提交前、切分支前、rebase 前,都先跑一遍。

git status

绝大多数 Git 翻车现场,根源都是你没搞清楚当前到底处于什么状态。我曾经因为漏了这一步,把 .env 文件、调试日志、没写完的代码甚至截图一起提交上去。

一个命令,两秒钟,省下来的是几个小时的善后。

2. git diff:让你提交前不再"社死"

提交之前,先看一眼到底改了什么:

git diff

我靠它拦下过差点泄露的 API Key、漏改的引用路径、忘了删的 console.log

更常用的是这一条,只看已经 add 进去的内容:

git diff --staged

3. 别再无脑 git add .

git add . 会把所有改动一股脑全部加进去。但很多时候,你只想提交某一个具体的修改,而不是顺手改的另外三四处。

试试这个:

git add -p

它会让你一块一块地审查改动,自己决定加还是不加。我曾经在同一个文件里同时改了登录逻辑、调整了 UI、顺手做了点清理,靠 git add -p 干净地只提交了登录修复那部分。

多花的 30 秒,换来的是清爽的提交记录和未来排查问题时的轻松。

4. git bisect:让你看起来像个魔法师

这个命令我多年不敢碰,觉得太"高级"。

但场景其实很常见:线上出问题了,三周前还是好的,中间隔着 80 个提交,完全不知道是哪一个引入的 bug。

git bisect start
git bisect bad          # 当前是坏的
git bisect good v2.3.1  # 这个版本是好的

Git 会自动跳到好坏之间正中间的那个提交,你测试一下、告诉它好还是坏,它再继续折半查找。重复大约 7 次,80 个提交就能锁定到 1 个。

我用它排查过一个挂了一个月的老 bug,11 分钟就找到了那个"罪魁祸首"——提交信息写的是"小幅清理"。当然,不是。

5. git stash:救命的临时收纳箱

场景:你正在写一个功能写到一半,突然冒出一个紧急 bug,必须立刻切分支处理。

以前的我会陷入手足无措。现在:

git stash       # 把当前改动先收起来
# 切分支,修 bug,提交
git stash pop   # 把改动原样取回来

分支本质上就是一个个独立的"沙盒环境",git stash 就是你在沙盒之间切换时的那个安全暂停键。

6. git log 终于让我看懂了项目的全貌

很长一段时间,Git 历史在我眼里就是一堆噪音。后来我开始用:

git log --oneline --graph --decorate

整个项目的时间线、分支、合并轨迹一下子全部可视化了。我立刻给它配了个别名:

alias gl='git log --oneline --graph --decorate'

现在 gl 是我每天用得最多的命令之一。

7. 分支很便宜,多用就是了

直接在 main 上改代码是个大坑,我踩了太久。现在几乎所有事都先开分支:

git switch -c fix-login-bug

这之后我才真正敢放手实验、大胆重构、尝试风险更高的修复方案——因为我知道,弄坏分支没关系,弄坏 main 才要命。

8. git restore:关键时刻的"撤销键"

不小心改错了文件,不用手动一行一行改回去:

git restore app.js

瞬间恢复到最后一次提交的状态。这个命令我真希望入职第一个月就学会。

9. git worktree:被严重低估的多任务神器

以前切任务时,我的流程是:stash 改动 → 切分支 → 处理紧急修复 → 切回来 → pop 改动 → 祈祷不要冲突。

git worktree 提供了另一种思路:

git worktree add ../hotfix-branch hotfix/login-timeout

它会把这个分支单独检出到另一个目录,你当前的工作分支完全不受影响。cd 过去修完 bug、推送,再 cd 回来接着干活——不用 stash,不用切换,不用担心"我刚才到底改到哪了"。

说实话,我还没完全养成习惯用它,但对于一小时以上的中断任务,它比 stash 大法干净太多了。

10. git reflog:真正的"时间旅行"

这是最容易让人觉得资深开发者"开了天眼"的命令。

我曾经以为一次 rebase 操作彻底丢掉了某些提交——其实 Git 几乎什么都记得:

git reflog

它会显示你最近的所有操作,包括你以为已经删掉的提交、丢掉的分支、reset 掉的状态。恢复只需要一条命令:

git checkout <commit-id>

reflog 的记录大约能保留 90 天。在你认定某个东西"永远丢了"之前,先看一眼这里。

11. 提交信息,是写给人看的

以前的我:

git commit -m "fix"

未来的我看到这种提交信息,想打过去的自己。现在我会写:

git commit -m "修复 auth middleware 中的 token 刷新问题"

好的提交信息不是为 Git 而写的,是为人写的——通常是半年后那个深夜对着代码一头雾水的"未来的你"。

12. 交互式 rebase:让历史变干净

git rebase 这个词听起来就让人害怕,我躲了它好多年。其实它能做的事很简单:

git rebase -i HEAD~5

提 PR 之前,把零散的提交合并、重命名、重新排序,变成一条清晰、有意义的记录。比起一堆"fix"、"再修一下"、"小调整"、"终于修好了",团队成员看到一条干净的提交,体感完全不同。

13. git blame:代码考古的乐趣

名字听起来吓人,其实很实用:

git blame app.js

它会告诉你每一行代码是谁改的、什么时候改的、在哪个提交里改的。我靠它追溯过线上 bug 的源头,搞懂过一些"为什么这里要这样写"的历史遗留逻辑。找到答案的那一刻,莫名有种破案的满足感。

14. 别小看别名,它能省下大量"摩擦力"

打长命令打烦了之后,我加了一组别名:

alias gs='git status'
alias ga='git add'
alias gc='git commit -m'
alias gp='git push'
alias gl='git log --oneline --graph --decorate'

单次也许只省 3 秒,但一天用上 50 次,几个月下来差别就很明显了。更重要的是:摩擦力越低,你才越愿意把该做的检查动作真的做出来。


真正的差距,不在记了多少命令

这么多年下来,我现在的理解是:决定一个人 Git 用得好不好的,不是背了多少条命令,而是出问题时还能不能稳住。

那些让人觉得很厉害的开发者,往往不是打字更快,也没有什么花式工作流——他们只是真的不怕 Git 出问题,因为他们清楚怎么恢复。

而这种底气,基本都来自三件事:

  1. 学会查看改动(git diff
  2. 学会撤销错误(git stash / git restore
  3. 学会安全恢复(git reflog

如果只能记住三个命令,就记这三个——它们能帮你省下无数个抓狂的下午。


写在最后

大多数人把 Git 当成一个"备份工具"在用。

真正用顺手的人,是把它当成一台时间机器——可以随时回看、随时纠错、随时安心地往前走。

希望这篇整理,能帮你少走一点弯路。