3.3 dsh-pre-push-checks:推送前的最后一道关
它是什么
dsh-pre-push-checks 的官方描述:在推送、强推、标记为待评审或合并之前使用。
约 11283 字节,覆盖四个动作前的检查。这四个动作有个共同点:一旦做了,就很难不动声色地收回。 推送会把代码送到远端,强推会改写他人可能已经拉取的历史,标记待评审等于邀请别人为你的代码花时间,合并则直接进入主干。技能把检查点卡在这四个动作之前,本质上是在保护“还能安静改错”的那个窗口。
为什么卡在 push 之前
研发流程里有个经验规律:问题发现得越晚,修复成本越高。
| 阶段 | 发现问题 | 修复成本 |
|---|---|---|
| 本地编辑 | 自己改 | 分钟级 |
| commit 后 | amend 或新 commit | 十分钟级 |
| push 后 | 强推,可能影响他人 | 小时级 + 协作成本 |
| 合并后 | 需要 revert + 回归 | 天级 |
注意这张表里最陡的一跳是从“本地”到“push 后”:成本从十分钟级跳到小时级,多出来的不是修复时间,是协作成本——你要通知所有人重新拉取,别人基于旧历史的提交要收拾。第二跳是合并后,修复动作从“改代码”变成“回滚 + 回归 + 重新发版”,牵动面再上一个量级。
dsh-pre-push-checks 存在的意义就是把检查点尽量往前挪,在“还很容易改”的时刻把问题拦下。它不替代任何流程,只是保证你在按下一个难以撤回的按钮之前,已经被同一份清单问过一遍。
它一般检查什么
按工程惯例与技能体量推断,这类推送前检查通常覆盖六个类别:
| 类别 | 典型项 |
|---|---|
| 构建 | 类型检查、编译、打包是否通过 |
| 测试 | 相关测试是否跑过、是否全绿 |
| 格式 | 代码格式、导入顺序、无用导入 |
| 提交卫生 | commit message 是否清晰、是否混入无关改动 |
| 分支状态 | 是否落后于上游、是否需要 rebase |
| 副作用 | 是否带了调试代码、console 输出、临时文件 |
其中“提交卫生”和“副作用”两类最容易被忽略,也最值得自动化:一个混着无关改动的 commit、一行忘记删的 console.log,靠人是查不出来的,靠清单可以。
dsh 版本还会包含它自己的钩子要求(例如特定的 lint 规则、快照测试)。
一份十项以内的推送前清单示例
和评审清单一样,这个技能的关键在于“短而真查”。下面是一份可直接改造的起点:
## 推送前检查
- [ ] 相关测试通过(只跑受影响模块)
- [ ] 类型检查 / 编译通过
- [ ] 无调试残留(console、debugger、临时开关)
- [ ] 无混入的无关改动
- [ ] commit message 能说清“为什么改”
- [ ] 分支已 rebase 到最新上游
- [ ] 公开 API 变更已写迁移说明
- [ ] 大文件 / 密钥没有进暂存区
最后一条值得单说:密钥泄露是推送前最容易酿成大祸、却最容易被忽略的项。一旦 push 到远端,即使立刻删掉,历史里也留下了。把“密钥 / 大文件未进暂存区”写进清单,比事后轮换密钥便宜一万倍。
与 CI 的分工
常见误解是“有 CI 就行了”。实际上两者定位不同:
| pre-push 技能 | CI | |
|---|---|---|
| 速度 | 快(可只跑相关部分) | 慢(全量) |
| 时机 | 推送前,可拦下 | 推送后,只能报错 |
| 反馈 | 交互式,可追问 | 日志,需自行翻 |
| 定位 | 省一次失败的 CI | 守门,不可绕过 |
展开说:CI 的价值在于不可绕过——它守在远端,本地手段跳不过它;pre-push 技能的价值在于可对话——检查失败了你可以当场问“这个失败能不能放过、为什么”,而不是对着日志干瞪眼。一个在门里,一个在门外,少了哪个都漏。
正确姿势是关键项本地跑,全量交给 CI。把所有检查都堆在 CI,结果就是每个人每天都在等一次注定失败的构建。
技能 vs 钩子(hook)
有人会问:这不就是 git hook 吗?区别在三点:
| 维度 | pre-push 技能 | git hook |
|---|---|---|
| 修改方式 | 改 Markdown 即可 | 改脚本文件,需分发 |
| 可对话性 | 失败可追问原因 | 脚本直接拒绝,信息有限 |
| 跨机一致性 | 随仓库走,所有人一致 | 依赖每人本地装了钩子 |
钩子的优势是“无法绕过”,劣势是僵硬、难维护、换了机器就丢。技能的优势是灵活、可读、随仓库版本化;劣势是它依赖人或模型主动调用,理论上能被跳过。实务上两者可以共存:用钩子兜底硬性红线(如密钥扫描),用技能做可对话的软性检查。
改造三要点
- 换命令。 把 dsh 专属命令换成你项目的(
pnpm test/npm run lint等),这是最低限度的改造,不改就用不了。 - 清单控制在十条以内。 超过十条没人会认真看——包括模型。十条以内的清单,每条都是真检查;五十条的清单等于没有清单。
- 明确哪些可放过。 提前定义“哪些失败必须拦住,哪些可以放过并说明理由”。没有这条,技能要么太松形同虚设,要么太紧被大家绕开——被绕开的检查比没有检查更糟,因为它制造了“已经查过了”的错觉。
单人项目怎么用
没有团队也值得装。单人项目的“评审人”是未来的自己:三个月后回看这个仓库,你最希望当时的自己提前拦下什么?把那个清单写进去。常见的单人痛点——忘了跑测试就推、把本地配置文件推上去、commit message 全写成“update”——都能被一份十项清单兜住。
你要不要装
| 你的情况 | 建议 |
|---|---|
| 有 CI 但本地常忘跑 | 强烈建议,把 CI 的关键项搬到本地 |
| 单人项目 | 建议,替代手工记忆 |
| 已有完善的 pre-commit 钩子 | 可选,技能比钩子更灵活但更慢 |
小结
dsh-pre-push-checks卡在推送、强推、待评审、合并四个动作之前,约 11283 字节。- 核心思想:把检查点前移到修复成本最低的时刻。
- 与 CI 互补而非替代:关键项本地,全量 CI。
- 改造时清单控制在十条以内,并明确哪些失败可放过。
