Skip to content

← Writing

engineering

CI/CD and Version Control: The Conveyor Belt for Code

· Jerwin Arnado ·

Part seven of the full-stack series. The deployment post said deploys should be automated and a non-event. This is the machine that makes them so. Two linked ideas: version control is the single source of truth for your code’s history, and CI/CD is the automated conveyor belt that carries a commit from “pushed” to “live” — running the tests and building the artifact on the way, so humans don’t do it by hand and forget a step.

Version control: the foundation everything else stands on

I’ve written a whole git series on this, so here I’ll just state the load-bearing parts. Git gives you history, branching, and collaboration. The decisions that matter for a pipeline:

  • A branching model the team actually follows — trunk-based or GitHub Flow for most web apps.
  • Conventional commits so history is readable and changelogs/versioning can be automated.
  • A protected main: no direct pushes, changes land via reviewed pull requests.

main is sacred because the pipeline treats it as deployable. If main is broken, your release valve is broken.

CI: catch it before a human sees it

Continuous Integration means every push runs an automated gauntlet — tests, linters, type checks, a build — before the code merges. The point is to catch breakage when it’s cheapest: in a PR, not in production. A minimal GitHub Actions workflow for a Laravel app:

name: CI
on: [pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    services:
      mysql:
        image: mysql:8
        env: { MYSQL_DATABASE: testing, MYSQL_ROOT_PASSWORD: secret }
        ports: ['3306:3306']
    steps:
      - uses: actions/checkout@v4
      - uses: shivammathur/setup-php@v2
        with: { php-version: '8.5' }
      - run: composer install --no-interaction
      - run: ./vendor/bin/pint --test    # formatting
      - run: php artisan test            # the test suite, real MySQL

This is the pre-push hook made non-bypassable. A hook is a courtesy; CI is the gate. Run tests against a real database service, not mocks, so a green check means it actually works.

CD: from green check to live

Continuous Delivery/Deployment is the back half: once main is green, ship it — using the reproducible, reversible deploy from the hosting post.

name: Deploy
on:
  push:
    branches: [main]
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Trigger deploy
        run: curl -fsS "$FORGE_DEPLOY_HOOK"   # Forge runs the deploy script

Delivery means every green main is ready to ship at the push of a button. Deployment means it ships automatically. Pick based on how much you trust your test suite and how much a bad deploy costs — money-handling apps often keep a human on the button.

Why this is worth the setup cost

The pipeline pays for itself fast:

Without CI/CD With CI/CD
“did you run the tests?” tests ran, automatically, every PR
manual deploy, steps forgotten identical sequence every time
broken main discovered in prod broken main blocked at the PR
fear of shipping → rare, huge deploys confidence → small, frequent deploys

Small frequent deploys are safer than big rare ones: less changes per deploy means a smaller blast radius and an obvious culprit when something breaks — which pairs perfectly with git bisect on an honest, always-green history.

Caveats and best practices

  • Keep CI fast. A 30-minute pipeline trains people to skip it or merge around it. Cache dependencies, parallelize jobs, run the slowest suites only where they’re needed.
  • Secrets live in the CI provider’s vault, never in the workflow file. Same rule as .env in deployment.
  • The pipeline is code — review it. A workflow with deploy keys is a high-value target; changes to it deserve the same scrutiny as app code, and more.
  • Make failure loud. A red build nobody notices is worse than no build. Wire failures to Slack/email so they can’t be ignored.

Conclusion

VCS   → source of truth: protected main, PRs, conventional commits
CI    → every push: lint + test + build, real services, non-bypassable
CD    → green main → reproducible, reversible deploy
Why   → small frequent deploys, smaller blast radius, no fear

Version control plus CI/CD is the conveyor belt that turns shipping from a nervous ritual into background noise. Set it up once and every change after rides it for free. Next: security and row-level security — hardening the app the pipeline so reliably ships.