Przejdź do treści
Anleitungen

Git - Fortgeschrittene Techniken und Workflow

Veröffentlicht am:
·6 Min. Lesezeit·Autor: MDS Software Solutions Group
Git - Fortgeschrittene Techniken und Workflow

Git - Fortgeschrittene Techniken und Workflow

Git ist mit Abstand das beliebteste Versionskontrollsystem der Welt. Die meisten Entwickler kennen die Grundlagen - git add, git commit, git push - aber die wahre Staerke von Git liegt in fortgeschrittenen Techniken, die die Teamproduktivitaet radikal verbessern koennen. In diesem Artikel besprechen wir Branching-Strategien, fortgeschrittene Befehle, Automatisierung mit Hooks, Commit-Konventionen und vieles mehr.

Branching-Strategien#

Die Wahl der richtigen Branching-Strategie ist eine der wichtigsten architektonischen Entscheidungen in einem Projekt. Jede populaere Strategie hat ihre Vor- und Nachteile, und die Wahl sollte von der Teamgroesse, der Deployment-Haeufigkeit und den Projektspezifika abhaengen.

Git Flow#

Git Flow ist eine klassische Strategie, die von Vincent Driessen vorgeschlagen wurde. Sie basiert auf zwei Hauptbranches - main (Produktion) und develop (Entwicklung) - sowie drei Typen von unterstuetzenden Branches.

# Git Flow initialisieren
git flow init

# Neues Feature starten
git flow feature start login-page

# Am Feature arbeiten
git add .
git commit -m "feat: add login form component"

# Feature abschliessen - in develop mergen
git flow feature finish login-page

# Release starten
git flow release start 1.2.0

# Release abschliessen - in main und develop mergen
git flow release finish 1.2.0

# Produktions-Hotfix
git flow hotfix start fix-auth-bug
git flow hotfix finish fix-auth-bug

Vorteile von Git Flow:

  • Klare Trennung von Produktions- und Entwicklungscode
  • Funktioniert gut mit geplanten Release-Zyklen
  • Einfaches Hotfix-Management

Nachteile von Git Flow:

  • Komplexitaet - viele Branches zu verwalten
  • Lange Integrationszyklen koennen zu Konflikten fuehren
  • Nicht geeignet fuer CI/CD mit haeufigen Deployments

Trunk Based Development#

Trunk Based Development (TBD) ist ein Ansatz, bei dem alle Entwickler an einem einzigen Hauptbranch arbeiten. Kurzlebige Feature-Branches (maximal 1-2 Tage) werden schnell zurueck in den Trunk gemergt.

# Kurzlebigen Feature-Branch erstellen
git checkout -b feature/add-search main

# Schnelle Iteration - kleine Commits
git commit -m "feat: add search input component"
git commit -m "feat: add search API integration"

# Haeufiges Rebase auf main
git fetch origin
git rebase origin/main

# Schneller Merge zurueck nach main
git checkout main
git merge feature/add-search
git push origin main

# Feature Flags verwenden, um unfertige Features zu verbergen
# if (featureFlags.isEnabled('new-search')) { ... }

Vorteile von TBD:

  • Minimiert Merge-Konflikte
  • Ideal fuer CI/CD
  • Erzwingt kleine, haeufige Commits

Nachteile von TBD:

  • Erfordert ein erfahrenes Team und gute Praktiken
  • Notwendigkeit der Verwendung von Feature Flags
  • Schwierigere Verwaltung mehrerer Versionen

GitHub Flow#

GitHub Flow ist eine vereinfachte Version, ideal fuer Open-Source-Projekte und Teams, die Continuous Delivery praktizieren.

# Branch von main erstellen
git checkout -b feature/user-dashboard main

# Arbeit und Commits
git add .
git commit -m "feat: add user dashboard layout"
git push -u origin feature/user-dashboard

# Pull Request auf GitHub erstellen
gh pr create --title "Add user dashboard" --body "Implements #42"

# Nach Review und Genehmigung - Merge ueber Weboberflaeche
# oder ueber die Kommandozeile
gh pr merge --squash

Wann welche Strategie waehlen?

| Kriterium | Git Flow | TBD | GitHub Flow | |-----------|----------|-----|-------------| | Teamgroesse | Grosse Teams | Klein-mittel | Klein-mittel | | Release-Zyklus | Geplant | Kontinuierlich | Kontinuierlich | | Komplexitaet | Hoch | Niedrig | Niedrig | | CI/CD | Optional | Erforderlich | Empfohlen |

Interactive Rebase - Geschichte umschreiben#

Interactive Rebase ist eines der maechtigsten Git-Werkzeuge. Es ermoeglicht das Umschreiben der Commit-Geschichte - Zusammenfuegen, Aufteilen, Neuordnen und Bearbeiten von Nachrichten.

# Interaktives Rebase der letzten 5 Commits
git rebase -i HEAD~5

# Rebase auf den main-Branch
git rebase -i main

Im Editor sehen Sie eine Liste von Commits mit verfuegbaren Aktionen:

pick a1b2c3d feat: add user model
pick d4e5f6g fix: typo in user model
pick g7h8i9j feat: add user controller
pick j1k2l3m feat: add user routes
pick m4n5o6p fix: missing import

# Verfuegbare Befehle:
# p, pick = Commit verwenden
# r, reword = Commit verwenden, aber Nachricht bearbeiten
# e, edit = Commit verwenden, aber zum Bearbeiten anhalten
# s, squash = mit vorherigem Commit zusammenfuegen
# f, fixup = wie squash, aber Nachricht verwerfen
# d, drop = Commit entfernen

Typische Anwendungsfaelle:

# Fixes mit dem Haupt-Commit zusammenfuegen (squash)
pick a1b2c3d feat: add user model
fixup d4e5f6g fix: typo in user model
pick g7h8i9j feat: add user controller
pick j1k2l3m feat: add user routes
fixup m4n5o6p fix: missing import

# Commit-Nachricht aendern (reword)
reword a1b2c3d feat: add user model with validation

# Commit in kleinere aufteilen
edit a1b2c3d feat: add user model and controller
# Nach dem Anhalten:
git reset HEAD~1
git add src/models/user.ts
git commit -m "feat: add user model"
git add src/controllers/user.ts
git commit -m "feat: add user controller"
git rebase --continue

Wichtig: Rebasen Sie niemals Commits, die bereits in ein Remote-Repository gepusht und mit anderen Entwicklern geteilt wurden. Das Umschreiben geteilter Geschichte fuehrt zu ernsthaften Problemen.

Cherry-pick - Commits auswaehlen#

Cherry-pick ermoeglicht es, einen einzelnen Commit von einem Branch in einen anderen zu verschieben, ohne den gesamten Branch zu mergen.

# Einzelnen Commit verschieben
git cherry-pick a1b2c3d

# Bereich von Commits verschieben
git cherry-pick a1b2c3d..f6g7h8i

# Cherry-pick ohne automatischen Commit
git cherry-pick --no-commit a1b2c3d

# Konflikte waehrend Cherry-pick loesen
git cherry-pick a1b2c3d
# ... Konflikte loesen ...
git add .
git cherry-pick --continue

# Cherry-pick abbrechen
git cherry-pick --abort

Typische Anwendungsfaelle:

  • Hotfixes zwischen Branches verschieben
  • Selektives Auswaehlen von Aenderungen aus Feature-Branches
  • Backporting von Fixes auf aeltere Versionen

Git Bisect - Binaere Suche nach Bugs#

git bisect hilft, den Commit zu finden, der einen Bug eingefuehrt hat, mittels binaerer Suche. Es ist aeusserst effektiv bei einer langen Commit-Geschichte.

# Bisect-Sitzung starten
git bisect start

# Aktuellen Commit als schlecht markieren
git bisect bad

# Letzten bekannten guten Commit markieren
git bisect good v1.0.0

# Git waehlt einen Commit in der Mitte - testen und markieren
git bisect good  # lub git bisect bad

# Fortfahren, bis Git den schuldigen Commit findet
# ...

# Sitzung beenden
git bisect reset

Bisect mit einem Testskript automatisieren:

# Automatischer Bisect mit einem Testbefehl
git bisect start HEAD v1.0.0
git bisect run npm test

# Bisect mit einem eigenen Skript
git bisect run ./scripts/test-regression.sh

# Das Skript sollte 0 (gut) oder 1 (schlecht) zurueckgeben

Git Stash - Temporaere Speicherung von Aenderungen#

Stash ermoeglicht es, uncommitted Aenderungen voruebergehend beiseite zu legen, um zu anderer Arbeit zu wechseln.

# Einfacher Stash
git stash

# Stash mit Beschreibung
git stash push -m "work in progress: login form"

# Stash einschliesslich neuer Dateien (untracked)
git stash push -u -m "WIP: new feature with new files"

# Gestashte Aenderungen auflisten
git stash list
# stash@{0}: On feature/login: work in progress: login form
# stash@{1}: On main: quick experiment

# Letzten Stash wiederherstellen
git stash pop

# Bestimmten Stash wiederherstellen
git stash pop stash@{1}

# Wiederherstellen ohne aus dem Stash zu entfernen
git stash apply stash@{0}

# Aenderungen im Stash anzeigen
git stash show -p stash@{0}

# Branch aus Stash erstellen
git stash branch feature/from-stash stash@{0}

# Stash loeschen
git stash drop stash@{0}

# Alle gestashten Aenderungen loeschen
git stash clear

Git Worktrees - Paralleles Arbeiten an mehreren Branches#

Worktrees ermoeglichen es, mehrere Branches gleichzeitig in verschiedenen Verzeichnissen ausgecheckt zu haben, die sich ein einzelnes .git-Repository teilen.

# Worktree fuer einen bestehenden Branch hinzufuegen
git worktree add ../project-hotfix hotfix/critical-bug

# Worktree mit einem neuen Branch hinzufuegen
git worktree add -b feature/new-ui ../project-new-ui main

# Aktive Worktrees auflisten
git worktree list
# /home/user/project          a1b2c3d [main]
# /home/user/project-hotfix   d4e5f6g [hotfix/critical-bug]
# /home/user/project-new-ui   g7h8i9j [feature/new-ui]

# In einem separaten Worktree arbeiten
cd ../project-hotfix
git add .
git commit -m "fix: critical auth bypass"
git push origin hotfix/critical-bug

# Zum Hauptverzeichnis zurueckkehren
cd ../project

# Worktree entfernen
git worktree remove ../project-hotfix

# Nicht existierende Worktrees aufraeumen
git worktree prune

Vorteile von Worktrees:

  • Kein Stashen von Aenderungen beim Kontextwechsel noetig
  • Moeglichkeit, verschiedene Branches gleichzeitig zu bauen/testen
  • Geteiltes .git - spart Speicherplatz

Git Submodules - Abhaengigkeitsverwaltung#

Submodules ermoeglichen es, ein Git-Repository in ein anderes als Unterverzeichnis einzubetten.

# Submodul hinzufuegen
git submodule add https://github.com/org/shared-lib.git libs/shared

# Repository mit Submodulen klonen
git clone --recurse-submodules https://github.com/org/main-project.git

# Submodule nach dem Klonen ohne --recurse initialisieren
git submodule init
git submodule update

# Submodul auf die neueste Version aktualisieren
cd libs/shared
git fetch
git checkout v2.0.0
cd ../..
git add libs/shared
git commit -m "chore: update shared-lib to v2.0.0"

# Alle Submodule aktualisieren
git submodule update --remote --merge

# Submodul entfernen
git submodule deinit libs/shared
git rm libs/shared
rm -rf .git/modules/libs/shared

Git Hooks - Prozessautomatisierung#

Hooks sind Skripte, die automatisch als Reaktion auf Git-Ereignisse ausgefuehrt werden. Sie koennen fuer Validierung, Code-Formatierung, Ausfuehren von Tests und viele andere Aufgaben verwendet werden.

Pre-commit Hook#

#!/bin/sh
# .git/hooks/pre-commit

# Code-Formatierung mit Prettier pruefen
echo "Running Prettier check..."
npx prettier --check "src/**/*.{ts,tsx,js,jsx}" || {
    echo "FEHLER: Code ist nicht formatiert. Fuehren Sie aus: npx prettier --write ."
    exit 1
}

# Linter ausfuehren
echo "Running ESLint..."
npx eslint "src/**/*.{ts,tsx}" --max-warnings 0 || {
    echo "FEHLER: ESLint-Fehler. Beheben Sie diese vor dem Commit."
    exit 1
}

# TypeScript-Typen pruefen
echo "Running type check..."
npx tsc --noEmit || {
    echo "FEHLER: TypeScript-Typfehler."
    exit 1
}

echo "All checks passed!"

Commit-msg Hook#

#!/bin/sh
# .git/hooks/commit-msg

commit_msg=$(cat "$1")

# Conventional Commits Format validieren
pattern="^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\(.+\))?: .{1,72}$"

if ! echo "$commit_msg" | head -1 | grep -qE "$pattern"; then
    echo "FEHLER: Commit-Nachricht entspricht nicht den Conventional Commits."
    echo ""
    echo "Format: <Typ>(<Bereich>): <Beschreibung>"
    echo ""
    echo "Typen: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert"
    echo ""
    echo "Beispiele:"
    echo "  feat(auth): add OAuth2 login flow"
    echo "  fix(api): handle null response from payment gateway"
    echo "  docs: update API documentation"
    exit 1
fi

Hooks verwalten mit Husky#

Anstatt Hooks manuell in .git/hooks/ zu verwalten, koennen Sie Husky verwenden:

# Husky installieren
npm install -D husky

# Initialisieren
npx husky init

# Pre-commit Hook hinzufuegen
echo "npx lint-staged" > .husky/pre-commit

# lint-staged Konfiguration in package.json
{
  "lint-staged": {
    "*.{ts,tsx}": ["eslint --fix", "prettier --write"],
    "*.{json,md,yml}": ["prettier --write"]
  }
}

Conventional Commits und Semantic Versioning#

Conventional Commits ist eine Spezifikation fuer die Struktur von Commit-Nachrichten, die automatische Changelog-Generierung und Versionsverwaltung ermoeglicht.

Conventional Commits Format#

<Typ>[optionaler Bereich]: <Beschreibung>

[optionaler Koerper]

[optionale Fussnote(n)]

Commit-Typen und ihr Einfluss auf die Versionierung:

| Typ | Beschreibung | SemVer | |-----|------|--------| | feat | Neues Feature | MINOR (1.x.0) | | fix | Bugfix | PATCH (1.0.x) | | docs | Dokumentation | - | | style | Formatierung | - | | refactor | Refactoring | - | | perf | Performance-Optimierung | PATCH | | test | Tests | - | | build | Build-System | - | | ci | CI-Konfiguration | - | | chore | Sonstiges | - |

Breaking Changes verursachen einen MAJOR-Versionssprung (x.0.0):

feat(api)!: change authentication endpoint response format

BREAKING CHANGE: The /auth/login endpoint now returns
a different JSON structure. See migration guide.

Versionierung automatisieren#

# semantic-release installieren
npm install -D semantic-release @semantic-release/changelog @semantic-release/git

# Konfiguration in .releaserc.json
{
  "branches": ["main"],
  "plugins": [
    "@semantic-release/commit-analyzer",
    "@semantic-release/release-notes-generator",
    "@semantic-release/changelog",
    "@semantic-release/npm",
    "@semantic-release/git"
  ]
}

Monorepo-Strategien#

Monorepo ist ein Ansatz, bei dem mehrere Projekte/Pakete in einem einzigen Repository liegen. Git bietet Werkzeuge, die bei der effizienten Verwaltung solcher Strukturen helfen.

Sparse Checkout#

# Sparse Checkout aktivieren
git sparse-checkout init --cone

# Nur benoetigte Verzeichnisse auswaehlen
git sparse-checkout set packages/frontend packages/shared

# Weiteres Verzeichnis hinzufuegen
git sparse-checkout add packages/backend

# Aktive Verzeichnisse auflisten
git sparse-checkout list

# Sparse Checkout deaktivieren
git sparse-checkout disable

Monorepo-Werkzeuge#

# Turborepo - nur geaenderte Pakete bauen
npx turbo run build --filter=...[HEAD~1]

# Nx - Abhaengigkeitsanalyse
npx nx affected --target=test --base=main

# pnpm Workspaces - Abhaengigkeitsverwaltung
pnpm install --filter @myorg/frontend

Geschichte im Monorepo filtern#

# Logs nur fuer ein bestimmtes Verzeichnis
git log --oneline -- packages/frontend/

# Diff nur fuer ein bestimmtes Paket
git diff main -- packages/api/

# Blame fuer eine Datei in einem Paket
git blame packages/shared/src/utils.ts

Git LFS - Large File Storage#

Git LFS loest das Problem der Speicherung grosser Dateien (Grafiken, 3D-Modelle, Binaerdaten) in Git-Repositories.

# Git LFS installieren
git lfs install

# Grosse Dateien verfolgen
git lfs track "*.psd"
git lfs track "*.zip"
git lfs track "assets/videos/**"

# Konfiguration pruefen
cat .gitattributes
# *.psd filter=lfs diff=lfs merge=lfs -text
# *.zip filter=lfs diff=lfs merge=lfs -text

# .gitattributes zum Repository hinzufuegen
git add .gitattributes
git commit -m "chore: configure Git LFS for binary files"

# Normale Git-Nutzung - LFS arbeitet transparent
git add assets/logo.psd
git commit -m "feat: add new logo design"
git push

# LFS-Status pruefen
git lfs status
git lfs ls-files

Commits signieren (GPG/SSH)#

Das Signieren von Commits ermoeglicht die Verifizierung der Identitaet des Autors und gewaehrleistet die Code-Integritaet.

# GPG-Signierung konfigurieren
gpg --gen-key
gpg --list-secret-keys --keyid-format=long

# Schluessel in Git setzen
git config --global user.signingkey ABC123DEF456
git config --global commit.gpgsign true

# Commit signieren
git commit -S -m "feat: add verified feature"

# Signatur verifizieren
git log --show-signature

# Signierung mit SSH-Schluessel (Git 2.34+)
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub
git config --global commit.gpgsign true

# SSH-Signaturen verifizieren
git config --global gpg.ssh.allowedSignersFile ~/.ssh/allowed_signers
echo "user@example.com ssh-ed25519 AAAA..." >> ~/.ssh/allowed_signers

Die .gitattributes-Datei#

.gitattributes ermoeglicht die Kontrolle darueber, wie Git verschiedene Dateitypen behandelt - von der Zeilenende-Konvertierung bis zu Merge-Strategien.

# Zeilenenden normalisieren
* text=auto

# LF fuer Quelldateien erzwingen
*.js text eol=lf
*.ts text eol=lf
*.tsx text eol=lf
*.json text eol=lf
*.yml text eol=lf
*.md text eol=lf

# Binaerdateien - keine Konvertierung
*.png binary
*.jpg binary
*.gif binary
*.ico binary
*.woff2 binary

# Eigene Merge-Strategie fuer Lock-Dateien
package-lock.json merge=ours
yarn.lock merge=ours
pnpm-lock.yaml merge=ours

# Binaerdateien vergleichen
*.pdf diff=pdf

# Git LFS
*.psd filter=lfs diff=lfs merge=lfs -text

# Export - aus Archiven ausschliessen
.github/ export-ignore
tests/ export-ignore
.gitignore export-ignore

Fortgeschrittene Merge-Strategien#

Git bietet verschiedene Merge-Strategien, die je nach Situation gewaehlt werden koennen.

# Standardstrategie (ort in neueren Versionen)
git merge feature/new-ui

# Merge mit Beibehaltung der Geschichte (no fast-forward)
git merge --no-ff feature/new-ui

# Ours-Strategie - unsere Version behalten
git merge -s ours legacy-branch

# Merge mit Bevorzugung unserer Aenderungen bei Konflikten
git merge -X ours feature/conflicting

# Merge mit Bevorzugung ihrer Aenderungen bei Konflikten
git merge -X theirs feature/external-update

# Squash-Merge - ein Commit aus dem gesamten Branch
git merge --squash feature/many-commits
git commit -m "feat: add complete user management module"

# Octopus-Merge - mehrere Branches gleichzeitig mergen
git merge feature/a feature/b feature/c

Rerere - Geloeste Konflikte merken#

# Rerere aktivieren (aufgezeichnete Loesung wiederverwenden)
git config --global rerere.enabled true

# Git merkt sich, wie Sie Konflikte geloest haben
# und wird automatisch dieselben Loesungen anwenden
# wenn es in Zukunft auf identische Konflikte trifft

# Gemerkte Loesungen anzeigen
git rerere diff

# Rerere-Cache leeren
git rerere forget <plik>

Konflikte loesen#

Konflikte sind in der Teamarbeit unvermeidlich. Hier sind bewaehrte Ansaetze zu ihrer Loesung.

# Konfliktstatus pruefen
git status

# Konflikte in einer Datei anzeigen
# <<<<<<< HEAD
# unsere Version des Codes
# =======
# ihre Version des Codes
# >>>>>>> feature/other-branch

# Merge-Tool verwenden
git mergetool

# Mit einer bestimmten Version loesen
git checkout --ours -- src/config.ts    # unsere Version
git checkout --theirs -- src/config.ts  # ihre Version

# Merge abbrechen
git merge --abort

# Rebase abbrechen
git rebase --abort

Best Practices fuer die Konfliktloesung:

  1. Haeufiges Mergen/Rebasen - je oefter Sie sich mit dem Hauptbranch synchronisieren, desto kleiner die Konflikte
  2. Kleine Commits - es ist einfacher, Konflikte in kleinen Aenderungen zu verstehen und zu loesen
  3. Teamkommunikation - informieren Sie, wenn Sie an gemeinsamen Dateien arbeiten
  4. Visuelle Tools - VS Code, IntelliJ, Beyond Compare erleichtern die Loesung komplexer Konflikte

Nuetzliche Aliase und Konfiguration#

# Nuetzliche Aliase
git config --global alias.lg "log --oneline --graph --all --decorate"
git config --global alias.st "status -sb"
git config --global alias.co "checkout"
git config --global alias.br "branch -vv"
git config --global alias.unstage "reset HEAD --"
git config --global alias.last "log -1 HEAD --stat"
git config --global alias.amend "commit --amend --no-edit"
git config --global alias.wip "commit -am 'WIP: work in progress'"

# Nuetzliche Konfiguration
git config --global pull.rebase true
git config --global push.autoSetupRemote true
git config --global fetch.prune true
git config --global diff.algorithm histogram
git config --global merge.conflictstyle zdiff3
git config --global init.defaultBranch main
git config --global core.autocrlf input

Zusammenfassung#

Fortgeschrittene Git-Techniken koennen die Teamproduktivitaet erheblich verbessern:

  • Branching-Strategien - waehlen Sie Git Flow, Trunk Based Development oder GitHub Flow je nach Projektanforderungen
  • Interactive Rebase - pflegen Sie eine saubere, lesbare Commit-Geschichte
  • Cherry-pick und Bisect - praezises Aenderungsmanagement und Fehlersuche
  • Stash und Worktrees - effizienter Kontextwechsel
  • Hooks - Automatisierung von Validierung und Qualitaetskontrolle
  • Conventional Commits - strukturierte Nachrichten, die Automatisierung ermoeglichen
  • Git LFS - Umgang mit grossen Binaerdateien
  • Commits signieren - Verifizierung von Identitaet und Code-Integritaet

Der Schluessel liegt darin, diese Techniken schrittweise einzufuehren und an die Spezifika Ihres Projekts anzupassen. Sie muessen nicht alles auf einmal verwenden - beginnen Sie mit dem, was Ihrem Team den groessten Nutzen bringt.

Brauchen Sie Unterstuetzung?#

Bei MDS Software Solutions Group helfen wir bei:

  • Gestaltung von Git-Workflows, die auf Ihr Team zugeschnitten sind
  • Konfiguration von CI/CD mit fortgeschrittenen Branching-Strategien
  • Implementierung von Conventional Commits und automatischer Versionierung
  • Migration zu Monorepo und Optimierung grosser Repositories
  • Schulungen in fortgeschrittenen Git-Techniken

Kontaktieren Sie uns, um Ihr Projekt zu besprechen!

Autor
MDS Software Solutions Group

Team von Programmierexperten, die sich auf moderne Webtechnologien spezialisiert haben.

Git - Fortgeschrittene Techniken und Workflow | MDS Software Solutions Group | MDS Software Solutions Group