Git-Workflow-Muster
Best Practices für die Git-Versionskontrolle, Branching-Strategien und kollaborative Entwicklung.
Wann aktivieren
- Einrichtung eines Git-Workflows für ein neues Projekt
- Entscheidung für eine Branching-Strategie (GitFlow, trunk-basiert, GitHub Flow)
- Schreiben von Commit-Nachrichten und PR-Beschreibungen
- Auflösen von Merge-Konflikten
- Verwaltung von Releases und Versionstags
- Einarbeitung neuer Teammitglieder in Git-Praktiken
Branching-Strategien
GitHub Flow (Einfach, für die meisten empfohlen)
Am besten geeignet für Continuous Deployment und kleine bis mittelgroße Teams.
main (geschützt, immer bereit für Deployment)
│
├── feature/user-auth → PR → merge to main
├── feature/payment-flow → PR → merge to main
└── fix/login-bug → PR → merge to main
Regeln:
mainist immer deploybar- Feature-Branches werden von
mainerstellt - Pull Request öffnen, wenn bereit für Review
- Nach Genehmigung und bestandenem CI in
mainmergen - Sofort nach dem Merge deployen
Trunk-Based Development (Hochgeschwindigkeits-Teams)
Am besten geeignet für Teams mit starkem CI/CD und Feature Flags.
main (trunk)
│
├── kurzlebiger Feature-Branch (max. 1-2 Tage)
├── kurzlebiger Feature-Branch
└── kurzlebiger Feature-Branch
Regeln:
- Jeder commitet in
mainoder in sehr kurzlebigen Branches - Feature Flags verbergen unfertige Arbeit
- CI muss vor dem Merge bestehen
- Mehrmals täglich deployen
GitFlow (Komplex, Release-Zyklus-gesteuert)
Am besten geeignet für geplante Releases und Unternehmensprojekte.
main (Produktions-Releases)
│
└── develop (Integrations-Branch)
│
├── feature/user-auth
├── feature/payment
│
├── release/1.0.0 → merge to main and develop
│
└── hotfix/critical → merge to main and develop
Regeln:
mainenthält nur produktionsbereiten Codedevelopist der Integrations-Branch- Feature-Branches von
develop, mergen zurück indevelop - Release-Branches von
develop, mergen inmainunddevelop - Hotfix-Branches von
main, mergen inmainunddevelop
Wann welche Strategie verwenden
| Strategie | Teamgröße | Release-Rhythmus | Am besten geeignet für |
|---|---|---|---|
| GitHub Flow | Beliebig | Kontinuierlich | SaaS, Web-Apps, Startups |
| Trunk-Based | 5+ erfahrene | Mehrmals täglich | Hochgeschwindigkeits-Teams, Feature Flags |
| GitFlow | 10+ | Geplant | Unternehmen, regulierte Branchen |
Commit-Nachrichten
Conventional Commits Format
<typ>(<bereich>): <betreff>
[optionaler body]
[optionaler footer(s)]
Typen
| Typ | Verwendung | Beispiel |
|---|---|---|
feat | Neue Funktion | feat(auth): add OAuth2 login |
fix | Fehlerbehebung | fix(api): handle null response in user endpoint |
docs | Dokumentation | docs(readme): update installation instructions |
style | Formatierung, keine Codeänderung | style: fix indentation in login component |
refactor | Code-Umstrukturierung | refactor(db): extract connection pool to module |
test | Tests hinzufügen/aktualisieren | test(auth): add unit tests for token validation |
chore | Wartungsarbeiten | chore(deps): update dependencies |
perf | Leistungsverbesserung | perf(query): add index to users table |
ci | CI/CD-Änderungen | ci: add PostgreSQL service to test workflow |
revert | Commit rückgängig machen | revert: revert "feat(auth): add OAuth2 login" |
Gute vs. schlechte Beispiele
# SCHLECHT: Vage, kein Kontext
git commit -m "Dinge gefixt"
git commit -m "Updates"
git commit -m "WIP"
# GUT: Klar, spezifisch, erklärt das Warum
git commit -m "fix(api): Wiederholungsversuche bei 503 Service Unavailable
Die externe API gibt während Stoßzeiten gelegentlich 503-Fehler zurück.
Exponentielle Backoff-Wiederholungslogik mit max. 3 Versuchen hinzugefügt.
Schließt #123"
Commit-Vorlage
Erstelle .gitmessage im Repository-Root:
# <typ>(<bereich>): <betreff>
# # Typen: feat, fix, docs, style, refactor, test, chore, perf, ci, revert
# Bereich: api, ui, db, auth, etc.
# Betreff: Imperativ, kein Punkt, max. 50 Zeichen
#
# [optionaler body] - erklären warum, nicht was
# [optionaler footer] - Breaking Changes, schließt #issue
Aktivieren mit: git config commit.template .gitmessage
Merge vs. Rebase
Merge (bewahrt Historie)
# Erzeugt einen Merge-Commit
git checkout main
git merge feature/user-auth
# Ergebnis:
# * merge commit
# |\
# | * feature commits
# |/
# * main commits
Verwenden wenn:
- Feature-Branches in
maingemergt werden - Die genaue Historie erhalten bleiben soll
- Mehrere Personen am Branch gearbeitet haben
- Der Branch bereits gepusht wurde und andere darauf aufbauen
Rebase (lineare Historie)
# Schreibt Feature-Commits auf den Ziel-Branch um
git checkout feature/user-auth
git rebase main
# Ergebnis:
# * feature commits (umschrieben)
# * main commits
Verwenden wenn:
- Der lokale Feature-Branch mit dem aktuellen
mainaktualisiert wird - Eine lineare, saubere Historie gewünscht ist
- Der Branch nur lokal existiert (nicht gepusht)
- Man der einzige Entwickler am Branch ist
Rebase-Workflow
# Feature-Branch mit aktuellem main aktualisieren (vor PR)
git checkout feature/user-auth
git fetch origin
git rebase origin/main
# Konflikte beheben
# Tests sollten weiterhin bestehen
# Force-Push (nur, wenn man der einzige Beitragende ist)
git push --force-with-lease origin feature/user-auth
Wann NICHT rebasen
# NIEMALS Branches rebasen, die:
- Bereits in ein gemeinsames Repository gepusht wurden
- Als Basis für die Arbeit anderer dienen
- Geschützte Branches sind (main, develop)
- Bereits gemergt wurden
# Grund: Rebase schreibt Historie um und zerstört die Arbeit anderer
Pull-Request-Workflow
PR-Titel-Format
<typ>(<bereich>): <beschreibung>
Beispiele:
feat(auth): add SSO support for enterprise users
fix(api): resolve race condition in order processing
docs(api): add OpenAPI specification for v2 endpoints
PR-Beschreibungsvorlage
## Was
Kurze Beschreibung, was dieser PR tut.
## Warum
Erklärt die Motivation und den Kontext.
## Wie
Wichtige Implementierungsdetails, die hervorzuheben sind.
## Tests
- [ ] Unit-Tests hinzugefügt/aktualisiert
- [ ] Integrationstests hinzugefügt/aktualisiert
- [ ] Manuelle Tests durchgeführt
## Screenshots (falls zutreffend)
Vorher/Nachher-Screenshots für UI-Änderungen.
## Checkliste
- [ ] Code folgt den Projektstilrichtlinien
- [ ] Selbst-Review abgeschlossen
- [ ] Kommentare für komplexe Logik hinzugefügt
- [ ] Dokumentation aktualisiert
- [ ] Keine neuen Warnungen eingeführt
- [ ] Tests bestehen lokal
- [ ] Verwandte Issues verlinkt
Schließt #123
Code-Review-Checkliste
Für Reviewer:
- Löst der Code das genannte Problem?
- Werden Randfälle nicht behandelt?
- Ist der Code lesbar und wartbar?
- Gibt es ausreichend Tests?
- Gibt es Sicherheitsbedenken?
- Ist die Commit-Historie sauber (falls nötig gesquashed)?
Für Autoren:
- Selbst-Review vor dem Anfordern eines Reviews abgeschlossen
- CI besteht (Tests, Lint, Typecheck)
- PR-Größe ist angemessen (<500 Zeilen ideal)
- Bezieht sich auf eine einzelne Funktion/Fehlerbehebung
- Beschreibung erklärt die Änderung klar
Konfliktlösung
Konflikte identifizieren
# Vor dem Merge auf Konflikte prüfen
git checkout main
git merge feature/user-auth --no-commit --no-ff
# Bei Konflikten zeigt Git an:
# CONFLICT (content): Merge conflict in src/auth/login.ts
# Automatischer Merge fehlgeschlagen; Konflikte beheben und dann Ergebnis committen.
Konflikte lösen
# Konfliktdateien anzeigen
git status
# Konfliktmarkierungen in der Datei anzeigen
# <<<<<<< HEAD
# Inhalt aus main
# =======
# Inhalt aus Feature-Branch
# >>>>>>> feature/user-auth
# Option 1: Manuelle Auflösung
# Datei bearbeiten, Markierungen entfernen, korrekten Inhalt behalten
# Option 2: Merge-Tool verwenden
git mergetool
# Option 3: Eine Seite übernehmen
git checkout --ours src/auth/login.ts # main-Version behalten
git checkout --theirs src/auth/login.ts # Feature-Version behalten
# Nach der Auflösung, stagen und committen
git add src/auth/login.ts
git commit
Strategien zur Konfliktvermeidung
# 1. Feature-Branches klein und kurzlebig halten
# 2. Häufig auf main rebasen
git checkout feature/user-auth
git fetch origin
git rebase origin/main
# 3. Kommunikation im Team bezüglich gemeinsam genutzter Dateien
# 4. Feature Flags statt langlebiger Branches verwenden
# 5. PRs zeitnah reviewen und mergen
Branch-Verwaltung
Namenskonventionen
# Feature-Branches
feature/user-authentication
feature/JIRA-123-payment-integration
# Fehlerbehebungen
fix/login-redirect-loop
fix/456-null-pointer-exception
# Hotfixes (Produktionsprobleme)
hotfix/critical-security-patch
hotfix/database-connection-leak
# Releases
release/1.2.0
release/2024-01-hotfix
# Experimente/PoCs
experiment/new-caching-strategy
poc/graphql-migration
Branch-Bereinigung
# Gemergte lokale Branches löschen
git branch --merged main | grep -v "^\*\|main" | xargs -n 1 git branch -d
# Remote-Tracking-Referenzen für gelöschte Remote-Branches entfernen
git fetch -p
# Lokalen Branch löschen
git branch -d feature/user-auth # Sicheres Löschen (nur wenn gemergt)
git branch -D feature/user-auth # Erzwungenes Löschen
# Remote-Branch löschen
git push origin --delete feature/user-auth
Stash-Workflow
# Arbeit in Arbeit speichern
git stash push -m "WIP: Benutzerauthentifizierung"
# Stashes auflisten
git stash list
# Neuesten Stash anwenden
git stash pop
# Bestimmten Stash anwenden
git stash apply stash@{2}
# Stash löschen
git stash drop stash@{0}
Release-Verwaltung
Semantische Versionierung
MAJOR.MINOR.PATCH
MAJOR: Breaking Changes
MINOR: Neue Funktionen, abwärtskompatibel
PATCH: Fehlerbehebungen, abwärtskompatibel
Beispiele:
1.0.0 → 1.0.1 (patch: Fehlerbehebung)
1.0.1 → 1.1.0 (minor: neue Funktion)
1.1.0 → 2.0.0 (major: Breaking Change)
Releases erstellen
# Annotierten Tag erstellen
git tag -a v1.2.0 -m "Release v1.2.0
Features:
- Benutzerauthentifizierung hinzugefügt
- Passwort-Reset implementiert
Fehlerbehebungen:
- Login-Weiterleitungsproblem behoben
Breaking Changes:
- Keine"
# Tag zu Remote pushen
git push origin v1.2.0
# Tags auflisten
git tag -l
# Tag löschen
git tag -d v1.2.0
git push origin --delete v1.2.0
Changelog-Generierung
# Changelog aus Commits generieren
git log v1.1.0..v1.2.0 --oneline --no-merges
# Oder conventional-changelog verwenden
npx conventional-changelog -i CHANGELOG.md -s
Git-Konfiguration
Wichtige Konfigurationen
# Benutzeridentität
git config --global user.name "Dein Name"
git config --global user.email "[email protected]"
# Standard-Branch-Name
git config --global init.defaultBranch main
# Pull-Verhalten (Rebase statt Merge)
git config --global pull.rebase true
# Push-Verhalten (nur aktuellen Branch pushen)
git config --global push.default current
# Tippfehler automatisch korrigieren
git config --global help.autocorrect 1
# Besseren Diff-Algorithmus
git config --global diff.algorithm histogram
# Farbausgabe
git config --global color.ui auto
Nützliche Aliase
# In ~/.gitconfig hinzufügen
[alias]
co = checkout
br = branch
ci = commit
st = status
unstage = reset HEAD --
last = log -1 HEAD
visual = log --oneline --graph --all
amend = commit --amend --no-edit
wip = commit -m "WIP"
undo = reset --soft HEAD~1
contributors = shortlog -sn
Gitignore-Muster
# Abhängigkeiten
node_modules/
vendor/
# Build-Ausgaben
dist/
build/
*.o
*.exe
# Umgebungsdateien
.env
.env.local
.env.*.local
# IDE
.idea/
.vscode/
*.swp
*.swo
# Betriebssystemdateien
.DS_Store
Thumbs.db
# Logs
*.log
logs/
# Testabdeckung
coverage/
# Cache
.cache/
*.tsbuildinfo
Häufige Workflows
Eine neue Funktion starten
# 1. main-Branch aktualisieren
git checkout main
git pull origin main
# 2. Feature-Branch erstellen
git checkout -b feature/user-auth
# 3. Änderungen vornehmen und committen
git add .
git commit -m "feat(auth): implement OAuth2 login"
# 4. Zu Remote pushen
git push -u origin feature/user-auth
# 5. Pull Request auf GitHub/GitLab erstellen
Einen PR mit neuen Änderungen aktualisieren
# 1. Weitere Änderungen vornehmen
git add .
git commit -m "feat(auth): add error handling"
# 2. Updates pushen
git push origin feature/user-auth
Fork mit Upstream synchronisieren
# 1. Upstream-Remote hinzufügen (einmalig)
git remote add upstream https://github.com/original/repo.git
# 2. Upstream abrufen
git fetch upstream
# 3. upstream/main in den eigenen main mergen
git checkout main
git merge upstream/main
# 4. Zum eigenen Fork pushen
git push origin main
Fehler rückgängig machen
# Letzten Commit rückgängig machen (Änderungen behalten)
git reset --soft HEAD~1
# Letzten Commit rückgängig machen (Änderungen verwerfen)
git reset --hard HEAD~1
# Letzten Commit, der bereits gepusht wurde, rückgängig machen
git revert HEAD
git push origin main
# Bestimmte Dateiänderungen rückgängig machen
git checkout HEAD -- pfad/zur/datei
# Letzte Commit-Nachricht korrigieren
git commit --amend -m "Neue Nachricht"
# Vergessene Datei zum letzten Commit hinzufügen
git add vergessene-datei
git commit --amend --no-edit
Git-Hooks
Pre-Commit-Hook
#!/bin/bash
# .git/hooks/pre-commit
# Linting ausführen
npm run lint || exit 1
# Tests ausführen
npm test || exit 1
# Nach Geheimnissen suchen
if git diff --cached | grep -E '(password|api_key|secret)'; then
echo "Mögliches Geheimnis erkannt. Commit abgebrochen."
exit 1
fi
Pre-Push-Hook
#!/bin/bash
# .git/hooks/pre-push
# Vollständige Testsuite ausführen
npm run test:all || exit 1
# Nach console.log-Anweisungen suchen
if git diff origin/main | grep -E 'console\.log'; then
echo "Entferne console.log-Anweisungen vor dem Pushen."
exit 1
fi
Anti-Patterns
# SCHLECHT: Direkt in main committen
git checkout main
git commit -m "fix bug"
# GUT: Feature-Branches und PRs verwenden
# SCHLECHT: Geheimnisse committen
git add .env # Enthält API-Schlüssel
# GUT: Zu .gitignore hinzufügen, Umgebungsvariablen verwenden
# SCHLECHT: Riesige PRs (1000+ Zeilen)
# GUT: In kleinere, fokussierte PRs aufteilen
# SCHLECHT: "Update"-Commit-Nachrichten
git commit -m "update"
git commit -m "fix"
# GUT: Beschreibende Nachrichten
git commit -m "fix(auth): resolve redirect loop after login"
# SCHLECHT: Öffentliche Historie umschreiben
git push --force origin main
# GUT: Revert für öffentliche Branches verwenden
git revert HEAD
# SCHLECHT: Langlebige Feature-Branches (Wochen/Monate)
# GUT: Branches kurz halten (Tage), häufig rebasen