GitHub Actions Basics: CI/CD verstehen
Wie GitHub Actions wirklich funktioniert — Workflows, Jobs, Steps und Trigger. Mit einem ersten lauffähigen Workflow und den Konzepten dahinter.
Zuletzt aktualisiert: 11. Mai 2026
GitHub Actions ist die Automatisierungsschicht direkt im Repo: Jedes Mal, wenn jemand pushed, einen PR öffnet, ein Tag setzt oder ein Cron-Timer feuert, kann Code laufen — gebaut, getestet, deployed, gelabelt. In diesem Kurs lernst du das mentale Modell und schreibst deinen ersten eigenen Workflow.
Lernziele
- Du verstehst die Hierarchie Workflow → Job → Step
- Du kennst die wichtigsten Trigger (
on:) - Du schreibst einen funktionierenden Workflow von Hand
- Du nutzt Secrets, Caches und Matrix-Builds bewusst
Das mentale Modell
flowchart TD
E[Event: push, PR, schedule, ...] --> WF[Workflow<br/><small>.github/workflows/ci.yml</small>]
WF --> J1[Job: build]
WF --> J2[Job: test]
WF --> J3[Job: deploy]
J1 --> S1[Step: checkout]
J1 --> S2[Step: setup-node]
J1 --> S3[Step: npm run build]| Ebene | Was es ist |
|---|---|
| Workflow | YAML-Datei in .github/workflows/ |
| Job | Eine Gruppe von Steps, läuft auf einem Runner |
| Step | Ein einzelner Befehl oder eine Action |
| Action | Wiederverwendbarer Baustein (z. B. actions/checkout@v4) |
| Runner | Die Maschine, auf der der Job ausgeführt wird |
Wichtig: Jeder Job startet in einer frischen VM. Dateien zwischen Jobs zu teilen geht nur über Artifacts oder Caches — nicht über das Dateisystem.
Dein erster Workflow
Lege eine Datei .github/workflows/ci.yml an:
name: CI
on:
push:
branches: [main]
pull_request:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- run: npm testWas hier passiert, Zeile für Zeile:
name:— wie der Workflow in der UI heißton:— wann er läuft (siehe nächster Abschnitt)jobs.test— ein Job namenstestruns-on:— der Runner-Typ (Ubuntu, Windows, macOS oder self-hosted)steps:— die Befehlsfolge, von oben nach unten
Die wichtigsten Trigger
on:
push:
branches: [main, release/*]
paths:
- "src/**"
- "package.json"
pull_request:
types: [opened, synchronize, reopened]
schedule:
- cron: "0 6 * * *" # täglich 06:00 UTC
workflow_dispatch: # manuell aus der UI
release:
types: [published]
workflow_dispatchist Gold wert beim Testen — du kannst den Workflow manuell aus der UI starten, ohne ein Commit erzwingen zu müssen.
Steps: uses vs run
Es gibt genau zwei Arten von Steps:
| Typ | Beispiel | Wann |
|---|---|---|
uses: |
actions/checkout@v4 |
Wiederverwendbare Action aus Marketplace/Repo |
run: |
npm test |
Direkter Shell-Befehl auf dem Runner |
- name: Tests laufen lassen
run: |
npm ci
npm test -- --reporter=verbose
env:
NODE_ENV: testAction immer mit Version pinnen (@v4 oder besser ein SHA-Hash) —
sonst kann sich Verhalten unter dir ändern.
Secrets & Variables
Niemals Tokens ins YAML schreiben. Stattdessen in den Repository- Settings unter Secrets and variables → Actions hinterlegen:
- name: Deploy
env:
API_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
REGION: ${{ vars.AWS_REGION }}
run: ./scripts/deploy.sh| Wert | Sichtbar im Log? | Wofür |
|---|---|---|
secrets.X |
nein (maskiert) | Tokens, Passwörter, Keys |
vars.X |
ja | Konfiguration, Regionen, Flags |
Jobs parallel & abhängig
Standardmäßig laufen Jobs parallel. Mit needs: machst du sie
abhängig:
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm run lint
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm test
deploy:
needs: [lint, test]
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- run: ./deploy.shflowchart LR
L[lint] --> D[deploy]
T[test] --> DDas if: ist eine Bedingung — deploy läuft nur auf main, nicht
bei jedem PR.
Matrix-Builds
Wenn du die gleichen Schritte auf mehreren Konfigurationen laufen lassen willst:
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
node: [18, 20, 22]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
- run: npm ci && npm testDas erzeugt 3 × 3 = 9 parallele Jobs. fail-fast: false heißt:
selbst wenn einer scheitert, laufen die anderen weiter — du siehst alle
Probleme auf einmal.
Caching — Builds beschleunigen
- uses: actions/setup-node@v4
with:
node-version: 20
cache: "npm" # eingebauter Cache von setup-nodeOder explizit mit actions/cache:
- uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-Der Key entscheidet über Hit/Miss. hashFiles(...) ändert sich, wenn
sich die Lockfile ändert — genau das, was du willst.
Artifacts — Dateien zwischen Jobs teilen
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm run build
- uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
e2e:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v4
with:
name: dist
path: dist/
- run: npm run test:e2eHäufige Stolperfallen
„Mein Workflow läuft gar nicht"
- Liegt die Datei in
.github/workflows/(zwei Punkte beachten)? - Endung
.ymloder.yaml? - Auf welcher Branch? Trigger feuert nur, wenn die YAML auf der Branch liegt, die das Event auslöst.
„Secrets sind leer in Forks"
Aus Sicherheitsgründen: bei PRs aus Forks werden Secrets nicht
mitgegeben. Workaround: pull_request_target — aber vorsichtig, das
führt zu eigenen Sicherheitsrisiken.
„Workflow gewinnt nie an Geschwindigkeit"
Checke in dieser Reihenfolge:
- Wird wirklich gecached? (UI zeigt Cache-Hit/Miss)
- Lassen sich Jobs parallel statt sequenziell führen?
- Kann der Job auf einem kleineren Runner laufen?
Praxis-Übung
In einem beliebigen kleinen Repo:
- Lege
.github/workflows/hello.ymlan:
name: Hello
on: [workflow_dispatch, push]
jobs:
greet:
runs-on: ubuntu-latest
steps:
- run: echo "Hallo von $GITHUB_ACTOR auf $GITHUB_REF"
- run: |
echo "Event: $GITHUB_EVENT_NAME"
echo "SHA: $GITHUB_SHA"- Push die Datei.
- Geh auf den Actions-Tab im Repo — du solltest deinen Workflow laufen sehen.
- Klick auf „Run workflow" (
workflow_dispatch), um ihn manuell zu starten.
Wenn das klappt: erweitere ihn um einen zweiten Job mit needs: und
schau dir die Visualisierung in der UI an.
Weiterführendes
- Offizielle Docs: https://docs.github.com/de/actions
- Marketplace: https://github.com/marketplace?type=actions
- Awesome Actions: https://github.com/sdras/awesome-actions
- Action-Versionen pinnen (SHA-Hash): https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-third-party-actions
CI/CD ist kein Tool, das man installiert — es ist eine Gewohnheit, die man schreibt. ⚙️