git 本身不执行测试,需通过 pre-push hook(本地)或 github actions(云端)实现:pre-push 在推送前校验主干分支并运行 npm test,github actions 则需精确配置 on.push.branches 和 runs-on: ubuntu-latest 保证环境一致。

push 时怎么让 Git 自己跑测试?
Git 本身不执行测试,它只管版本控制;真正干活的是 Git hooks(尤其是 pre-push 或 pre-commit),或者 CI/CD 工具(如 GitHub Actions、GitLab CI)。本地 push 触发测试,99% 的情况该用 pre-push hook,而不是幻想 Git “内置”自动测试能力。
常见错误是把测试脚本塞进 post-receive(服务端 hook),结果发现本地 push 没反应——因为 post-receive 只在远程仓库(比如你自己的服务器)上运行,而 GitHub/GitLab 等平台根本不允许用户自定义服务端 hook。
-
pre-push是唯一能在你敲完git push后、数据发出前执行的本地 hook,适合做快速校验 - 它不能替代 CI:不保证所有分支、所有环境都走同一套逻辑,且容易被
--no-verify绕过 - 脚本必须放在项目根目录的
.git/hooks/pre-push,并加可执行权限:chmod +x .git/hooks/pre-push
pre-push hook 怎么写才不失败?
很多 pre-push 脚本一跑就卡住或静默退出,根本原因是没处理好它的输入协议:Git 会按行传入 <local ref><local sha1><remote ref><remote sha1></remote></remote></local></local> 四个字段。直接用 npm test 或 pytest 是不行的,得先判断当前 push 是否涉及主干分支(比如 main)、是否修改了关键文件等。
一个安全的最小可用示例:
#!/bin/sh
# .git/hooks/pre-push
if git rev-parse --abbrev-ref HEAD | grep -qE '^(main|master|develop)$'; then
echo "Running tests before push to protected branch..."
npm test 2>/dev/null || { echo "❌ Tests failed. Push aborted."; exit 1; }
fi
- 必须以
#!/bin/sh开头,Windows 用户注意换行符是 LF,不是 CRLF - 不要依赖
node_modules/.bin的路径,npm test比./node_modules/.bin/jest更可靠 - 输出重定向
2>/dev/null不是为隐藏错误,而是避免 Git 把 stderr 当成推送失败——但最终仍要靠exit 1中断 push - 别在 hook 里调用
git push或改工作区,hook 运行期间 Git 锁着索引,会死锁
GitHub Actions 里怎么确保每次 push 都跑测试?
本地 hook 可被跳过,真要强约束就得靠 GitHub Actions。关键是把触发条件写对,否则 PR 提交不跑、定时任务乱跑、或者只在 main 分支跑漏了 feature 分支。
最稳妥的 .github/workflows/test.yml 写法:
on:
push:
branches: [main, develop]
paths-ignore:
- '**.md'
- 'docs/**'
pull_request:
branches: [main, develop]
-
push事件默认包含所有分支,不加branches就等于“每次 commit 都触发”,CI 资源很快耗尽 -
paths-ignore是性能关键:跳过文档变更能省下 30–60 秒,尤其当测试本身要装依赖时 - 别信“
on: [push, pull_request]”这种简写——它会让 PR 的 base 分支变更也触发,和直觉不符 - GitHub Actions 的
GITHUB_TOKEN默认有读写权限,但如果你用了私有 action 或需要部署密钥,得显式声明permissions
为什么测试通过了,线上还是出问题?
因为本地 pre-push 和 GitHub Actions 测试环境不一致:Node 版本不同、NODE_ENV 默认是 development、没有 mock 数据库、甚至没装 libpq 这类系统依赖。
- CI 脚本里别用
npm ci就完事,得加runs-on: ubuntu-latest显式声明环境,避免 macOS 下开发、Linux 下 CI 导致路径或权限差异 - 本地 hook 里跑
npm test,CI 里却跑npm run test:ci,两个命令实际执行的脚本不同,等于测了个寂寞 - 数据库测试如果用
sqlite本地跑得飞快,CI 里换成postgres却没初始化 schema,测试就挂——得在jobs.*.steps里补psql -c 'CREATE DATABASE test;' - 最隐蔽的坑:Git 默认不提交
.env,但本地测试靠它连 mock API;CI 里没等价配置,所有 HTTP 请求超时,测试却显示“passed”(因为用了jest.useFakeTimers()却忘了jest.runAllTimers())
环境一致性不是个“优化项”,是自动化测试能信的前提。少一个 os: ubuntu-latest,少一行 env: 声明,就可能让一次看似成功的 push 埋下线上故障。











