GitHub Actions Tutorial — Push & Pull Request
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
mainis 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 →