跳到主要内容
预计阅读 51 分钟

Git与CI/CD:让代码自动飞 —— 从Git Hooks到自动化流水线

手动检查代码风格、手动跑测试、手动打版本号、手动部署——每一个”手动”背后都是一次可能的人为失误。Git不仅是版本控制工具,它还内置了一套完善的钩子系统,让你能在关键节点自动执行任务。当Git Hooks与CI/CD平台联手,代码从提交到上线就变成了一条自动运转的传送带。

开篇自测:你已经知道多少?

  1. Git Hooks分为客户端钩子和服务端钩子,它们分别在什么时机触发?
  2. Conventional Commits规范中,featfixchore分别表示什么类型的变更?
  3. GitHub Actions的工作流配置文件应该放在项目的哪个目录下?
  4. 语义化版本号(SemVer)中,1.2.3三个数字分别代表什么含义?

一、Git Hooks:代码仓库里的”门禁系统”

想象你管理一栋写字楼。每层楼都有门禁卡,有的在你进门时检查身份,有的在你出门时记录考勤。Git Hooks就是代码仓库里的门禁系统——它们在特定的Git操作前后自动触发,执行你预设的脚本。

钩子的两大阵营

Git Hooks分为客户端钩子服务端钩子

┌─────────────────────────────────────────────────────────────┐
│                    Git Hooks 全景图                          │
├──────────────────────────┬──────────────────────────────────┤
│     客户端钩子(本地)     │      服务端钩子(远程仓库)       │
├──────────────────────────┼──────────────────────────────────┤
│  pre-commit              │  pre-receive                     │
│  prepare-commit-msg      │  update                          │
│  commit-msg              │  post-receive                    │
│  post-commit             │                                  │
│  pre-push                │                                  │
│  pre-rebase              │                                  │
│  post-merge              │                                  │
│  post-checkout           │                                  │
└──────────────────────────┴──────────────────────────────────┘
  • 客户端钩子运行在开发者本地机器上,通常用于代码质量检查。它们可以被开发者绕过(加 --no-verify 参数),所以更像是一道”建议性”的防线。
  • 服务端钩子运行在远程仓库所在的服务器上,通常用于强制执行团队规范。它们无法被绕过,是真正的”铁门禁”。

钩子脚本存放在每个仓库的 .git/hooks/ 目录下。你可以查看一下这个目录:

ls .git/hooks/
# 你会看到一堆 .sample 结尾的文件
# applypatch-msg.sample  commit-msg.sample  pre-commit.sample ...

# 去掉 .sample 后缀,脚本就会生效

三个最实用的客户端钩子

1. pre-commit:提交前的质量门卫

pre-commit 在你执行 git commit 之后、真正创建提交对象之前触发。如果脚本返回非零退出码,提交会被中止。

来写一个检查代码中是否残留调试语句的钩子:

#!/bin/sh
# .git/hooks/pre-commit

# 检查暂存区的文件中是否包含 console.log 或 debugger
FORBIDDEN_PATTERNS="console\.log\|debugger\|TODO:.*HACK"

# 只检查暂存区中的文件(即将被提交的文件)
FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(js|ts|jsx|tsx)$')

if [ -z "$FILES" ]; then
    exit 0
fi

FOUND=$(echo "$FILES" | xargs grep -n -E "$FORBIDDEN_PATTERNS" 2>/dev/null)

if [ -n "$FOUND" ]; then
    echo "================================================"
    echo " 提交被拦截!发现以下调试代码:"
    echo "================================================"
    echo "$FOUND"
    echo ""
    echo "请移除后重新提交,或使用 git commit --no-verify 跳过检查"
    exit 1
fi

exit 0

2. commit-msg:提交信息的格式审查员

commit-msg 钩子在编辑器关闭、提交信息写入临时文件后触发。它接收一个参数——存放提交信息的临时文件路径。

#!/bin/sh
# .git/hooks/commit-msg

COMMIT_MSG_FILE=$1
COMMIT_MSG=$(cat "$COMMIT_MSG_FILE")

# 检查是否符合 Conventional Commits 格式
# 格式:type(scope): description
PATTERN="^(feat|fix|docs|style|refactor|perf|test|chore|ci|build|revert)(\(.+\))?: .{1,100}"

if ! echo "$COMMIT_MSG" | grep -qE "$PATTERN"; then
    echo "================================================"
    echo " 提交信息格式不符合规范!"
    echo "================================================"
    echo ""
    echo "正确格式:type(scope): description"
    echo ""
    echo "type 可选值:"
    echo "  feat     - 新功能"
    echo "  fix      - 修复Bug"
    echo "  docs     - 文档变更"
    echo "  style    - 代码格式(不影响逻辑)"
    echo "  refactor - 重构(非新功能、非修复)"
    echo "  perf     - 性能优化"
    echo "  test     - 测试相关"
    echo "  chore    - 构建过程或辅助工具变更"
    echo "  ci       - CI配置变更"
    echo "  build    - 构建系统变更"
    echo "  revert   - 回退提交"
    echo ""
    echo "示例:feat(auth): 添加微信扫码登录"
    echo "      fix: 修复用户列表分页错误"
    exit 1
fi

exit 0

3. pre-push:推送前的最后防线

pre-pushgit push 执行之后、数据实际传输之前触发。这是阻止有问题的代码到达远程仓库的最后机会。

#!/bin/sh
# .git/hooks/pre-push

REMOTE="$1"

# 阻止直接推送到 main 或 master 分支
CURRENT_BRANCH=$(git symbolic-ref HEAD 2>/dev/null | sed 's|refs/heads/||')

if [ "$CURRENT_BRANCH" = "main" ] || [ "$CURRENT_BRANCH" = "master" ]; then
    echo "================================================"
    echo " 禁止直接推送到 $CURRENT_BRANCH 分支!"
    echo "================================================"
    echo "请创建功能分支,通过 Pull Request 合并。"
    exit 1
fi

# 推送前运行测试
echo "推送前运行测试..."
npm test 2>/dev/null
if [ $? -ne 0 ]; then
    echo "测试未通过,推送已取消。"
    exit 1
fi

exit 0

想一想 .git/hooks/ 目录不会被 git add 追踪(因为它在 .git 内部),那么团队成员之间如何共享同一套钩子脚本?


二、Husky + lint-staged:工程化的钩子管理方案

上面提到的问题正好引出了工程化方案。手动管理 .git/hooks/ 目录有两个痛点:一是钩子脚本无法随代码一起版本控制;二是团队成员需要手动配置。Husky 和 lint-staged 正是为解决这些问题而生。

安装与配置

# 初始化(假设项目已有 package.json,需要 Husky v9+)
npx husky init

# 这会做两件事:
# 1. 在 package.json 的 scripts 中添加 "prepare": "husky"
# 2. 创建 .husky/ 目录并写入一个示例 pre-commit 钩子

💡 版本提示npx husky init 是 Husky v9+ 的用法。如果你使用的是 v8 或更早版本,初始化命令为 npx husky-init,配置方式也有所不同。建议直接使用最新版本。

安装 lint-staged,它的作用是只对暂存区的文件运行检查,而不是整个项目:

npm install --save-dev lint-staged

配置 lint-staged

package.json 中添加配置:

{
  "lint-staged": {
    "*.{js,jsx,ts,tsx}": [
      "eslint --fix",
      "prettier --write"
    ],
    "*.{css,scss,less}": [
      "prettier --write"
    ],
    "*.{json,md}": [
      "prettier --write"
    ]
  }
}

配置 Husky 钩子

# 编辑 pre-commit 钩子
echo "npx lint-staged" > .husky/pre-commit

# 添加 commit-msg 钩子(配合 commitlint 使用)
npm install --save-dev @commitlint/cli @commitlint/config-conventional
echo "npx --no -- commitlint --edit \$1" > .husky/commit-msg

创建 commitlint 配置文件 commitlint.config.js(如果项目在 package.json 中设置了 "type": "module",需改用 commitlint.config.mjs 并将 module.exports 替换为 export default):

// commitlint.config.js(CommonJS 格式)
module.exports = {
  extends: ['@commitlint/config-conventional'],
  rules: {
    'type-enum': [2, 'always', [
      'feat', 'fix', 'docs', 'style', 'refactor',
      'perf', 'test', 'chore', 'ci', 'build', 'revert'
    ]],
    'subject-max-length': [2, 'always', 100],
    'subject-empty': [2, 'never'],
  }
};

现在,当团队成员克隆项目并执行 npm install 时,prepare 脚本会自动运行 husky,配置好Git钩子。整个过程对开发者来说是透明的。

团队成员克隆项目 → npm install → prepare脚本自动执行husky

                            .git/hooks/ 被自动配置

                        此后每次 commit/push 都会触发检查

常见误区

  • 误区一:“lint-staged会检查项目中所有的文件”。lint-staged的核心价值恰恰在于它只检查暂存区中被修改的文件。如果你的项目有上万个文件,但你只改了3个,那lint-staged只会对这3个文件运行ESLint和Prettier,速度极快。
  • 误区二:“钩子检查太严格会影响开发效率”。恰恰相反,在提交时就拦住格式问题和低级错误,比在代码评审时才发现要高效得多。把机械性的检查交给机器,人类只需要审查逻辑。

三、GitHub Actions:云端的自动化引擎

Git Hooks是在本地运行的”门禁”,而CI/CD平台则是云端的”自动化工厂”。代码推送到远程仓库后,CI/CD平台接手后续的测试、构建、部署工作。

GitHub Actions是目前最流行的CI/CD平台之一,它与GitHub深度集成,对公开仓库完全免费。

Workflow的基本结构

工作流配置文件存放在 .github/workflows/ 目录下,使用YAML格式:

.github/
  workflows/
    ci.yml          ← 持续集成工作流
    release.yml     ← 自动发版工作流
    deploy.yml      ← 部署工作流

一个工作流的骨架长这样:

name: CI                          # 工作流名称

on:                               # 触发条件
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:                             # 任务列表
  lint-and-test:                  # 任务名称
    runs-on: ubuntu-latest        # 运行环境
    steps:                        # 步骤列表
      - uses: actions/checkout@v6 # 使用现成的Action
      - run: npm install          # 运行命令
      - run: npm test

触发条件详解

GitHub Actions支持丰富的触发条件:

on:
  # 代码推送时触发(支持同时匹配分支和标签)
  push:
    branches: [main]
    paths:
      - 'src/**'           # 只有src目录下的文件变更才触发
      - '!src/**/*.md'     # 排除markdown文件
    tags:
      - 'v*'               # 匹配 v1.0.0、v2.1.3 等

  # PR事件触发
  pull_request:
    types: [opened, synchronize, reopened]

  # 定时触发(cron表达式)
  schedule:
    - cron: '0 2 * * 1'    # 每周一凌晨2点

  # 手动触发
  workflow_dispatch:
    inputs:
      environment:
        description: '部署环境'
        required: true
        default: 'staging'
        type: choice
        options:
          - staging
          - production

💡 注意:YAML 规范要求同一层级的键不能重复。如果你需要分别为分支推送和标签推送配置不同的工作流,应该创建两个独立的 workflow 文件,而不是在同一个 on: 块中写两个 push: 键。

实战:前端项目CI工作流

下面是一个React/Vue项目的完整CI配置:

name: Frontend CI

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  quality-check:
    name: 代码质量检查
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [20, 22]     # 同时测试两个LTS版本

    steps:
      - name: 检出代码
        uses: actions/checkout@v6

      - name: 配置 Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v6
        with:
          node-version: ${{ matrix.node-version }}
          cache: 'npm'

      - name: 安装依赖
        run: npm ci

      - name: 代码风格检查
        run: npm run lint

      - name: 类型检查
        run: npm run type-check

      - name: 运行单元测试
        run: npm run test -- --coverage

      - name: 上传覆盖率报告
        if: matrix.node-version == 22
        uses: actions/upload-artifact@v4
        with:
          name: coverage-report
          path: coverage/

  build:
    name: 构建验证
    runs-on: ubuntu-latest
    needs: quality-check            # 依赖quality-check成功

    steps:
      - uses: actions/checkout@v6

      - uses: actions/setup-node@v6
        with:
          node-version: 20
          cache: 'npm'

      - run: npm ci
      - run: npm run build

      - name: 上传构建产物
        uses: actions/upload-artifact@v4
        with:
          name: build-output
          path: dist/
          retention-days: 7

注意几个关键设计:

  • matrix策略:同时在多个Node.js版本上运行测试,确保兼容性。
  • needs依赖build 任务等待 quality-check 通过后才执行,避免浪费计算资源。
  • artifact保存:将覆盖率报告和构建产物保存下来,方便后续查看或部署。

四、CI流水线的完整链路

一条设计良好的CI/CD流水线,就像工厂的装配线——每个工位负责一道工序,产品依次通过每个工位,任何一道工序不合格就停线报警。

┌──────┐    ┌──────┐    ┌──────┐    ┌──────┐    ┌──────┐    ┌──────┐
│ 推送  │───→│ Lint │───→│ 测试  │───→│ 构建  │───→│ 预览  │───→│ 部署  │
│ 代码  │    │ 检查  │    │      │    │      │    │ 环境  │    │ 生产  │
└──────┘    └──────┘    └──────┘    └──────┘    └──────┘    └──────┘
               │            │           │                       │
               ↓            ↓           ↓                       ↓
            格式不过?    测试失败?   构建报错?             需要人工审批
            ← 阻止 →    ← 阻止 →   ← 阻止 →              ← 等待确认 →

GitLab CI/CD简介

如果你的团队使用GitLab,CI/CD配置文件是项目根目录的 .gitlab-ci.yml。核心概念与GitHub Actions类似,但术语有所不同:

概念GitHub ActionsGitLab CI/CD
配置文件.github/workflows/*.yml.gitlab-ci.yml
执行单元JobJob
执行阶段通过needs控制stages定义顺序
运行环境Runner(GitHub托管)Runner(需自行注册或用共享的)
密钥管理SecretsVariables

一个GitLab CI配置示例:

stages:
  - check
  - test
  - build
  - deploy

variables:
  NODE_VERSION: "20"

lint:
  stage: check
  image: node:${NODE_VERSION}-alpine
  cache:
    key: ${CI_COMMIT_REF_SLUG}
    paths:
      - node_modules/
  script:
    - npm ci
    - npm run lint
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
    - if: '$CI_COMMIT_BRANCH == "main"'

unit-test:
  stage: test
  image: node:${NODE_VERSION}-alpine
  script:
    - npm ci
    - npm run test -- --coverage
  coverage: '/All files[^|]*\|[^|]*\s+([\d\.]+)/'
  artifacts:
    reports:
      coverage_report:
        coverage_format: cobertura
        path: coverage/cobertura-coverage.xml

build:
  stage: build
  image: node:${NODE_VERSION}-alpine
  script:
    - npm ci
    - npm run build
  artifacts:
    paths:
      - dist/
    expire_in: 1 week
  only:
    - main

deploy-staging:
  stage: deploy
  script:
    - echo "Deploying to staging..."
  environment:
    name: staging
  only:
    - main

deploy-production:
  stage: deploy
  script:
    - echo "Deploying to production..."
  environment:
    name: production
  when: manual      # 生产部署需手动触发
  only:
    - main

想一想 GitHub Actions和GitLab CI/CD都支持”缓存”机制(缓存node_modules等依赖目录),这对CI流水线的执行速度有多大影响?如果不缓存,每次运行都要从零安装依赖,一个大型项目的 npm install 可能需要2-3分钟。


五、Conventional Commits与语义化版本

代码的提交信息不只是给人看的——当你的提交信息遵循统一的规范时,工具就能自动从中提取信息,实现自动化的版本号管理和变更日志生成。

Conventional Commits规范

这是目前社区最广泛采用的提交信息规范,格式如下:

<type>(<scope>): <description>

[可选的正文]

[可选的脚注]

各字段的含义:

feat(shopping-cart): 添加批量删除商品功能
│    │               │
│    │               └─ description:简短描述,用祈使句
│    └─ scope:影响范围(可选),通常是模块名
└─ type:变更类型

BREAKING CHANGE: 购物车API的返回格式从数组改为对象

└─ 脚注:破坏性变更声明(会触发主版本号递增)

type的完整列表及其含义

type含义示例
feat新功能feat: 添加用户头像上传
fix修复Bugfix: 修复登录页面白屏问题
docs文档变更docs: 更新API接口文档
style代码格式调整style: 统一缩进为2空格
refactor重构refactor: 拆分订单处理模块
perf性能优化perf: 优化首页图片懒加载
test测试相关test: 补充支付模块单元测试
chore杂务(依赖更新等)chore: 升级webpack到v5
ciCI配置变更ci: 添加代码覆盖率检查
build构建系统变更build: 切换到Vite构建
revert回退提交revert: 回退feat(cart)提交

语义化版本(Semantic Versioning)

语义化版本号的格式是 MAJOR.MINOR.PATCH

v2.4.1
│ │ │
│ │ └─ PATCH:修复Bug(向后兼容)
│ └─ MINOR:新增功能(向后兼容)
└─ MAJOR:破坏性变更(不向后兼容)

Conventional Commits与SemVer之间有明确的映射关系:

fix  类型的提交  →  PATCH 版本号递增  →  1.0.0 → 1.0.1
feat 类型的提交  →  MINOR 版本号递增  →  1.0.0 → 1.1.0
BREAKING CHANGE  →  MAJOR 版本号递增  →  1.0.0 → 2.0.0

自动发版实战

利用 standard-versionrelease-please 等工具,可以实现完全自动化的版本管理:

# .github/workflows/release.yml
name: Release

on:
  push:
    branches: [main]

permissions:
  contents: write
  pull-requests: write

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
        with:
          fetch-depth: 0         # 获取完整历史,用于分析提交

      - uses: actions/setup-node@v6
        with:
          node-version: 20
          registry-url: 'https://registry.npmjs.org'

      - name: 安装依赖
        run: npm ci

      - name: 构建
        run: npm run build

      # 使用 release-please 自动管理版本和CHANGELOG
      - uses: googleapis/release-please-action@v4
        id: release
        with:
          release-type: node

      # 如果有新版本发布,自动发布到npm
      - name: 发布到npm
        if: ${{ steps.release.outputs.release_created }}
        run: npm publish
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

这个工作流的运作方式是:

  1. 每次推送到main分支时,release-please 分析自上个版本以来的所有提交信息
  2. 根据Conventional Commits规范自动计算下一个版本号
  3. 自动生成CHANGELOG.md
  4. 创建一个Release PR
  5. 当Release PR被合并时,自动打Tag、创建GitHub Release、发布到npm
feat提交被合并到main → release-please分析提交 → 创建Release PR

                                               PR内容包含:
                                               - 版本号变更
                                               - CHANGELOG更新

                                            维护者审核并合并PR

                                          自动打Tag + 发布npm包

常见误区

  • 误区一:“Conventional Commits太死板,增加了提交的心智负担”。一开始确实需要适应,但配合commitlint自动校验后,格式错误会被即时拦截并提示正确写法,很快就能形成肌肉记忆。而收益是巨大的——自动化的CHANGELOG和版本号让你再也不需要在发版时手动整理”这次版本改了什么”。
  • 误区二:“每个commit都必须严格遵循规范”。在使用Squash Merge策略时,中间的commit信息不太重要,只需要保证最终合并到主分支的那条信息符合规范即可。
  • 误区三:“语义化版本号只是好看”。SemVer是一种承诺——当用户看到你的库从1.2.3升级到1.3.0,他们可以放心升级,因为MINOR版本变更承诺了向后兼容。这是开源生态信任链的基石。

六、实战:配置一套完整的前端自动化流水线

现在让我们把前面所有的知识串联起来,为一个真实的前端项目配置从提交到发版的全套自动化。

第一步:初始化项目钩子

# 安装所有工具
npm install --save-dev husky lint-staged eslint prettier \
  @commitlint/cli @commitlint/config-conventional

# 初始化husky
npx husky init

第二步:配置 package.json

{
  "scripts": {
    "prepare": "husky",
    "lint": "eslint src/ --ext .js,.jsx,.ts,.tsx",
    "lint:fix": "eslint src/ --ext .js,.jsx,.ts,.tsx --fix",
    "format": "prettier --write 'src/**/*.{js,jsx,ts,tsx,css,json}'",
    "type-check": "tsc --noEmit",
    "test": "vitest run",
    "test:coverage": "vitest run --coverage",
    "build": "vite build"
  },
  "lint-staged": {
    "*.{js,jsx,ts,tsx}": [
      "eslint --fix",
      "prettier --write"
    ],
    "*.{css,json,md}": [
      "prettier --write"
    ]
  }
}

第三步:配置钩子脚本

# pre-commit:只检查暂存区文件
echo "npx lint-staged" > .husky/pre-commit

# commit-msg:校验提交信息格式
echo "npx --no -- commitlint --edit \$1" > .husky/commit-msg

# pre-push:推送前运行测试
cat > .husky/pre-push << 'HOOK'
npm run type-check && npm run test
HOOK

第四步:配置GitHub Actions

# .github/workflows/ci.yml
name: CI Pipeline

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

concurrency:
  group: ci-${{ github.ref }}
  cancel-in-progress: true     # 同一分支的新推送会取消旧的运行

jobs:
  lint:
    name: Lint & Format
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - uses: actions/setup-node@v6
        with:
          node-version: 20
          cache: 'npm'
      - run: npm ci
      - run: npm run lint
      - run: npm run type-check

  test:
    name: Unit Tests
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - uses: actions/setup-node@v6
        with:
          node-version: 20
          cache: 'npm'
      - run: npm ci
      - run: npm run test:coverage
      - uses: actions/upload-artifact@v4
        with:
          name: coverage
          path: coverage/

  build:
    name: Build
    runs-on: ubuntu-latest
    needs: [lint, test]
    steps:
      - uses: actions/checkout@v6
      - uses: actions/setup-node@v6
        with:
          node-version: 20
          cache: 'npm'
      - run: npm ci
      - run: npm run build
      - uses: actions/upload-artifact@v4
        with:
          name: dist
          path: dist/

  deploy-preview:
    name: Deploy Preview
    runs-on: ubuntu-latest
    needs: build
    if: github.event_name == 'pull_request'
    steps:
      - uses: actions/download-artifact@v4
        with:
          name: dist
          path: dist/
      - name: 部署到预览环境
        run: echo "Deploy preview for PR #${{ github.event.number }}"
        # 实际项目中可使用 Vercel、Netlify 等平台的预览部署

  deploy-production:
    name: Deploy Production
    runs-on: ubuntu-latest
    needs: build
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
    environment: production     # 可配置需要人工审批
    steps:
      - uses: actions/download-artifact@v4
        with:
          name: dist
          path: dist/
      - name: 部署到生产环境
        run: echo "Deploying to production..."

整体链路图

开发者本地                    │             GitHub 云端

 编写代码                     │
    ↓                        │
 git add                     │
    ↓                        │
 git commit                  │
    ↓                        │
 [pre-commit 触发]           │
  └→ lint-staged             │
     └→ ESLint + Prettier    │
    ↓                        │
 [commit-msg 触发]           │
  └→ commitlint 校验格式     │
    ↓                        │
 git push                    │
    ↓                        │
 [pre-push 触发]             │
  └→ 类型检查 + 单元测试      │
    ↓                        │
 代码到达远程仓库 ──────────→  GitHub Actions 触发
                              │    ├→ Lint检查
                              │    ├→ 测试 + 覆盖率
                              │    ├→ 构建
                              │    ├→ 预览部署(PR时)
                              │    └→ 生产部署(合并到main时)

                              │  release-please 分析提交
                              │    └→ 自动版本号 + CHANGELOG + 发版

这条流水线实现了一个目标:开发者只需要关心写代码和写好提交信息,其余的格式检查、测试、构建、发版全部由自动化工具完成。


掌握度自测

  1. 请解释 pre-commitcommit-msgpre-push 三个钩子各自的触发时机和典型用途。如果开发者使用 --no-verify 跳过了本地钩子,还有什么机制能保证代码质量?

  2. 在一个已有项目中引入husky + lint-staged,需要哪些步骤?新成员克隆项目后如何自动获得钩子配置?

  3. 请写出以下变更对应的Conventional Commits提交信息:(a) 在用户模块中新增了手机号登录功能;(b) 修复了订单金额计算精度丢失的Bug;(c) 将打包工具从webpack迁移到vite,所有构建命令都变了。

  4. 一个npm包当前版本是 2.3.1,经过以下三次提交后版本号应该是多少?fix: 修复类型定义feat: 添加深色模式fix: 修复深色模式下按钮颜色

  5. 在GitHub Actions中,如何实现”lint和test并行执行,两者都通过后再执行build”的流水线结构?请说明关键配置。

自我评估

  • 全部答对:你已经掌握了Git自动化的完整技能栈。代码质量和交付效率可以同时提升,这就是工程化的力量。
  • 答对3-4题:基础扎实,建议在自己的项目中实际配置一遍完整流水线,实践出真知。
  • 答对1-2题:先从最简单的开始——给项目加一个pre-commit钩子,只做ESLint检查。用起来之后,再逐步增加commit-msg校验和CI工作流。

购买课程解锁全部内容

版本控制不翻车:Git 从基础到团队协作

¥29.90