我对 CI/CD 的理解是从配一条能稳定跑通的流水线开始的:先让它把构建、检查、部署串起来,后来才琢磨缓存、灰度这些细节。 延伸方向: Martin Fowler 在其经典文章《Continuous Integration》中定义了 CI 的三大原则:频繁集成、自动化构建、立即修复失败构建。现代前端 CI/CD 在此基础上叠加了 Monorepo 增量构建(Turborepo)、远程缓存、AI 驱动的选择性测试等新范式。[4]
Q1: Git 提交规范有哪些?
1
没有规范的灾难
每个人的 commit message 都不一样—“fix bug”、“update”、“改了一下”、“123”。三个月后没人知道这个提交改了什么、为什么改。当需要回滚某个功能或者排查线上问题时,面对一堆毫无意义的提交记录,工程师将彻底迷失方向。
2
Conventional Commits 规范
Angular 团队提出的提交规范:
<type>(<scope>): <subject>。type 限定为 feat/fix/docs/style/refactor/test/chore 等,scope 可选,subject 用祈使句。这套规范的核心价值在于让 commit message 具备机器可解析的结构化语义。3
自动生成 CHANGELOG
当提交信息遵循 Conventional Commits 规范后,工具(如 standard-version 或 semantic-release)可以自动从 commit 历史中提取 feat 和 fix 类型的提交,生成结构化的 CHANGELOG 文档,并根据语义化版本规则自动决定版本号的升级策略。
4
工具链自动化校验
用 commitlint + husky + lint-staged 在 git commit 时自动校验提交信息格式,不合规的提交直接被 Git Hook 拒绝。lint-staged 还会对暂存区的文件运行 ESLint/Prettier,确保代码风格和质量在提交前就达标。
5
CI/CD 流水线的集成
在 CI/CD 流水线中,可以利用 Conventional Commits 的语义信息自动触发不同的部署流程:feat 类型的提交触发功能分支的预览环境部署,fix 类型触发 hotfix 流程,chore 类型则跳过部署只运行测试。
Git 提交规范让 commit message 从”自言自语”变成”团队可追溯的变更日志”。
🚫 没有提交规范
每个人的 commit message 都不一样—“fix bug”、“update”、“改了一下”。三个月后没人知道这个提交改了什么。就像一本没有目录的书,你永远找不到想看的章节。
✅ Conventional Commits
统一格式
<type>(<scope>): <subject>,自动生成 CHANGELOG,支持语义化版本发布。就像一本有清晰目录的书,每章每节都有明确的标题。Q2: CI/CD 是什么?怎么配置?
CI(持续集成)和 CD(持续部署)是现代前端工程的核心实践。CI 是”每次提交都自动验证”,CD 是”验证通过就自动部署”。核心价值不是自动化本身,而是缩短从代码提交到上线的反馈循环。
GitHub Actions 详解
GitHub Actions 是最流行的 CI/CD 工具,核心概念:前端 CI/CD 的完整流程
代码校验工具链
Q3: ESLint、Prettier、TypeScript 的关系?
真正需要弄清的
上面那张工具对比表,背下来的人很多。但实际往往会追问一层:ESLint、Prettier、TypeScript 三者的执行顺序是什么?如果 ESLint 报了一个格式错误,Prettier 又把格式改了,谁赢? 执行顺序是:Prettier 格式化 → TypeScript 类型检查 → ESLint 质量检查。在保存文件时,编辑器先跑 Prettier 格式化代码,再跑 ESLint 检查质量。在 CI 中,通常是npm run lint(ESLint)和 npm run type-check(TypeScript)并行执行。关于冲突,Prettier 赢—因为 eslint-config-prettier 放在 ESLint 配置的最后,关闭了所有与 Prettier 冲突的格式规则。所以 ESLint 不会报格式错误,格式完全交给 Prettier 管。这也是为什么两者不会冲突—不是”谁赢”的问题,而是从架构上就把职责分开了。
自动化测试策略
前端自动化测试分为三层:自动化部署策略
自动化部署有三种策略:Monorepo 场景下的 CI/CD 优化
在 Monorepo 项目中,CI/CD 的核心挑战是如何只构建/测试被修改的包,而不是全量执行。Turborepo 通过依赖图分析和远程缓存解决这个问题:Q4: Git 核心命令详解
📌 Git 专题: Q4-Q7 聚焦 Git 工程实践,涵盖核心命令、高级操作、工作流和高频面试题。虽然不属于 CI/CD 范畴,但 Git 是工程规范的基础设施,与 CI/CD 流水线紧密配合。Git 命令看似简单,但每组命令之间的区别往往是面试高频考点。
1
git pull vs git fetch
git fetch 只从远程拉取最新数据到本地的远程追踪分支(如 origin/main),不会自动合并到当前分支。git pull 等价于 git fetch + git merge(或 git fetch + git rebase,取决于配置),会自动合并。2
git merge vs git rebase
git merge 保留完整的分支历史,会生成一个合并提交(merge commit)。git rebase 把当前分支的提交”搬到”目标分支的最新位置,历史更线性、更干净,但会改写提交历史。3
git cherry-pick 使用场景
git cherry-pick 把某个特定提交从一个分支”摘”到当前分支。常见场景:hotfix 需要从 main 分支摘到 release 分支,或者从 feature 分支摘一个 bugfix 到 main。4
git stash 使用场景
git stash 把当前工作区和暂存区的修改临时保存,让工作区恢复干净。常见场景:正在开发 feature,突然需要切到其他分支修 bug。5
git reset vs git revert
git reset 移动 HEAD 指针,丢弃提交历史(危险)。git revert 创建一个新提交来撤销某个提交的内容(安全)。两者都能”撤销”提交,但 revert 不改写历史,适合已推送的提交。revert,本地未推送的提交可以用 reset。git fetch 只拉不并,git pull 拉并合一;merge 保历史,rebase 要干净;cherry-pick 摘单个,stash 暂存忙;reset 丢历史,revert 安全撤。
🚫 git reset --hard 的灾难
正在 feature 分支开发,老板说”切到 main 修个 bug”。你
git reset --hard HEAD~5 试图回到 5 个提交之前,结果 5 个提交的代码全丢了。如果没有 reflog,这些代码就永远消失了。✅ git stash 的正确姿势
git stash push -m "feature: 用户模块" → git checkout main → 修 bug → git checkout feature → git stash pop。stash 就像一个临时抽屉,把桌上的文件暂存进去,回来时再拿出来,桌面恢复原样。Q5: Git 高级操作
git tag 打标签
标签(Tag)用于标记发布版本,是一个指向特定提交的不可变引用。git release 发布流程
标准的 Git 发布流程:自动更改版本号(semantic-release)
semantic-release 根据 Conventional Commits 的提交信息,自动决定版本号升级策略并发布:
git bisect 调试
git bisect 用二分法快速定位哪个提交引入了 bug:
git blame 追溯
git blame 查看文件每一行最后修改的提交和作者:
tag 标记版本,release 管发布,semantic-release 自动化版本号,bisect 二分法定位 bug,blame 追溯每一行的作者。
Q6: Git 工作流对比
选择哪种 Git 工作流,取决于团队规模、发版频率和项目复杂度。Git Flow
Git Flow 有 5 种分支,适合发版周期长(如每月发版)的项目:
缺点: 分支多、合并冲突多、CI 维护成本高。对于需要持续部署的项目,Git Flow 过于笨重。
GitHub Flow
GitHub Flow 只有main 和 feature 分支,适合持续部署的项目:
- 从
main创建 feature 分支 - 在 feature 分支开发并提交
- 创建 Pull Request
- Code Review + CI 通过后合并到
main - 合并后自动部署
GitLab Flow
GitLab Flow 在 GitHub Flow 的基础上增加了环境分支:main分支是开发主分支pre-production分支是预发布环境production分支是生产环境- 代码从
main→pre-production→production逐级合并
Trunk Based Development
主干开发,只有main 和短期 feature 分支(不超过 2 天)。Google 等大型互联网公司普遍使用:
- feature 分支生命周期极短(不超过 2 天)
- 频繁合并到 main,减少合并冲突
- 配合 Feature Flag 控制未完成功能的可见性
- 需要强大的 CI/CD 和测试覆盖来保障质量
Git Flow 适合月度发版,GitHub Flow 简单易用,GitLab Flow 多环境逐级发布,Trunk-Based 是大厂标配——选哪种取决于发版频率和团队规模。
Q7: 高频面试题
git pull —rebase 和 git pull 有什么区别?
git pull 默认执行 git fetch + git merge,会产生一个合并提交(merge commit),历史分叉。git pull --rebase 执行 git fetch + git rebase,把本地提交”搬到”远程最新提交之后,历史更线性。
git config --global pull.rebase true,保持历史干净。
git stash 怎么用?有哪些常用命令?
git cherry-pick 和 git revert 有什么区别?
两者都能”撤销”或”搬运”提交,但机制完全不同:git reset —soft/—mixed/—hard 有什么区别?
三种模式的区别在于重置的范围:怎么撤销一个已经 push 的提交?
分两种情况: 情况 1: 只撤销最近一次 push 的提交🔍 底层源码:commitlint 是怎么工作的?
commitlint 是怎么校验 commit message 的?
commitlint 通过 Git 的 commit-msg hook 触发(详见 commitlint 源码)。当开发者执行 git commit -m "xxx" 时,Git 会调用 .husky/commit-msg 脚本,该脚本调用 commitlint 读取 commit message,用正则表达式校验是否符合 Conventional Commits 规范。不合规的提交会被拒绝(exit code 1)。
十、及格回答 vs 满分回答
问题:“你们团队的 Git 工作流是怎样的?”
及格回答(60-70分):“我们用 Git Flow,有 main、develop、feature 分支。提交信息用 Conventional Commits 规范。”问题出在:知道规范但不理解落地。 满分回答(90-100分):
我们团队的 Git 工作流基于Trunk-Based Development(主干开发),而不是 Git Flow。核心分支只有main和短期的feature/*分支,feature 分支通常不超过 2 天就合并回 main。[1]
代码质量通过CI 流水线保障。每次 push 或 PR 都会触发 GitHub Actions,依次执行 ESLint 检查、TypeScript 类型检查、单元测试、构建检查。任何一个步骤失败,PR 不允许合并。提交信息用 Conventional Commits 规范,通过 commitlint + husky 在本地校验。[2]
部署通过CD 流水线自动化。main 分支合并后自动构建并部署到 CDN。我们保留最近 3 个版本的构建产物,如果线上发现问题,可以一键回滚到上一个版本。部署完成后自动发送飞书通知到团队群。[3]
实际踩坑:CI 太慢(超过 5 分钟)会导致开发者跳过检查。我们的优化方案是:缓存 node_modules、并行执行 ESLint 和测试、用 lint-staged 只检查改动的文件。如果是 Monorepo 项目,还会用 Turborepo 的 --filter 只处理变更的包,配合远程缓存把 CI 时间从 10 分钟压到 1-2 分钟。[4]
常见追问
ESLint 和 Prettier 会冲突吗?怎么解决?
ESLint 和 Prettier 会冲突吗?怎么解决?
答题要点: 两者都管代码格式,会冲突。用 eslint-config-prettier 关闭 ESLint 的格式规则。高分回答:
“ESLint 既有’代码质量’规则(如 no-unused-vars),也有’代码格式’规则(如 indent)。Prettier 也管’代码格式’。两者会冲突。解决方案是用 ”
eslint-config-prettier 关闭 ESLint 中所有与 Prettier 冲突的格式规则,让 ESLint 只管质量,Prettier 只管格式。Git Flow 和 Trunk-Based Development 怎么选?
Git Flow 和 Trunk-Based Development 怎么选?
答题要点: Git Flow 适合发版周期长的项目,Trunk-Based 适合持续部署的项目。高分回答:
“Git Flow 有 main、develop、feature、release、hotfix 五种分支,适合发版周期长(如每月发版)的项目。但分支多、合并冲突多、CI 维护成本高。Trunk-Based Development 只有 main 和短期 feature 分支,适合持续部署(每天多次发版)的项目。feature 分支不超过 2 天就合并,减少合并冲突。Google 等公司普遍用 Trunk-Based Development。”
🔥 CI 太慢怎么办?
🔥 CI 太慢怎么办?
答题要点: 从缓存、并行、增量三个维度优化。高分回答:
“CI 太慢(超过 5 分钟)会导致开发者跳过检查。优化方案:
- 缓存:缓存 node_modules(用 actions/cache),避免每次 npm install。
- 并行:ESLint、TypeScript、测试并行执行,不要串行。
- 增量:用 Turborepo 或 lint-staged 只检查改动的文件/包,不要全量检查。
- 构建缓存:Turborepo 的 remote cache 可以跨 CI 复用构建产物。 优化后 CI 时间从 10 分钟降到 1-2 分钟。”
GitHub Actions 的核心概念是什么?
GitHub Actions 的核心概念是什么?
答题要点: 说出 workflow、job、step、action 四个核心概念。高分回答:
“GitHub Actions 有四个核心概念:
- Workflow:一个自动化流程,由
.github/workflows/*.yml文件定义。可以有多个 workflow(如 CI、CD、Release)。 - Job:workflow 中的一个任务,运行在独立的虚拟机上。多个 job 可以并行执行。
- Step:job 中的一个步骤,可以是 shell 命令或 action。
- Action:可复用的步骤单元,如
actions/checkout@v4(检出代码)、actions/setup-node@v4(安装 Node.js)。
怎么配置 GitHub Actions 的缓存?
怎么配置 GitHub Actions 的缓存?
答题要点: 说出缓存的配置方式和失效策略。高分回答:
“GitHub Actions 的缓存通过 缓存失效策略:
actions/cache 配置:- key 变更:package-lock.json 变更时,生成新的 key,旧缓存失效
- restore-keys:如果精确匹配失败,用前缀匹配找最近的缓存
- 缓存过期:GitHub 自动清理 7 天未使用的缓存
怎么配置自动化部署?
怎么配置自动化部署?
答题要点: 说出 CD 流水线的配置方式和部署策略。高分回答:
“GitHub Actions 的自动化部署配置:部署策略:
- GitHub Pages:适合静态网站,免费但功能有限
- Vercel / Netlify:适合前端项目,自动预览 PR
- 自建服务器:用 SSH 部署,灵活但需要维护
- 云服务:阿里云 OSS、腾讯云 COS,适合国内访问”
怎么配置自动化测试?
怎么配置自动化测试?
答题要点: 说出测试的配置方式和覆盖率报告。高分回答:
“GitHub Actions 的自动化测试配置:测试策略:
- 单元测试:每次 push 都运行,确保基础功能正常
- 集成测试:PR 时运行,确保组件交互正常
- 端到端测试:main 分支合并后运行,确保完整流程正常
- 覆盖率报告:用 Codecov 生成覆盖率报告,PR 中显示覆盖率变化”
git pull --rebase 和 git pull 有什么区别?
git pull --rebase 和 git pull 有什么区别?
答题要点: 区别在于 merge vs rebase,历史是否线性。高分回答:
“建议在团队中配置
git pull 默认执行 git fetch + git merge,会产生合并提交(merge commit),历史分叉。git pull --rebase 执行 git fetch + git rebase,把本地提交’搬到’远程最新提交之后,历史更线性。git config --global pull.rebase true,保持历史干净。”git stash 怎么用?有哪些常用命令?
git stash 怎么用?有哪些常用命令?
答题要点: 说出 stash 的核心场景和常用命令。高分回答:
“
git stash 把当前工作区和暂存区的修改临时保存,让工作区恢复干净。常见场景:正在开发 feature,突然需要切到其他分支修 bug。apply 和 pop 的区别:apply 恢复后保留 stash 记录,pop 恢复后删除记录。如果恢复时有冲突,用 apply 更安全——stash 记录还在,可以反复尝试。”git cherry-pick 和 git revert 有什么区别?
git cherry-pick 和 git revert 有什么区别?
答题要点: 两者都能”撤销”或”搬运”,但机制不同。高分回答:
“核心区别:
cherry-pick 是把某个提交从一个分支’摘’到当前分支,revert 是创建一个新提交来撤销某个提交的内容。cherry-pick 是复制提交内容,revert 是生成’反向’提交。两者都不改写历史,都是安全操作。”git reset --soft/--mixed/--hard 有什么区别?
git reset --soft/--mixed/--hard 有什么区别?
答题要点: 三种模式的区别在于重置的范围。高分回答:
“已经 push 的提交不要用
--soft 只移动 HEAD,暂存区和工作区不变(适合合并多个提交)。--mixed 移动 HEAD 并重置暂存区,工作区不变(默认模式,适合重新选择文件)。--hard 移动 HEAD 并重置暂存区和工作区(危险,彻底丢弃修改)。reset,用 revert 更安全。”怎么撤销一个已经 push 的提交?
怎么撤销一个已经 push 的提交?
答题要点: 分情况讨论,推荐 revert,慎用 force push。高分回答:
“分两种情况:
- 安全撤销(推荐):用
git revert生成一个’反向’提交
- 强制回退(危险,需团队协商):用
git reset+git push --force-with-lease
--force-with-lease 比 --force 更安全——它会在远程有新提交时拒绝推送,避免覆盖他人的工作。”🔥 git bisect 怎么用?什么场景适合?
🔥 git bisect 怎么用?什么场景适合?
答题要点: 用二分法快速定位引入 bug 的提交。高分回答:
“适合场景:线上出了 bug,知道某个版本没有 bug,想快速定位是哪个提交引入的。二分法只需 log2(n) 次验证,比手动
git bisect 用二分法快速定位哪个提交引入了 bug。当项目有几百个提交,手动排查太慢时,bisect 只需要 log2(n) 次就能找到。git log 逐个版本排查高效得多。”git tag 和 semantic-release 怎么配合?
git tag 和 semantic-release 怎么配合?
答题要点: tag 标记版本,semantic-release 自动化版本号。高分回答:
“在 CI/CD 中集成
git tag 用于标记发布版本(如 v1.0.0),semantic-release 根据 Conventional Commits 的提交信息自动决定版本号升级策略。semantic-release,合并 PR 后自动打 tag、发 npm 包、生成 CHANGELOG,完全不需要手动管理版本号。”Git 工作流怎么选?Git Flow vs Trunk-Based
Git 工作流怎么选?Git Flow vs Trunk-Based
答题要点: 取决于发版频率和团队规模。高分回答:
“Git Flow 有 5 种分支(main/develop/feature/release/hotfix),适合发版周期长(如每月发版)的项目。但分支多、合并冲突多、CI 维护成本高。
Trunk-Based Development 只有 main 和短期 feature 分支(不超过 2 天),适合持续部署(每天多次发版)的项目。Google 等大型互联网公司普遍使用 Trunk-Based Development,配合 Feature Flag 控制未完成功能的可见性。
GitHub Flow 介于两者之间,只有 main 和 feature 分支,适合中小型项目持续部署。“
Q8: Jenkins 是什么?怎么用 Jenkinsfile 配置流水线?
Jenkins 是最老牌的开源 CI/CD 自动化服务器,2011 年从 Hudson 项目 fork 而来。它的核心优势是插件生态极其丰富(1800+ 插件),几乎可以对接任何工具链,特别适合中大型团队自建 CI/CD 平台。Jenkins 的核心概念
Pipeline 语法:Declarative vs Scripted
Jenkins Pipeline 有两种语法风格,推荐使用 Declarative Pipeline(结构清晰、易维护):Jenkinsfile 最佳实践
1. 使用npm ci 而不是 npm install
npm ci 严格按照 package-lock.json 安装依赖,保证 CI 环境和本地环境一致。npm install 可能更新 lock 文件,导致”本地能跑、CI 挂了”的问题。
2. 并行执行独立任务
ESLint、TypeScript、单元测试之间没有依赖关系,用 parallel 块并行执行,CI 时间从串行的 6 分钟缩短到并行的 2 分钟。
3. 归档构建产物
用 archiveArtifacts 保存 dist/ 目录,方便回滚和调试。配合 buildDiscarder 策略自动清理旧产物,避免磁盘爆满。
4. Post 阶段通知
在 post 块中配置构建结果通知(Slack、飞书、钉钉),无论成功还是失败都通知团队。
5. Shared Library 复用流水线
多项目共用的流水线逻辑抽成 Shared Library,避免每个项目的 Jenkinsfile 重复代码:
Jenkins 的核心是 Pipeline as Code——用 Jenkinsfile 定义完整的构建部署流程,阶段可并行、可条件控制、可复用,配合 1800+ 插件生态对接任意工具链。
灰度发布(Progressive Delivery)
灰度发布的核心思想是让新版本逐步生效,而不是一次性全量切换。📚 延伸阅读与引用参考
- 🔗 Conventional Commits 规范:Git 提交信息的官方规范,定义了
feat/fix/chore等 type 的语义化结构。[1] - 📖 GitHub Actions 官方文档:GitHub 的 CI/CD 配置指南,覆盖 workflow、job、step、action 四个核心概念。[2]
- 📖 Git 官方文档:Git 命令的权威参考手册。[3]
- 📖 Martin Fowler《Continuous Integration》:CI 理论的奠基性文章,定义了频繁集成、自动化构建、立即修复失败构建三大原则。[4]
- 🟢 美团技术团队博客:国内最成体系的大厂技术博客之一,覆盖前端 CI/CD 流水线搭建、灰度发布策略、容器化部署等工业级实践。[5]
- 🟢 commitlint 源码:commit message 校验工具的核心实现。
- 🔗 semantic-release 文档:自动化版本管理和发布工具。
- 📖 Atlassian Git 工作流对比:Git Flow、GitHub Flow 等工作流的详细对比。
- 🔗 Harness 官方文档:Harness 平台的完整文档,覆盖 CI、CD、Feature Flags 等模块。
- 📖 Harness Test Intelligence:AI 驱动的选择性测试,只运行受代码变更影响的测试用例。
