GitHub Actions can enforce that all required status checks pass before a pull request can be merged.

Let’s see it in action. Imagine a repository with a CI workflow that runs tests and linters.

name: CI

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

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - name: Set up Python 3.10
      uses: actions/setup-python@v3
      with:
        python-version: "3.10"
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install flake8 pytest
    - name: Lint with flake8
      run: |
        flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
    - name: Test with pytest
      run: pytest

This workflow defines a build job that checks out the code, sets up Python, installs dependencies, and then runs flake8 for linting and pytest for testing.

By default, GitHub doesn’t know which of these jobs are "required." To make them required, we need to go to the repository’s settings.

Navigate to your repository on GitHub. Click on "Settings" in the right-hand sidebar. Then, select "Branches" from the left-hand menu. Under "Branch protection rules," click "Add rule."

Here, you’ll configure the rule. Under "Branch name pattern," enter main (or whichever branch you want to protect). Scroll down to "Status checks." Check the box that says "Require status checks to pass before merging."

Once that’s checked, a new section appears: "Status checks that are required." You’ll see a list of checks that have recently run on your repository. If your CI workflow has already run, you should see names like build (the job name) or specific step names if they were configured to report status.

Click "Find status checks to require" or "Add status checks" and select the relevant checks. In our example, you’d select build. You can also check "Require branches to be up to date before merging." This ensures that the checks are run against the latest version of the target branch, preventing merge conflicts and ensuring compatibility.

Now, when someone opens a pull request against the main branch, the CI workflow will automatically trigger. The pull request will show a status indicator next to the required checks. Until all selected status checks pass (they turn green), the "Merge pull request" button will be disabled. If any check fails (turns red), the PR cannot be merged until the failure is resolved and the checks pass again.

The most surprising true thing about this system is that the "status checks" displayed in the branch protection rules UI are not directly tied to the workflow file itself, but rather to the status reports generated by jobs or individual steps within those workflows. If a job or step is configured to report its status (which most are by default when run via on: pull_request:), and it has a unique name, GitHub registers it. You can even have external services report status checks.

This mechanism is powerful because it decouples the enforcement of checks from the definition of the checks, allowing for flexibility and integration with various CI/CD tools beyond GitHub Actions. You could, for instance, have a Jenkins job report its status back to GitHub, and then make that status check required.

The next concept you’ll likely encounter is configuring more granular branch protection rules, such as requiring reviews or restricting who can push to a branch.

Want structured learning?

Take the full Github-actions course →