Skip to main content

Command Palette

Search for a command to run...

GitHub Actions and Git: A Complete Workflow Guide

Updated
6 min readView as Markdown

Originally published on DevToolHub.

Git and GitHub Actions are two tools most teams adopt without ever deciding how they fit together. You pick a branching habit, wire up a workflow file, and six months later nobody remembers why deploys are slow or why one pull request skipped its tests. This guide covers the decisions that actually matter.

What does a Git and GitHub Actions workflow actually look like?

A working setup has three layers. Git tracks your code history on short-lived branches. GitHub hosts the shared repository and enforces review rules. GitHub Actions runs automated jobs triggered by events like a push or a pull request.

Every run follows one chain: an event fires (push, pull_request, schedule, workflow_dispatch), GitHub matches it against the on: block of every file in .github/workflows/, matching workflows start their jobs, jobs run in parallel unless needs: sets an order, and each job runs its steps on one runner.

Which Git branching model should you use?

For most teams, use GitHub Flow: one long-lived main, short-lived feature branches, merge through a pull request once checks pass. Trunk-based development suits teams shipping continuously. Git Flow only earns its complexity if you ship versioned software to customers running several versions at once.

Model Branch structure Best for Main cost
GitHub Flow main + short feature branches Most web teams Needs solid PR checks
Trunk-based main only, feature flags Many deploys a day Requires a fast test suite
Git Flow main, develop, release/* Versioned software Heavy branch bookkeeping

Default to GitHub Flow. Move to trunk-based only when your test suite can gate main directly.

When should you rebase instead of merge?

Rebase to clean up your own local commits before you share them. Merge to combine branches other people have already pulled. The Pro Git rule: "Do not rebase commits that exist outside your repository and that people may have based work on."

git checkout feature/login
git rebase main

Rebasing a branch you have already pushed means force-pushing over shared history. Rebase before the first push, merge after.

What are Git hooks actually good for?

Git hooks run your scripts at points in the Git lifecycle — pre-commit for linting, commit-msg for message format, pre-push for a fast test. Hooks live in .git/hooks and are never copied on clone, so share them with git config core.hooksPath or a manager like pre-commit or Husky. Anyone can skip one with git commit --no-verify.

How are GitHub Actions workflows structured?

A workflow is a YAML file in .github/workflows/ with on: (triggers), jobs: (units of work), and inside each job, runs-on: and steps:. Jobs run in parallel by default.

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

permissions:
  contents: read

jobs:
  test:
    runs-on: ubuntu-latest
    timeout-minutes: 15
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
      - run: npm ci
      - run: npm test

concurrency cancels a superseded run. timeout-minutes caps a job before the six-hour platform limit.

Reusable workflows, composite actions, or a matrix?

Use a matrix for the same job across variations. Use a composite action for a repeated step sequence inside one repo. Use a reusable workflow for whole jobs shared across many repos. A matrix caps at 256 jobs per run. Reach for it first.

How should GitHub Actions handle secrets and cloud auth?

Use OpenID Connect for cloud auth: a short-lived token requested at run time, scoped to that repo and branch. Keep the GITHUB_TOKEN read-only by default.

permissions:
  contents: read
  id-token: write

Organizations created before February 2023 may still default to a read-write token — set it explicitly.

How does GitHub Actions caching work, and what does it cost?

The actions/cache action stores a keyed directory. Each repository gets 10 GB. GitHub deletes caches not accessed in seven days and evicts the oldest first past 10 GB.

- uses: actions/cache@v4
  with:
    path: ~/.npm
    key: npm-${{ hashFiles('package-lock.json') }}
    restore-keys: |
      npm-

"Anyone who can open a pull request against your repository can read the contents of caches in the base branch." Do not cache secrets.

How do you enforce tests and reviews?

Enforcement lives in branch protection. Mark status checks as required; the merge button stays disabled until they pass. Required checks match by job name — rename a job and the rule silently stops.

/api/        @org/backend
/web/        @org/frontend
*.tf         @org/platform

How do GitHub Actions deployment environments work?

An environment is a named target with its own secrets and protection rules. A job that sets environment: production pauses until required reviewers approve or a wait timer elapses.

deploy:
  runs-on: ubuntu-latest
  environment: production
  concurrency: production
  steps:
    - run: ./deploy.sh

What actually breaks GitHub Actions in production?

A compromised action dumps secrets into the logs. March 2025: tj-actions/changed-files (CVE-2025-30066). Every tag repointed to a commit that read secrets from runner memory into public logs. 23,000+ repos affected. Fix: pin to a full commit SHA.

pull_request_target runs fork code with your token. If the workflow checks out the pull request head and runs anything from it, that is attacker code with your secrets in scope. Use plain pull_request for contributor code.

Caches vanish mid-sprint. Seven-day eviction plus the 10 GB cap. Symptom: CI time doubles overnight with no code change. Check gh cache list.

Jobs hit a limit and stop. Killed at six hours. Queued job cancelled after 24 hours. Matrix caps at 256. Concurrent jobs cap at 20 on Free, 40 on Pro, 60 on Team.

Frequently Asked Questions

Q: Do I need GitHub Actions if I already use Git? A: Git tracks code; GitHub Actions automates what happens to it. For a team, that automation keeps main releasable.

Q: Is rebase or merge better for a team? A: Rebase your local commits before the first push. Merge branches once other people have pulled them.

Q: How do I stop a third-party GitHub Action from stealing secrets? A: Pin it to a full commit SHA, not a tag. Set the GITHUB_TOKEN read-only and use OIDC.

Q: Why did my GitHub Actions build suddenly get slower? A: Usually cache eviction — seven days unused, or evicted past the 10 GB cap.

Q: Where should I enforce that tests pass before a merge? A: In branch protection, as a required status check. Not the workflow file.

Quick Summary:

  • GitHub Flow is the right default; trunk-based needs a fast, trusted test suite.
  • Rebase local commits before the first push; merge anything already shared.
  • Pin third-party actions to a full commit SHA.
  • Caches are 10 GB per repo and evicted after seven days unused.
  • Real enforcement lives in branch protection.