一个人写代码,Git 也应该有自己的规矩
发布 修订 分类 engineering
当前浏览器未执行 JavaScript,下面是本篇的 Markdown 原文,内容一字未改。
团队里有分支策略,个人项目常常就没有规矩——于是历史里堆满 `update`、`fix`、`fix2`,半年后自己都看不懂。
<!-- more -->
## 规矩一:一次提交只做一件事
提交信息写清楚「做了什么」和「为什么」,不写「改了哪个文件」:
```text
feat(search): 中文按二元组分词,提升两字查询命中率
fix(toc): 修正重复标题锚点编号从 0 开始的问题
perf(bg): 页面不可见时暂停 requestAnimationFrame
refactor(md): 把行内解析拆出独立的 token 表
```
好处是 `git log --oneline` 本身就是一份变更说明书。
## 规矩二:每步都能回退
我给自己定的线是:**任何一次提交,单独 checkout 出来都能跑**。所以:
- 不在一个提交里同时做重构和改功能(改坏了分不清是哪边的问题)。
- 大改动先加「空实现 + 开关」,再填内容。
- 实验性想法先开分支,验证失败直接删,不污染主线。
## 规矩三:本地历史可以脏,推上去之前要干净
我大量使用 `--amend` 和交互式 rebase:
```bash
git add -p # 按块暂存,只提交相关内容
git commit --amend --no-edit # 补进上一次提交
git rebase -i HEAD~5 # 合并琐碎提交、改信息
git stash push -m 'wip search' # 临时收工
```
`git add -p` 是我用得最多的一个命令,它让「这次提交只做一件事」从愿望变成可行。
## 我的日常循环
```bash
git switch -c feat/search-bigram # 开一条小分支
# ... 写代码 ...
git add -p && git commit -m 'feat(search): 二元组分词'
git fetch --prune && git rebase origin/main
node scripts/build.mjs # 推送前跑一遍生成与自测
git push -u origin HEAD
```
## 三个救命命令
| 场景 | 命令 |
| --- | --- |
| 改错了但还没提交 | `git restore <file>` / `git checkout -p` |
| 提交错了但还没推 | `git reset --soft HEAD~1` |
| 已经推错了 | `git revert <sha>`(别用 force push 抹历史) |
| 找是谁改了这行 | `git log -S 'low[v]' --oneline -- assets/js/app.js?v=ef616b19` |
> [!WARN]
> 对已推送的公共分支做 `push --force` 是把自己的便利转嫁给别人。一个人写也要养成 revert 的习惯,因为「以后的你」也是别人。