很长一段时间里,我以为 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 出问题,因为他们清楚怎么恢复。
而这种底气,基本都来自三件事:
- 学会查看改动(
git diff) - 学会撤销错误(
git stash/git restore) - 学会安全恢复(
git reflog)
如果只能记住三个命令,就记这三个——它们能帮你省下无数个抓狂的下午。
写在最后
大多数人把 Git 当成一个"备份工具"在用。
真正用顺手的人,是把它当成一台时间机器——可以随时回看、随时纠错、随时安心地往前走。
希望这篇整理,能帮你少走一点弯路。