Zum Inhalt springen
sw
en

Tippe um zu suchen

Automatisierung & DevOps

Git fuer IT-Admins: Workflows, Branching und Merge-Konflikte

Git-Grundkonzepte, Branching-Modelle, Konfigs versionieren und Merge-Konflikte in YAML/JSON sauber loesen – fuer den IT-Alltag im KMU.

14 Min Lesezeit Fortgeschritten Zuletzt aktualisiert:

Warum Git auch fuer Admins Pflicht ist

Git gilt vielen als “Entwickler-Werkzeug” – dabei landet es in jedem KMU frueher oder later auch auf dem Schreibtisch der IT: Ansible-Playbooks, Terraform-State-Konfigurationen, GPO-Backups, Netzwerk-Configs von Firewalls, PowerShell-Skript-Sammlungen, Dokumentation als Markdown. Sobald mehr als eine Person an denselben Dateien arbeitet oder du nachvollziehen willst, wer wann was geaendert hat, brauchst du Versionierung. Und die beste, am weitesten verbreitete Loesung dafuer ist Git.

Der Unterschied zum Entwickler-Alltag: Du versionierst selten Anwendungscode, sondern Konfigurationsdateien, Skripte und Infrastructure-as-Code (siehe Infrastructure-as-Code im Werkzeug-Vergleich). Das bedeutet andere Schwerpunkte – weniger komplexe Feature-Branches mit hundert Commits, dafuer mehr Fokus auf Nachvollziehbarkeit, saubere Konfliktloesung in strukturierten Dateien (YAML, JSON, INI) und striktes Vermeiden von Secrets im Repository.

Dieser Artikel geht davon aus, dass du git clone, git add, git commit und git push schon mal getippt hast. Wir steigen direkt in Branching-Strategien, Merge-Konflikte und Praxis-Workflows fuer Infrastruktur-Teams ein.


Kurzer Grundlagen-Refresher

Drei Konzepte, die du fuer den Rest des Artikels sicher haben solltest:

  • Commit: ein unveraenderlicher Schnappschuss des gesamten Repository-Zustands zu einem Zeitpunkt, identifiziert durch einen SHA-1-Hash (z. B. a3f5c9e). Jeder Commit verweist auf seinen/seine Elternteil(e) – daraus ergibt sich der Verlauf als gerichteter azyklischer Graph (DAG).
  • Branch: nichts weiter als ein beweglicher Zeiger auf einen Commit. main ist kein besonderer Branch-Typ, sondern nur ein ueblicher Name. Das macht Branches in Git extrem billig – Erstellen kostet Millisekunden, kein Kopieren von Dateien.
  • Remote: ein Verweis auf ein anderes Repository (z. B. origin auf deinem Gitea-Server). Dein lokales Repo und das Remote synchronisieren sich explizit ueber fetch, pull und push – nichts passiert automatisch im Hintergrund.
# Status und Verlauf schnell im Blick
git status
git log --oneline --graph --all -n 20

# Ein Remote-Repository hinzufuegen
git remote add origin https://git.firma.ch/it/netzwerk-configs.git

# Aktuellen Stand holen, ohne zu mergen
git fetch origin

# Unterschied zwischen lokalem und Remote-Branch
git diff main origin/main

Branching-Modelle: Trunk-based vs. Git-Flow

Die Wahl der Branching-Strategie entscheidet, wie dein Team parallel arbeitet, ohne sich staendig in die Quere zu kommen. Fuer IT-Infrastruktur-Repos ist das nicht nur akademisch – falsche Strategie bedeutet in der Praxis: veraltete Configs landen versehentlich in Produktion, oder Aenderungen haengen wochenlang in nie gemergten Branches fest.

Trunk-based Development

Ein einziger langlebiger Branch (main, historisch auch trunk), auf den alle direkt oder ueber sehr kurzlebige Feature-Branches (Lebensdauer: Stunden bis maximal 1-2 Tage) committen. Kein develop-Branch, keine Release-Branches im klassischen Sinn.

# Trunk-based: kurzer Feature-Branch, schnell zurueck in main
git switch -c fix/dhcp-scope-erweitern
# ... Aenderung an dhcp-config.yaml ...
git add dhcp-config.yaml
git commit -m "DHCP-Scope VLAN20 auf /23 erweitert (Ticket #4521)"
git switch main
git pull origin main
git merge fix/dhcp-scope-erweitern
git push origin main
git branch -d fix/dhcp-scope-erweitern

Vorteile: wenig Merge-Aufwand, standig integrierte Aenderungen, passt hervorragend zu CI/CD-Pipelines, die bei jedem Push auf main automatisch testen und ausrollen. Nachteil: erfordert Disziplin – kaputte Commits landen schnell direkt im Haupt-Branch, wenn niemand Code-Reviews via Pull-Request erzwingt.

Git-Flow

Das klassische Modell von Vincent Driessen (2010): zwei langlebige Branches (main fuer Produktivstand, develop fuer laufende Integration) plus temporaere feature/*-, release/*- und hotfix/*-Branches.

# Git-Flow: Feature von develop abzweigen
git switch develop
git switch -c feature/vpn-split-tunneling
# ... Arbeit ...
git switch develop
git merge --no-ff feature/vpn-split-tunneling

# Release vorbereiten
git switch -c release/2026.3 develop
# ... letzte Fixes, Versionsnummer hochziehen ...
git switch main
git merge --no-ff release/2026.3
git tag -a v2026.3 -m "Release 2026.3"
git switch develop
git merge --no-ff release/2026.3

# Hotfix direkt ab main
git switch -c hotfix/cert-expiry main
# ... Fix ...
git switch main
git merge --no-ff hotfix/cert-expiry
git switch develop
git merge --no-ff hotfix/cert-expiry

Vorteile: klare Trennung zwischen “was laeuft produktiv” und “was ist in Arbeit”, saubere Release-Historie mit Tags. Nachteil: mehr administrativer Aufwand, mehr Merge-Punkte, mehr Potenzial fuer divergierende Branches, die auseinanderlaufen.

Entscheidungstabelle

KriteriumTrunk-basedGit-Flow
Team-Groesse1-8 Personen, hohe Vertrautheitgroessere Teams, mehrere parallele Release-Linien
Release-Rhythmuskontinuierlich (mehrmals taeglich moeglich)geplante Releases, Versionsnummern
CI/CD-Reifehoch – automatisierte Tests zwingendoptional, oft manuelle Freigaben
Typischer Anwendungsfall im KMU-IT-KontextAnsible-Playbooks, die staendig gegen Live-Inventar laufenFirewall-/Netzwerk-Configs mit geplanten Wartungsfenstern
Rollback-Komplexitaeteinfach (revert des letzten Commits)mittel (Hotfix-Branch noetig)
Lernkurveniedrigmittel bis hoch

Ein dritter Weg: GitHub Flow (leichtgewichtig)

Fuer viele Infrastruktur-Repos ist GitHub Flow der pragmatische Mittelweg: ein main-Branch, jede Aenderung ueber einen Feature-Branch und einen Pull-Request, nach Review und (wo vorhanden) automatischem Test direkt gemergt. Kein develop, keine Release-Branches – aber im Gegensatz zu reinem Trunk-based ist der PR mit Review verpflichtend.

main ──●──●──●──●──●──●──●──►
        \        /  \    /
         feature/x  feature/y

Merge-Konflikte in YAML/JSON-Configs loesen

Konflikte in strukturierten Konfigurationsdateien sind der Alltag im Infrastruktur-Kontext – und leider genau die Dateiformate, bei denen ein falsch geloester Konflikt (kaputte Einrueckung, doppelter Key) erst beim naechsten ansible-playbook-Lauf oder kubectl apply auffaellt.

Wie ein Konflikt entsteht und aussieht

Ein Konflikt tritt auf, wenn zwei Branches dieselben Zeilen unterschiedlich geaendert haben und Git nicht automatisch entscheiden kann, welche Version gilt. Git markiert die betroffene Stelle direkt in der Datei:

# inventory/group_vars/webserver.yaml
webserver:
  vars:
<<<<<<< HEAD
    nginx_worker_processes: 4
    max_connections: 2048
=======
    nginx_worker_processes: 8
    max_connections: 4096
>>>>>>> feature/perf-tuning
    timeout: 30

Die Markierungen bedeuten:

  • Alles zwischen <<<<<<< HEAD und ======= ist der Stand deines aktuellen Branches.
  • Alles zwischen ======= und >>>>>>> feature/perf-tuning ist der Stand des Branches, den du gerade mergst.
  • Zeilen ausserhalb der Marker sind unveraendert und identisch in beiden Versionen.

Schritt-fuer-Schritt-Ablauf

  1. Konflikt erkennen: git status zeigt “both modified” fuer betroffene Dateien.
  2. Datei oeffnen und die Konfliktmarker verstehen – nicht blind eine Seite loeschen, sondern inhaltlich pruefen, was fachlich richtig ist (hier z. B.: reicht nginx_worker_processes: 8 fuer die Hardware, oder war 4 bewusst wegen begrenztem RAM gesetzt?).
  3. Entscheiden und bereinigen: die gewuenschte(n) Zeile(n) behalten, alle drei Marker-Zeilen (<<<<<<<, =======, >>>>>>>) vollstaendig entfernen.
  4. YAML/JSON-Syntax validieren, bevor du committest (siehe unten).
  5. Staging: git add inventory/group_vars/webserver.yaml.
  6. Merge abschliessen: git commit (bei einem laufenden Merge reicht git commit ohne -m, Git generiert eine Merge-Commit-Message).
# Konflikt-Status pruefen
git status

# Alle Dateien mit Konflikten auflisten
git diff --name-only --diff-filter=U

# YAML nach der Bereinigung validieren
python -c "import yaml, sys; yaml.safe_load(open('inventory/group_vars/webserver.yaml'))" && echo "YAML OK"

# JSON validieren
python -m json.tool config/appsettings.json > $null

# Merge abschliessen
git add inventory/group_vars/webserver.yaml
git commit

Merge-Strategien und Tools, die helfen

# diff3-Konfliktstil aktiviert zusaetzlich den gemeinsamen Vorfahren
git config --global merge.conflictstyle diff3
# Ergebnis zeigt zusaetzlich einen |||||||-Block mit dem Original vor beiden Aenderungen

# Externes Merge-Tool oeffnen (z. B. VS Code)
git config --global merge.tool vscode
git config --global mergetool.vscode.cmd 'code --wait $MERGED'
git mergetool

# Bei mehreren gleichartigen Konflikten: eine Seite komplett bevorzugen
git checkout --ours  config/netzwerk.yaml   # eigene Version behalten
git checkout --theirs config/netzwerk.yaml  # eingehende Version behalten
git add config/netzwerk.yaml

Rebase statt Merge – wann das sinnvoller ist

git rebase schreibt deine lokalen Commits auf den aktuellen Stand von main um, statt einen zusaetzlichen Merge-Commit zu erzeugen. Das ergibt eine lineare, leichter lesbare Historie – kostet aber, dass du denselben Konflikt unter Umstaenden mehrfach loesen musst, einmal pro betroffenem Commit.

git switch feature/dns-umzug
git rebase main
# Bei Konflikt: Datei bereinigen, dann
git add dns-records.yaml
git rebase --continue
# Bei Bedarf komplett abbrechen und zuruecksetzen:
git rebase --abort

Git fuer Infrastruktur-Configs: Praxis-Setup

Ein sauberes Infra-Repo unterscheidet sich von einem App-Code-Repo vor allem durch Sensitivitaet der Inhalte und durch die Kopplung an reale Systeme. Ein paar bewaehrte Muster:

Repo-Struktur fuer Config-Verwaltung

netzwerk-configs/
├── .gitignore
├── .pre-commit-config.yaml
├── ansible/
│   ├── inventory/
│   │   ├── production.yaml
│   │   └── group_vars/
│   ├── playbooks/
│   └── roles/
├── terraform/
│   ├── environments/
│   │   ├── prod/
│   │   └── test/
│   └── modules/
├── configs/
│   ├── firewall/
│   │   └── fortigate-branch01.conf
│   └── switches/
│       └── core-switch-01.yaml
└── README.md

Wichtig: environmentspezifische Werte (Prod vs. Test) klar trennen, entweder per Verzeichnis oder per Branch – nie per unkommentiertem Kommentarblock in derselben Datei, den man beim Deploy “schnell mal” umschaltet.

Commit-Konventionen fuer Nachvollziehbarkeit

Bei Infra-Configs ist die Commit-Message oft die einzige Doku dazu, warum etwas geaendert wurde. Ein Format wie Conventional Commits hilft, spaeter automatisiert Changelogs zu bauen oder gezielt zu suchen:

git commit -m "fix(dhcp): Scope VLAN20 auf /23 erweitert (Ticket #4521)"
git commit -m "feat(vpn): Split-Tunneling fuer Aussendienst aktiviert"
git commit -m "chore(ansible): inventory auf neue Filialserver erweitert"
git commit -m "docs(firewall): Regelwerk-Kommentare ergaenzt fuer Audit"

Aenderungen nachvollziehen: blame, bisect, tag

# Wer hat wann welche Zeile geaendert – und warum?
git blame -L 40,55 ansible/playbooks/deploy-webserver.yaml

# Welcher Commit hat einen Fehler eingefuehrt? Git sucht binaer.
git bisect start
git bisect bad                  # aktueller Stand ist fehlerhaft
git bisect good v2026.1          # dieser Tag/Commit war noch gut
# Git checkt automatisch die Mitte aus, du testest und markierst:
git bisect good   # oder: git bisect bad
git bisect reset  # Suche beenden, zurueck zum Ausgangs-Branch

# Stabile Konfig-Staende markieren – wichtig vor grossen Wartungsfenstern
git tag -a pre-migration-2026-07 -m "Stand vor Exchange-Hybrid-Migration"
git push origin pre-migration-2026-07

Secrets vermeiden: .gitignore und Pre-Commit-Hooks

Der teuerste Git-Fehler im Infrastruktur-Alltag: ein API-Key, ein Domain-Admin-Passwort oder eine .pfx-Zertifikatsdatei landet versehentlich im Commit – und damit dauerhaft in der Historie, selbst wenn die Datei im naechsten Commit wieder geloescht wird.

.gitignore richtig einsetzen

# Secrets und Zugangsdaten
*.pem
*.key
*.pfx
*.p12
secrets.yaml
.env
.env.*
!*.env.example

# Terraform State (enthaelt oft sensible Werte im Klartext!)
*.tfstate
*.tfstate.backup
.terraform/
*.tfvars
!*.tfvars.example

# Ansible Vault-Passwortdateien
.vault_pass
vault_password.txt

# Editor- und OS-Muell
.vscode/
.idea/
Thumbs.db
.DS_Store

Terraform-State separat behandeln

Ein haeufiger Anfaengerfehler: terraform.tfstate landet im Repo, weil es “ja nur Infrastruktur-Zustand” ist. Tatsaechlich stehen dort oft Passwoerter und Zugriffsschluessel im Klartext. Details zum sauberen Umgang mit State (Remote Backend, Locking, Drift) findest du unter Terraform State Management und Drift.

Pre-Commit-Hooks: Secrets vor dem Commit abfangen

Ein Pre-Commit-Hook laeuft lokal, bevor ein Commit ueberhaupt entsteht – das Secret landet dann gar nicht erst in der Historie. Das Python-basierte Framework pre-commit mit dem Scanner gitleaks ist ein bewaehrter Standard:

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.21.2
    hooks:
      - id: gitleaks

  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.6.0
    hooks:
      - id: check-yaml
      - id: check-json
      - id: end-of-file-fixer
      - id: trailing-whitespace
      - id: detect-private-key
# Installation (einmalig pro Maschine)
pip install pre-commit
pre-commit install    # richtet den Git-Hook lokal ein

# Manuell gegen das ganze Repo laufen lassen (z. B. bei Erst-Einrichtung)
pre-commit run --all-files
ToolStaerkeEinsatzort
gitleaksschnell, breite Musterabdeckung, gute CI-IntegrationPre-Commit + CI-Pipeline
git-secrets (AWS)sehr leichtgewichtig, Fokus auf AWS-PatternPre-Commit, wenn primaer AWS-Keys relevant sind
detect-secrets (Yelp)Baseline-Datei gegen Alert-Flut bei Altbestandgrosse, gewachsene Repos
trufflehogerkennt zusaetzlich, ob ein Secret noch aktiv/gueltig istperiodischer History-Scan, Incident Response

Self-hosted (Gitea/Forgejo) vs. GitHub/GitLab

Fuer ein Schweizer KMU ist die Wahl der Git-Plattform auch eine Frage von Datenschutz (nDSG/DSGVO, siehe DSGVO/nDSG in der IT-Praxis), Betriebsaufwand und Budget.

Die Optionen im Ueberblick

  • GitHub / GitLab.com (SaaS): kein eigener Betrieb, aber Daten liegen bei einem US-Anbieter (Microsoft/GitHub bzw. GitLab Inc.) – bei sensiblen Infrastruktur-Configs ein Abwaegungspunkt.
  • GitLab CE/EE self-hosted: volles DevOps-Paket (CI/CD, Container-Registry, Security-Scanning) inklusive, aber deutlich ressourcenhungriger im Betrieb – mehrere Gigabyte RAM, PostgreSQL, Redis, mehrere Hintergrunddienste.
  • Gitea: leichtgewichtige, in Go geschriebene Einzelbinary-Loesung, laeuft problemlos auf einem kleinen VM mit 1-2 GB RAM.
  • Forgejo: 2022 als Fork von Gitea entstanden (Reaktion auf die kommerzielle Neuausrichtung der Gitea-Organisation), seit 2024 ein eigenstaendiger Hard Fork unter Foundation-Governance (dieselbe Non-Profit-Struktur wie hinter Codeberg). Technisch sehr nah an Gitea, aber mit eigenem Actions-System (kompatibel zu GitHub-Actions-Syntax) und schnellerer Feature-Uebernahme aus der Community.

Entscheidungstabelle

KriteriumGitHub/GitLab SaaSGitLab self-hostedGiteaForgejo
Betriebsaufwandkeinerhoch (mehrere Dienste, Updates)niedrig (Einzelbinary)niedrig (Einzelbinary)
Ressourcenbedarfab ca. 4 GB RAMab ca. 512 MB-1 GB RAMab ca. 512 MB-1 GB RAM
Datenhoheitbeim Anbietervollstaendig eigenvollstaendig eigenvollstaendig eigen
CI/CD integriertja (Actions/Pipelines)ja (sehr umfangreich)eingeschraenkt (Gitea Actions)ja (Forgejo Actions, GH-Actions-kompatibel)
Governancekommerziellkommerziell (Open-Core)kommerziell (Gitea Ltd.)Non-Profit/Community
Passend fuerkleine Teams ohne Compliance-ZwangUnternehmen mit vollem DevOps-Anspruchschlanke KMU-Loesung, Config-Backupschlanke KMU-Loesung mit aktiver Community

Entscheidungshilfe fuer den KMU-Alltag

Brauchst du volles CI/CD, Security-Scanning, Compliance-Reporting out of the box?
├── Ja  → GitLab (self-hosted, wenn Daten im Haus bleiben muessen; sonst SaaS)
└── Nein
    ├── Reicht ein schlanker Git-Server fuer Configs + einfache Pull-Requests?
    │   ├── Community-Governance wichtig / zukunftssicher? → Forgejo
    │   └── Etablierte Marke, viele Third-Party-Integrationen? → Gitea
    └── Kein eigener Betrieb gewuenscht, Cloud-Bindung akzeptabel? → GitHub/GitLab SaaS

Haeufige Stolperfallen im Admin-Alltag

ProblemUrsacheLoesung
Zeilenumbrueche aendern sich staendig (CRLF/LF)Windows-Editor speichert mit CRLF, Linux-Server erwartet LFgit config --global core.autocrlf true (Windows) bzw. .gitattributes mit * text=auto
”detached HEAD” nach Checkout eines TagsTag zeigt auf Commit, nicht auf Branchgit switch -c hotfix-aus-tag direkt nach dem Checkout, um weiterzuarbeiten
Grosse Binärdateien (Firmware-Images, ISOs) blaehen Repo aufGit ist fuer Textdiffs optimiert, nicht fuer BinaerdatenGit LFS nutzen oder Binaerdateien in separatem Artefakt-Speicher (z. B. Nexus, R2-Bucket) halten
Merge-Konflikt in terraform.tfstateState wurde versehentlich versioniert statt in Remote Backend gehaltenState nie versionieren – Remote Backend mit Locking einrichten, siehe Terraform State Management
Force-Push ueberschreibt Kollegen-Commitsgit push --force auf geteiltem Branch nach Rebasegit push --force-with-lease verwenden, Branch-Schutzregeln auf dem Server aktivieren

Weiterlernen

Videos

YouTube
Branch-Strategien für Git // deutsch

Kommentare

Frage, Verbesserungsvorschlag oder eigene Erfahrung zu diesem Artikel? Schreib einen Kommentar. Neue Beiträge erscheinen nach kurzer Moderation.

  • Lade Kommentare …
Kommentar schreiben