Git 工作流与 GitHub Actions CI/CD:从提交到生产部署
业余项目与专业项目的区别往往在于工作流自动化。GitHub Actions 让你能够自动化测试、代码检查、安全扫描和部署——全部在仓库中完成。
Git 分支策略

GitHub Flow(简单,推荐大多数团队使用)
main ──────────────────────────────────────────────────────→
│ │ │
├── feature/login ──→│ │
│ │ │
│ ── feature/cart ──→ │
│ │
│ ── fix/auth-bug ──→
规则:
main始终可部署- 所有工作在特性分支上进行
- 通过拉取请求合并分支
- 每次合并到 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

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 个批准
- ✅ 新提交时忽略过时的审查
- ✅ 要求线性历史(无合并提交)
- ✅ 包括管理员

有用的 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 ***
总结
专业工作流:
- 分支:在特性分支中工作
- 提交:使用 Conventional Commits
- PR:打开带有描述的拉取请求
- CI:自动进行代码检查 + 测试 + 安全检查
- 审查:获得同行审查
- 合并:压缩合并到 main
- 部署:自动部署到生产环境
→ 使用 Git Memo 工具参考常见 Git 命令。