正在加载,请稍候…

Git 工作流与 GitHub Actions CI/CD:从提交到生产部署

学习如何设置专业的 Git 工作流并使用 GitHub Actions 自动化部署。涵盖分支策略、拉取请求自动化、测试流水线和部署工作流。

Git Workflow and GitHub Actions CI/CD: From Commit to Production

Git 工作流与 GitHub Actions CI/CD:从提交到生产部署

业余项目与专业项目的区别往往在于工作流自动化。GitHub Actions 让你能够自动化测试、代码检查、安全扫描和部署——全部在仓库中完成。

Git 分支策略

Git Workflow and GitHub Actions CI/CD: From Commit to Production illustration

GitHub Flow(简单,推荐大多数团队使用)

main ──────────────────────────────────────────────────────→
        │                    │                     │
        ├── feature/login ──→│                     │
        │                    │                     │
        │              ── feature/cart ──→         │
        │                                          │
        │                              ── fix/auth-bug ──→

规则:

  1. main 始终可部署
  2. 所有工作在特性分支上进行
  3. 通过拉取请求合并分支
  4. 每次合并到 main 后部署

Git Flow(复杂,适用于基于发布的产品)

main ──────────────────────────────────────────────────────→
  │                                                         │
develop ──────────────────────────────────────────→        │
  │          │              │                              │
  │    feature/a ──→        │                              │
  │                    feature/b ──→                       │
  │                                  release/1.2 ──→       │
  │                                                    hotfix/critical ──→

分支命名约定

# 特性分支
feature/user-authentication
feature/JIRA-123-shopping-cart

# 错误修复
fix/login-redirect-loop
bugfix/memory-leak-in-worker

# 发布
release/v2.1.0
release/2026-Q1

# 热修复
hotfix/critical-security-patch
hotfix/payment-gateway-down

# 杂项
chore/update-dependencies
chore/add-eslint-rules
refactor/migrate-to-typescript
docs/update-api-documentation

提交消息约定(Conventional Commits)

# 格式:type(scope): description

feat(auth): add OAuth2 Google login
fix(cart): prevent duplicate item addition on rapid clicks
docs(api): update rate limiting documentation
chore(deps): upgrade to Node.js 20 LTS
refactor(utils): simplify date formatting functions
test(auth): add missing edge case tests for token expiry
perf(db): add index on orders.created_at column
ci(github): add automatic vulnerability scanning

# 破坏性变更——添加 ! 或 footer
feat(api)!: change user endpoint response format
# 或者
feat(api): change user endpoint response format

BREAKING CHANGE: user.fullName is now user.firstName + user.lastName

Git Workflow and GitHub Actions CI/CD: From Commit to Production illustration

GitHub Actions 基础

# .github/workflows/my-workflow.yml
name: CI Pipeline

# 何时触发
on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]
  workflow_dispatch:  # GitHub UI 中的手动触发按钮

jobs:
  test:
    name: Run Tests
    runs-on: ubuntu-latest   # 或 macos-latest, windows-latest
    
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'  # 缓存 node_modules 以加快速度
      
      - name: Install dependencies
        run: npm ci  # 比 npm install 更快,使用 package-lock.json
      
      - name: Run linter
        run: npm run lint
      
      - name: Run tests
        run: npm test
        env:
          DATABASE_URL: ${{ secrets.TEST_DATABASE_URL }}

完整 CI 流水线

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

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

jobs:
  lint:
    name: Lint & Type Check
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: '20', cache: 'npm' }
      - run: npm ci
      - run: npm run lint
      - run: npm run typecheck

  test:
    name: Test
    runs-on: ubuntu-latest
    needs: lint  # 仅在 lint 通过后运行
    
    services:
      postgres:
        image: postgres:16
        env:
          POSTGRES_DB: testdb
          POSTGRES_USER: user
          POSTGRES_PASSWORD: password
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
        ports:
          - 5432:5432
    
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: '20', cache: 'npm' }
      - run: npm ci
      - name: Run migrations
        run: npm run db:migrate
        env:
          DATABASE_URL: postgresql://user:password@localhost:5432/testdb
      - name: Run tests with coverage
        run: npm test -- --coverage
        env:
          DATABASE_URL: postgresql://user:password@localhost:5432/testdb
          JWT_SECRET: test-secret-32-characters-long-xx
      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v4
        with:
          token: ${{ secrets.CODECOV_TOKEN }}

  security:
    name: Security Scan
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: '20', cache: 'npm' }
      - run: npm ci
      - name: Check for vulnerabilities
        run: npm audit --audit-level=high
      - name: Run Snyk scan
        uses: snyk/actions/node@master
        env:
          SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
        with:
          args: --severity-threshold=high

  build:
    name: Build Docker Image
    runs-on: ubuntu-latest
    needs: [test, security]
    if: github.ref == 'refs/heads/main'  # 仅在 main 分支
    
    steps:
      - uses: actions/checkout@v4
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3
      - name: Login to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}
      - name: Build and push
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: |
            myapp/api:latest
            myapp/api:${{ github.sha }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

部署到生产环境

# .github/workflows/deploy.yml
name: Deploy to Production

on:
  workflow_run:
    workflows: ["CI"]
    types: [completed]
    branches: [main]

jobs:
  deploy:
    name: Deploy
    runs-on: ubuntu-latest
    if: ${{ github.event.workflow_run.conclusion == 'success' }}
    
    environment:
      name: production
      url: https://myapp.com  # 在 GitHub 部署中显示
    
    steps:
      - uses: actions/checkout@v4
      
      - name: Deploy to Railway
        uses: railway-app/railway-action@v1
        with:
          token: ${{ secrets.RAILWAY_TOKEN }}
          service: api
      
      # 或者部署到你的服务器
      - name: Deploy to server via SSH
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            cd /app
            docker pull myapp/api:${{ github.sha }}
            docker-compose up -d --no-deps api
            docker system prune -f
      
      - name: Create GitHub Release
        uses: softprops/action-gh-release@v2
        if: startsWith(github.ref, 'refs/tags/')
        with:
          generate_release_notes: true

分支保护规则

# 通过 GitHub Settings → Branches → Add rule 强制执行
# 或通过 github CLI:
gh api repos/{owner}/{repo}/branches/main/protection -X PUT -f required_status_checks='{"strict":true,"contexts":["lint","test","security"]}' -f enforce_admins=true -f required_pull_request_reviews='{"required_approving_review_count":1,"dismiss_stale_reviews":true}' -f restrictions=null

分支保护设置:

  • ✅ 合并前要求拉取请求
  • ✅ 要求状态检查通过(CI 必须为绿色)
  • ✅ 要求至少 1 个批准
  • ✅ 新提交时忽略过时的审查
  • ✅ 要求线性历史(无合并提交)
  • ✅ 包括管理员

Git Workflow and GitHub Actions CI/CD: From Commit to Production illustration

有用的 GitHub Actions 模式

矩阵测试

# 跨多个 Node 版本测试
strategy:
  matrix:
    node: ['18', '20', '22']
    os: [ubuntu-latest, macos-latest]

steps:
  - uses: actions/setup-node@v4
    with:
      node-version: ${{ matrix.node }}

缓存

# 缓存 node_modules(加速 10 倍)
- uses: actions/cache@v4
  with:
    path: ~/.npm
    key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
    restore-keys: |
      ${{ runner.os }}-node-

密钥管理

# 访问密钥
env:
  JWT_SECRET: ${{ secrets.JWT_SECRET }}
  DATABASE_URL: ${{ secrets.DATABASE_URL }}

# 切勿回显密钥(GitHub 会自动屏蔽)
- run: echo "JWT is ${{ secrets.JWT_SECRET }}"  # 显示:JWT is ***

总结

专业工作流:

  1. 分支:在特性分支中工作
  2. 提交:使用 Conventional Commits
  3. PR:打开带有描述的拉取请求
  4. CI:自动进行代码检查 + 测试 + 安全检查
  5. 审查:获得同行审查
  6. 合并:压缩合并到 main
  7. 部署:自动部署到生产环境

→ 使用 Git Memo 工具参考常见 Git 命令。