Lesson 5 of 9 · about 15 minutes

CI/CD and branches

A robot reviewer that tests every branch before it reaches main, and a robot publisher that ships main when it changes.

You will add a GitHub Actions workflow that runs pytest on every pull request, see a pull request go red and then green, and understand how main becomes a deployment.

Why integrate continuously?

Martin Fowler's definition: "Continuous Integration is a software development practice where each member of a team merges their changes into a codebase together with their colleagues changes at least daily. Each of these integrations is verified by an automated build (including test) to detect integration errors as quickly as possible."1 GitHub makes the same case: "Committing code more often detects errors sooner and reduces the amount of code a developer needs to debug."2

Two patterns from Fowler's branching essay give the vocabulary:3

His key point about branches: "Frequent integration increases the frequency of merges but reduces their complexity and risk."3 That's why the course keeps saying short-lived branches: a one-task branch merged within a day is easy to test and easy to merge.

How a workflow attaches to branches

A workflow is a YAML file in .github/workflows/. This one is the minimal Python CI from GitHub's tutorial,4 with the actions bumped to their current major versions (checkout@v7, setup-python@v7):12

# .github/workflows/ci.yml
name: CI
on:
  push:
    branches: [main]          # run after anything lands on main
  pull_request:
    branches: [main]          # run on every PR whose BASE is main
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: actions/setup-python@v7
        with:
          python-version: "3.12"
      - run: pip install -r requirements.txt
      - run: pytest

Three details trip people up:

Each job reports a status check that appears on the PR's Checks tab and next to the merge button.7

Do it for real: red, then green

Back in penguins-lab. main now has clean.py and test_clean.py from Lesson 4.

  1. $ git switch main
    $ git pull
    $ git switch -c add-ci
  2. pandas
    pytest
  3. $ git add .github requirements.txt
    $ git commit -m "Add pytest CI workflow"
    $ git push -u origin add-ci
    $ gh pr create --fill
    $ gh pr checks --watch
    Wait for the test check to pass. It takes a minute or two.
  4.     return df.reset_index(drop=True)   # bug: no dropna
    $ git commit -am "Simulate a bad change"
    $ git push
    $ gh pr checks --watch
    The check goes red. Open the PR in the browser (gh pr view --web) and find assert 3 == 2 in the job log. This is exactly what CI does when an agent's change breaks something.
  5. $ git restore --source=HEAD~1 clean.py   # bring back the good version
    $ git commit -am "Restore dropna"
    $ git push
    $ gh pr checks --watch
  6. $ gh pr merge --squash --delete-branch
    $ git switch main
    $ git pull
    The push: branches: [main] trigger now runs CI once more on main itself. Check the repo's Actions tab.

Making green mandatory: branch protection

Right now a red PR can still be merged. Branch protection closes that gap. With "require status checks before merging," required checks "must have a successful, skipped, or neutral status before collaborators can make changes to a protected branch."8 You can also require approving reviews, so changes reach main only "via a pull request that is approved by the required number of reviewers."8 Newer repositories can do the same with rulesets, "a named list of rules" that can stack on one branch.9

On GitHub Free, protected branches and rulesets work in public repositories only.89 A private student repo on Free can't enforce them, so you have to enforce the habit yourself: never merge on red.

One gotcha: if a required check's workflow is skipped by a branch or path filter, its check stays "Pending," and the PR "will be blocked from merging."5 Keep the triggers of required workflows broad.

The CD half: deploying from main

GitHub's definition: "Continuous deployment (CD) is the practice of using automation to publish and deploy software updates. As part of the typical CD process, the code is automatically built and tested before deployment." A CD workflow often runs "when new code is pushed to the default branch."10

feature branch you / Claude pull request CI: pytest ✓ main merge deploy (CD) GitHub Pages on: pull_request on: push to main
CI guards the door to main; CD ships whatever is on main. Branches are where the risky work happens.

The site you're reading is deployed this way. Here is a trimmed version of its Pages workflow (the full files are in the course repository):

name: Deploy Pages
on:
  push:
    branches: [main]          # only main deploys; PRs never do
  workflow_dispatch:
permissions:
  contents: read
  pages: write                # required by deploy-pages
  id-token: write             # required by deploy-pages
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: actions/configure-pages@v6
      - uses: actions/upload-pages-artifact@v5
        with:
          path: .
  deploy:
    needs: build
    runs-on: ubuntu-latest
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    steps:
      - id: deployment
        uses: actions/deploy-pages@v5

The deploy job "must have a minimum of pages: write and id-token: write permissions" and runs in the github-pages environment.11 GitHub's Pages docs also note the deploy step "is skipped if the workflow was triggered by a pull request."11 Branches stay previews of work; only main goes live.

Why this matters for agentic coding

When Claude Code pushes commits to an agent branch, CI is a reviewer that never gets tired. It re-runs your tests on every push and puts a red or green mark on the PR before you have read a line. Your job shifts to reading the diff and the check results. The agent's job is to make the check green. In Lesson 6 you'll tell Claude to do exactly that.

Check yourself

Watch the current branch's pull request checks in the terminal until they finish.

A workflow has on: pull_request: branches: [main]. You open a PR from add-ci into main. Does it run?

For pull_request, branches filters on the branch the PR targets: the base.

What code does CI test for a pull request, by default?

actions/checkout checks out refs/pull/N/merge, so tests run "against the merged result, not just the head branch alone."

Your private repo is on GitHub Free. Can you require green checks before merging?

Protected branches and rulesets are available for public repositories on GitHub Free; private repositories need Pro, Team, or Enterprise.

In this course's Pages workflow, what triggers a deployment?

CD runs on push to main. Pull requests get CI, not deployments.

Read Martin Fowler's Continuous Integration, at least the "Practices of Continuous Integration" section. It explains why the build must be fast, self-testing, and fixed immediately when broken. For hands-on reinforcement, try GitHub Skills' Test with Actions.
Anything fuzzy? Ask Claude: "Read my .github/workflows/ci.yml and explain each line," or "My PR check is failing. Run gh pr checks and summarise the error."

Want more practice before moving on? Paste the branch practice tutor prompt into Claude. It drills everything from Lessons 1 to 5, including red and green checks on real pull requests, before you hand the keyboard to an agent in Lesson 6.

Sources

  1. Martin Fowler, Continuous Integration (2024).
  2. GitHub Docs, Continuous integration.
  3. Martin Fowler, Patterns for Managing Source Code Branches (mainline, healthy branch, integration frequency).
  4. GitHub Docs, Building and testing Python.
  5. GitHub Docs, Workflow syntax: on.pull_request.branches.
  6. GitHub Docs, Events that trigger workflows: pull_request.
  7. GitHub Docs, Status checks.
  8. GitHub Docs, About protected branches.
  9. GitHub Docs, About rulesets.
  10. GitHub Docs, Continuous deployment.
  11. GitHub Docs, Using custom workflows with GitHub Pages and Configuring a publishing source.
  12. Release pages: actions/checkout, actions/setup-python, configure-pages, upload-pages-artifact, deploy-pages (checked October 2026).