正在加载,请稍候…

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

Learn how to set up professional Git workflows and automate deployments with GitHub Actions. Covers branch strategies, pull request automation, testing pipelines, and deployment workflows.

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

The difference between a hobby project and a professional one often comes down to workflow automation. GitHub Actions lets you automate testing, linting, security scanning, and deployment — all from your repository.

Git Branching Strategy

GitHub Flow (Simple, Recommended for Most Teams)

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

Rules:

  1. main is always deployable
  2. All work happens in feature branches
  3. Branches are merged via Pull Requests
  4. Deploy after every merge to main

Git Flow (Complex, for Release-Based Products)

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

Branch Naming Conventions

# Feature branches
feature/user-authentication
feature/JIRA-123-shopping-cart

# Bug fixes
fix/login-redirect-loop
bugfix/memory-leak-in-worker

# Releases
release/v2.1.0
release/2026-Q1

# Hotfixes
hotfix/critical-security-patch
hotfix/payment-gateway-down

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

Commit Message Convention (Conventional Commits)

# Format: 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

# Breaking changes — add ! or footer
feat(api)!: change user endpoint response format
# OR
feat(api): change user endpoint response format

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

GitHub Actions Basics

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

# When to trigger
on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]
  workflow_dispatch:  # Manual trigger button in GitHub UI

jobs:
  test:
    name: Run Tests
    runs-on: ubuntu-latest   # or 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'  # Cache node_modules for speed
      
      - name: Install dependencies
        run: npm ci  # Faster than npm install, uses package-lock.json
      
      - name: Run linter
        run: npm run lint
      
      - name: Run tests
        run: npm test
        env:
          DATABASE_URL: ${{ secrets.TEST_DATABASE_URL }}

Complete CI Pipeline

# .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  # Only run if lint passes
    
    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'  # Only on main branch
    
    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

Deploy to Production

# .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  # Shows in GitHub deployment
    
    steps:
      - uses: actions/checkout@v4
      
      - name: Deploy to Railway
        uses: railway-app/railway-action@v1
        with:
          token: ${{ secrets.RAILWAY_TOKEN }}
          service: api
      
      # OR deploy to your server
      - 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

Branch Protection Rules

# Enforce via GitHub Settings → Branches → Add rule
# Or via 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

Branch protection settings:

  • ✅ Require pull request before merging
  • ✅ Require status checks to pass (CI must be green)
  • ✅ Require at least 1 approval
  • ✅ Dismiss stale reviews on new commits
  • ✅ Require linear history (no merge commits)
  • ✅ Include administrators

Useful GitHub Actions Patterns

Matrix Testing

# Test across multiple Node versions
strategy:
  matrix:
    node: ['18', '20', '22']
    os: [ubuntu-latest, macos-latest]

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

Caching

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

Secrets Management

# Access secrets
env:
  JWT_SECRET: ${{ secrets.JWT_SECRET }}
  DATABASE_URL: ${{ secrets.DATABASE_URL }}

# Never echo secrets (GitHub masks them automatically)
- run: echo "JWT is ${{ secrets.JWT_SECRET }}"  # Shows: JWT is ***

Summary

A professional workflow:

  1. Branch: Work in feature branches
  2. Commit: Use conventional commits
  3. PR: Open pull request with description
  4. CI: Lint + test + security check automatically
  5. Review: Get peer review
  6. Merge: Squash and merge to main
  7. Deploy: Auto-deploy to production

→ Reference common Git commands with the Git Memo tool.