GitHub Actions Tutorial — Push & Pull Request

2 minute read

Push & Pull Request Triggers

The push and pull_request triggers are the foundation of CI workflows. Understanding exactly when each fires — and the differences between them — is critical for building reliable pipelines.


The push Trigger

on: push fires when commits are pushed to the repository. This includes:

  • Direct pushes to any branch
  • Merge commits from pull requests
  • Tag pushes

name: CI on Push

on:
  push:
    branches: [main, develop]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm test

What push Gives You

The github context contains push-specific information:

Context Variable Example Value
${{ github.event_name }} push
${{ github.ref }} refs/heads/main
${{ github.sha }} abc123def456...
${{ github.actor }} octocat

The pull_request Trigger

on: pull_request fires when a pull request is:

Activity Type When
opened PR is created
synchronize New commits pushed to the PR branch
reopened A closed PR is reopened

These three are the defaults. You can listen to additional activity types:


on:
  pull_request:
    types: [opened, synchronize, reopened, labeled, ready_for_review]

Basic PR Workflow


name: PR Checks

on:
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npm test


push vs pull_request — Key Differences

Aspect push pull_request
When Commits pushed to branch PR opened/updated
Ref Branch being pushed to Merge ref (refs/pull/N/merge)
SHA Commit SHA Merge commit SHA
Fork PRs N/A Limited token permissions
Typical use Post-merge CI, deploy Pre-merge validation

The Merge Ref

When a pull_request event fires, GitHub checks out a merge commit — the result of merging the PR branch into the target branch. This means your CI tests the merged result, not just the PR branch alone.

PR branch:     A → B → C
Target branch: A → D → E
                        ↓
Merge ref:     A → D → E → merge(C)  ← your CI tests this

Fork Pull Requests — Security

When someone opens a PR from a fork, GitHub restricts what the workflow can access:

Resource Fork PRs
Secrets ❌ Not available
GITHUB_TOKEN Read-only
Write permissions ❌ Not available

This prevents malicious forks from accessing your secrets. To run workflows that need secrets on fork PRs, use the pull_request_target trigger (with caution — see Troubleshooting).


Combining push and pull_request

A common pattern is to run CI on both:


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

This runs CI when:

  • Code is pushed directly to main
  • A PR targeting main is opened or updated

Note: When a PR is merged, both triggers fire — push (because commits land on main) and potentially pull_request (closed event). Use branch filters to avoid double runs.


Common Mistakes

Mistake Fix
CI runs twice on PR merge Use push for post-merge only: branches: [main]. The PR run already validated.
Fork PR can’t access secrets Expected behavior. Use pull_request_target carefully if needed.
PR workflow runs on wrong branches Add branches: filter: pull_request: branches: [main]
Push trigger fires on tag push Add branches: or use tags: filter to separate

Quick Reference

Trigger Default Activity Types Use Case
push N/A (fires on any push) Post-merge CI, deploy
pull_request opened, synchronize, reopened Pre-merge validation
pull_request_target Same as pull_request Fork PRs needing secrets

← Back to: Chapter 3: Triggers

Next: Branch & Path Filtering →

Updated: