团队协作里,Git 最容易乱的地方,不是会不会 git add 和 git commit,而是分支开发一段时间以后,提交历史变成一串“fix”“update”“再改一下”。
这些提交在自己本地看问题不大,但一旦发 PR,review 的人就很难判断真正的改动意图。等合并到主干后,后续查问题、回滚、看 blame 也会变得很痛苦。
所以日常协作里有一个很实用的习惯:开发时可以小步提交,发 PR 前把提交历史整理干净。
这篇只讲最常用的一条线:新建分支、同步主干、用 rebase 整理提交、再推送发 PR。
每个任务先开独立分支
不要直接在主干上改功能。一个任务、一个修复、一次实验,最好都从主干拉出单独分支。
git switch main
git pull
git switch -c feature/login-rate-limit
独立分支的好处很直接:
- 改动范围清楚。
- 可以单独发 PR。
- 出问题时容易丢弃或重做。
- 多个任务不会混在一起。
分支名不需要花哨,但要能看出用途。比如:
feature/rss-reader
fix/nginx-proxy-pass
docs/wordpress-publish-flow
开发时可以小步提交
写代码时不必一开始就追求提交历史完美。小步提交反而更安全。
git status
git add .
git commit -m "add draft payload validation"
开发中的 commit 可以记录阶段性进度,比如:
- 先把接口打通。
- 再补参数校验。
- 再修测试。
- 再改文档。
这些提交对自己有用,但不一定都适合原样进入主干。PR 前整理,就是把“开发过程记录”收敛成“最终变更说明”。
经常和主干同步
分支开发时间越长,越容易和主干产生偏差。同步主干通常有两种方式:merge 和 rebase。
日常功能分支里,我更倾向于用 rebase 保持线性历史。
git fetch origin
git rebase origin/main
这表示:先拿到远程最新主干,再把当前分支的提交挪到最新主干后面。
如果中间有冲突,处理完冲突后:
git add .
git rebase --continue
如果发现方向错了,不想继续:
git rebase --abort
这几个命令要记牢。尤其是 --abort,它能让你在 rebase 处理乱了时先退回去,而不是越修越乱。
squash 是把多个提交合成一个
开发时可能有很多临时 commit:
add publish preview
fix typo
fix test
update docs
fix again
发 PR 前,可以用交互式 rebase 把它们整理成一个或几个更清楚的提交。
git rebase -i origin/main
打开编辑器后,常见会看到类似内容:
pick a1b2c3d add publish preview
pick b2c3d4e fix typo
pick c3d4e5f fix test
pick d4e5f6a update docs
你可以把后面几个 pick 改成 squash 或 fixup:
pick a1b2c3d add publish preview
fixup b2c3d4e fix typo
fixup c3d4e5f fix test
squash d4e5f6a update docs
大致区别:
pick:保留这个提交。reword:保留提交,但修改提交信息。squash:合并到前一个提交,并保留编辑提交信息的机会。fixup:合并到前一个提交,但丢弃当前提交信息。
如果只是修拼写、修测试、补漏,用 fixup 很舒服。真正需要补充说明的提交,再用 squash。
不要在共享分支上随便改历史
rebase 和 squash 都会改写提交历史。它们很适合整理自己的功能分支,但不适合在多人共用的主干或共享分支上随便使用。
可以先按这个规则记:
| 分支类型 | 是否适合 rebase / squash |
| — | — |
| 自己本地功能分支 | 适合 |
| 自己远程功能分支,别人没基于它开发 | 通常可以 |
| 多人共用开发分支 | 谨慎 |
| 主干分支 | 不要随便改历史 |
如果已经把整理后的分支推到远程,因为历史变了,普通 push 可能会被拒绝。比起直接 --force,更建议使用:
git push --force-with-lease origin feature/login-rate-limit
--force-with-lease 会先确认远程分支没有被别人推进过,能少一些误覆盖风险。
PR 前可以按这张清单检查
准备发 PR 前,建议快速过一遍:
- 当前分支只包含这个任务需要的改动。
- 已经 rebase 到最新主干。
- 临时 commit 已经 squash 或 fixup。
- 提交信息能说明“为什么改”和“改了什么”。
- 测试、lint、构建或项目自己的校验命令已经跑过。
- PR 描述里写清影响范围、验证结果和需要 reviewer 重点看的地方。
这比堆一串临时提交更尊重 review,也更方便后面维护。
commit 信息怎么写更有用
一个好的 commit 信息不需要很长,但要能回答两个问题:
- 这次改动解决什么问题?
- 改动边界在哪里?
比如:
fix publish flow featured image validation
比下面这种更有用:
update
如果改动比较大,可以用多行提交信息:
fix publish flow featured image validation
- reject publish when featured_media is empty
- add post-id scoped image verification
- keep audit reports for remote writes
后续查历史时,你会感谢当时多写的这几行。
小结
Git 协作可以先抓住这几条:
- 一个任务一个分支,不要在主干上直接开发。
- 开发中可以小步提交,PR 前再整理。
git fetch+git rebase origin/main用来同步最新主干。git rebase -i可以用squash和fixup合并临时提交。- 改写历史只适合自己的功能分支,不要随便动共享分支。
- 需要强推时优先用
--force-with-lease。
Git 的目标不是把命令背得很花,而是让团队能清楚地看到:这次改动为什么发生、改了哪些文件、出了问题该怎么回退。
参考链接
- Git 官方文档:<https://git-scm.com/docs>
- Git rebase 官方文档:<https://git-scm.com/docs/git-rebase>
- Thoughtbot Git Protocol:<https://github.com/thoughtbot/guides/tree/main/protocol/git>




