Eintrag

GitLab: Git-Workflow und Teamarbeit in der Praxis

GitLab: Git-Workflow und Teamarbeit in der Praxis

Git ist das Rückgrat moderner Softwareentwicklung. Egal ob du alleine an einem Homelab-Projekt arbeitest oder im Team eine Anwendung entwickelst – ohne Versionskontrolle geht nichts. GitLab geht einen Schritt weiter und vereint Git-Repository, Issue-Tracking, CI/CD-Pipelines und Code Reviews unter einem Dach.

In diesem Post schauen wir uns den kompletten Workflow an: Von der Git-Grundkonfiguration über Branching-Strategien bis hin zu Merge Requests und Code Reviews in GitLab. Praxisnah, mit konkreten Befehlen und Beispielen.

Dieser Post bezieht sich auf eine self-hosted GitLab-Instanz. Die meisten Konzepte gelten aber genauso für gitlab.com oder andere Git-Plattformen.

Git einrichten

Installation

Auf den meisten Linux-Distributionen ist Git über den Paketmanager verfügbar:

1
2
3
4
5
6
7
8
# Debian / Ubuntu
sudo apt update && sudo apt install git

# Fedora
sudo dnf install git

# Arch Linux
sudo pacman -S git

Auf macOS kommt Git entweder über die Xcode Command Line Tools oder Homebrew:

1
2
3
4
5
# Xcode CLT (wird bei erstem git-Aufruf automatisch angeboten)
xcode-select --install

# Oder via Homebrew
brew install git

Unter Windows empfiehlt sich Git for Windows oder die Installation über winget:

1
winget install Git.Git

Grundkonfiguration

Nach der Installation solltest du Git mit deinem Namen und deiner E-Mail-Adresse konfigurieren. Diese Informationen werden in jedem Commit gespeichert:

1
2
git config --global user.name "Max Mustermann"
git config --global user.email "[email protected]"

Weitere sinnvolle Grundeinstellungen:

1
2
3
4
5
6
7
8
9
10
11
# Default-Branch auf 'main' setzen
git config --global init.defaultBranch main

# Pull-Strategie: Rebase statt Merge (sauberere History)
git config --global pull.rebase true

# Farbige Ausgabe
git config --global color.ui auto

# Editor für Commit-Messages
git config --global core.editor "vim"

SSH-Keys für GitLab

Für die Authentifizierung gegenüber GitLab empfiehlt sich SSH. So erstellst du einen Key und hinterlegst ihn:

1
2
3
4
5
# ED25519-Key erstellen (empfohlen)
ssh-keygen -t ed25519 -C "[email protected]"

# Key anzeigen
cat ~/.ssh/id_ed25519.pub

Den öffentlichen Key fügst du in GitLab unter Preferences → SSH Keys ein. Danach kannst du Repositories per SSH klonen:

1
git clone [email protected]:team/project.git

Falls du mehrere GitLab-Instanzen nutzt, kannst du in ~/.ssh/config verschiedene Keys pro Host konfigurieren.

Teste die Verbindung:

1
2
ssh -T [email protected]
# Welcome to GitLab, @max!

GPG-Signierung

Optional kannst du deine Commits mit GPG signieren. Damit wird kryptografisch nachweisbar, dass ein Commit wirklich von dir stammt:

1
2
3
4
5
6
7
8
9
# GPG-Key erstellen
gpg --full-generate-key

# Key-ID anzeigen
gpg --list-secret-keys --keyid-format=long

# Git konfigurieren
git config --global user.signingkey DEINE_KEY_ID
git config --global commit.gpgsign true

Den öffentlichen GPG-Key hinterlegst du in GitLab unter Preferences → GPG Keys. Signierte Commits werden in GitLab mit einem grünen “Verified”-Badge angezeigt.

Nützliche .gitconfig-Aliase

Ein paar Aliase, die den Alltag erleichtern:

1
2
3
4
5
6
7
git config --global alias.st "status -sb"
git config --global alias.co "checkout"
git config --global alias.br "branch"
git config --global alias.ci "commit"
git config --global alias.lg "log --oneline --graph --decorate --all"
git config --global alias.last "log -1 HEAD --stat"
git config --global alias.unstage "reset HEAD --"

Damit wird aus git log --oneline --graph --decorate --all ein simples git lg.

Die komplette Konfiguration findest du in ~/.gitconfig:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[user]
    name = Max Mustermann
    email = [email protected]
[init]
    defaultBranch = main
[pull]
    rebase = true
[alias]
    st = status -sb
    co = checkout
    br = branch
    ci = commit
    lg = log --oneline --graph --decorate --all
    last = log -1 HEAD --stat
    unstage = reset HEAD --

Git Grundlagen

Repository erstellen

Es gibt zwei Wege, ein Git-Repository zu starten:

1
2
3
4
5
6
7
# Neues Repository initialisieren
mkdir mein-projekt && cd mein-projekt
git init

# Bestehendes Repository klonen
git clone [email protected]:team/project.git
cd project

Bei git init wird ein leeres .git/-Verzeichnis angelegt. Bei git clone wird das komplette Repository inklusive History heruntergeladen.

Die drei Bereiche

Git arbeitet mit drei Bereichen, die du verstehen musst:

flowchart LR
    A["Working<br/>Directory"] -->|git add| B["Staging<br/>Area"]
    B -->|git commit| C["Repository<br/>(.git)"]
    C -->|git checkout| A
    B -->|git restore --staged| A

    style A fill:#1a1e24,stroke:#fc6d26,color:#fff
    style B fill:#1a1e24,stroke:#fdb45c,color:#fff
    style C fill:#1a1e24,stroke:#27c93f,color:#fff
  • Working Directory: Deine Dateien auf der Festplatte – hier arbeitest du
  • Staging Area (Index): Änderungen, die für den nächsten Commit vorgemerkt sind
  • Repository (.git/): Die gespeicherte History aller Commits

Der typische Ablauf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Dateien bearbeiten
vim app.py

# Änderungen stagen
git add app.py

# Oder alles stagen
git add .

# Status prüfen (was ist staged, was nicht?)
git status

# Commit erstellen
git commit -m "feat: add user authentication"

Mit git diff siehst du Änderungen im Working Directory, mit git diff --staged die bereits gestageten Änderungen.

Was ist ein guter Commit?

Ein Commit sollte eine logische Einheit darstellen. Nicht zu groß, nicht zu klein:

Schlecht Gut
“diverse Änderungen” “fix: correct null check in user validation”
“WIP” “feat: add password reset endpoint”
Gesamtes Feature in einem Commit Aufgeteilt in sinnvolle Schritte
Mischung aus Bugfix und Refactoring Jeweils eigene Commits

Bewährte Regeln:

  • Imperative Schreibweise: “Add feature” statt “Added feature”
  • Erste Zeile max. 72 Zeichen
  • Leerzeile zwischen Titel und Beschreibung
  • Body erklärt das Warum, nicht das Was (das sieht man im Diff)

Beispiel einer guten Commit-Message:

1
2
3
4
5
6
feat: add rate limiting to API endpoints

Requests are now limited to 100/minute per IP address.
This prevents abuse and ensures fair usage across all clients.

Implements: #142

Branches

Branches sind das Herzstück von Git. Sie ermöglichen paralleles Arbeiten, ohne sich gegenseitig in die Quere zu kommen:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Neuen Branch erstellen und wechseln
git checkout -b feature/user-profile

# Oder mit dem neueren switch-Befehl
git switch -c feature/user-profile

# Alle Branches anzeigen
git branch -a

# Branch wechseln
git checkout main
git switch main

# Branch löschen (nur wenn gemerged)
git branch -d feature/user-profile

# Branch löschen (Force)
git branch -D feature/user-profile

Ein Branch ist technisch gesehen nur ein Zeiger auf einen Commit. Das macht Branches in Git extrem leichtgewichtig – erstelle so viele wie du brauchst.

Tags

Tags markieren bestimmte Punkte in der History, typischerweise Releases:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Lightweight Tag (nur ein Zeiger)
git tag v1.0.0

# Annotated Tag (empfohlen für Releases)
git tag -a v1.0.0 -m "Release Version 1.0.0"

# Tags anzeigen
git tag -l

# Tag pushen
git push origin v1.0.0

# Alle Tags pushen
git push origin --tags

Verwende Annotated Tags für Releases. Sie enthalten Autor, Datum und eine Beschreibung. Lightweight Tags eignen sich für temporäre Markierungen.

Semantic Versioning (SemVer) ist der Standard für Versionsnummern:

Version Bedeutung
v1.0.0v1.0.1 Patch: Bugfix, keine neuen Features
v1.0.0v1.1.0 Minor: Neues Feature, abwärtskompatibel
v1.0.0v2.0.0 Major: Breaking Changes

Push & Pull

Um Änderungen mit einem Remote-Repository auszutauschen:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Remote anzeigen
git remote -v

# Remote hinzufügen
git remote add origin [email protected]:team/project.git

# Änderungen hochladen
git push origin main

# Beim ersten Push: Upstream-Tracking setzen
git push -u origin main

# Änderungen herunterladen und integrieren
git pull

# Nur herunterladen, ohne zu integrieren
git fetch

git pull ist im Grunde git fetch + git merge (oder git rebase, je nach Konfiguration). Mit git fetch holst du die Änderungen erstmal nur ab und entscheidest dann selbst, was du damit machst.

Merge vs. Rebase

Zwei Wege, Branches zusammenzuführen:

gitGraph
    commit id: "A"
    commit id: "B"
    branch feature
    commit id: "C"
    commit id: "D"
    checkout main
    commit id: "E"
    merge feature id: "Merge"

Merge erstellt einen Merge-Commit und bewahrt die komplette Branch-History:

1
2
git checkout main
git merge feature/login

Rebase schreibt die History um und setzt die Commits des Feature-Branches auf die Spitze von main:

1
2
git checkout feature/login
git rebase main
gitGraph
    commit id: "A"
    commit id: "B"
    commit id: "E"
    commit id: "C'"
    commit id: "D'"
  Merge Rebase
History Bleibt erhalten (Merge-Commit) Linear, “sauberer”
Konflikte Einmal lösen Pro Commit lösen
Shared Branches Sicher Nur für lokale Branches
Nachvollziehbarkeit Wann wurde was gemerged? Klare, lineare Abfolge

Goldene Regel: Rebase niemals auf Branches, die andere Entwickler nutzen. Für lokale Feature-Branches ist Rebase ideal, um die History aufzuräumen bevor man merged.

GitLab kennenlernen

Was ist GitLab?

GitLab ist eine DevOps-Plattform, die den gesamten Software-Lifecycle abdeckt:

  • Repository-Management: Git-Hosting mit Web-UI
  • Issue Tracking: Aufgaben, Bugs, Feature-Requests
  • CI/CD: Automatisierte Builds, Tests und Deployments
  • Code Review: Merge Requests mit Inline-Kommentaren
  • Container Registry: Docker-Images direkt in GitLab
  • Wiki & Pages: Dokumentation

Im Vergleich zu Alternativen:

Feature GitLab GitHub Gitea / Forgejo
Self-Hosted Community Edition (gratis) Enterprise (kostenpflichtig) Gratis
CI/CD Integriert GitHub Actions Externe Tools / Forgejo Actions
Container Registry Integriert Integriert Plugin
Ressourcenbedarf Hoch (~4 GB RAM minimum) - Niedrig (~512 MB)
Funktionsumfang Sehr umfangreich Umfangreich Grundfunktionen

Self-Hosted vs. SaaS

Für ein Homelab bietet sich eine eigene GitLab-Instanz an:

  • Volle Kontrolle über Daten und Konfiguration
  • Kein Vendor Lock-in
  • Interne Projekte bleiben im eigenen Netz
  • Kostenlos mit der Community Edition

Der Nachteil: GitLab ist ressourcenhungrig. Mindestens 4 GB RAM, besser 8 GB, sollten es sein.

Für leichtgewichtige Alternativen schau dir Gitea oder Forgejo an. Wenn du den vollen Funktionsumfang brauchst, führt an GitLab kein Weg vorbei.

Projekt erstellen und verbinden

In der GitLab-Web-UI:

  1. New ProjectCreate blank project
  2. Name, Beschreibung und Visibility (Private/Internal/Public) festlegen
  3. Optional: README und .gitignore initialisieren

Dann lokal verbinden:

1
2
3
4
5
6
7
# Neues lokales Projekt mit GitLab verbinden
cd mein-projekt
git init
git remote add origin [email protected]:gruppe/mein-projekt.git
git add .
git commit -m "init: initial commit"
git push -u origin main

Oder ein bestehendes GitLab-Projekt klonen:

1
git clone [email protected]:gruppe/mein-projekt.git

Web-IDE

GitLab bringt eine integrierte Web-IDE mit, die direkt im Browser läuft. Praktisch für schnelle Änderungen:

  • Öffne eine Datei und klicke auf EditWeb IDE
  • Syntax-Highlighting für alle gängigen Sprachen
  • Direkt committen ohne lokales Git
  • Basiert auf VS Code (Monaco Editor)

Für umfangreiche Arbeiten ist ein lokaler Editor natürlich besser geeignet, aber für einen schnellen Fix an einer Config-Datei ist die Web-IDE ideal.

GitLab-Workflow im Team

Workflow-Übersicht

Der typische GitLab-Workflow folgt einem klaren Muster:

GitLab Workflow

  1. Branch erstellen vom aktuellen main
  2. Commits mit den Änderungen
  3. Push zum Remote-Repository
  4. Merge Request in GitLab erstellen
  5. Code Review durch Teammitglieder
  6. Merge in main nach Approval

Feature Branches

Jede Änderung bekommt ihren eigenen Branch. Namenskonventionen helfen bei der Orientierung:

Prefix Verwendung Beispiel
feature/ Neue Funktionalität feature/user-dashboard
fix/ Bugfix fix/login-redirect
hotfix/ Dringender Fix für Production hotfix/security-patch
docs/ Dokumentation docs/api-reference
refactor/ Code-Umstrukturierung refactor/auth-module
chore/ Maintenance-Aufgaben chore/update-dependencies
1
2
3
4
5
6
7
8
9
10
11
12
# Feature-Branch erstellen
git checkout main
git pull
git checkout -b feature/user-dashboard

# Arbeiten, committen...
git add .
git commit -m "feat: add user dashboard layout"
git commit -m "feat: add activity feed to dashboard"

# Push zum Remote
git push -u origin feature/user-dashboard

Halte Feature-Branches kurzlebig. Je länger ein Branch existiert, desto wahrscheinlicher sind Merge-Konflikte.

Merge Requests erstellen

Nach dem Push erscheint in GitLab ein Banner: “Create merge request”. Alternativ erstellst du einen MR manuell:

  1. Merge RequestsNew merge request
  2. Source Branch: feature/user-dashboard
  3. Target Branch: main
  4. Titel und Beschreibung ausfüllen

Eine gute MR-Beschreibung enthält:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
## Was wurde geändert?
- User-Dashboard mit Activity Feed implementiert
- Responsive Layout für Mobile

## Warum?
Nutzer brauchen eine Übersicht über ihre letzten Aktivitäten (Issue #45)

## Wie testen?
1. Als User einloggen
2. /dashboard aufrufen
3. Activity Feed sollte die letzten 10 Einträge zeigen

## Screenshots
[Falls UI-Änderungen]

Nützliche MR-Optionen:

  • Assignee: Wer ist verantwortlich?
  • Reviewer: Wer soll reviewen?
  • Labels: Kategorisierung (bug, feature, etc.)
  • Milestone: Zuordnung zu einem Release
  • Delete source branch: Branch nach Merge automatisch löschen
  • Squash commits: Alle Commits zu einem zusammenfassen

Aktiviere “Delete source branch when merge request is accepted” als Standard. Das hält das Repository sauber.

Du kannst auch direkt aus der Kommandozeile einen MR erstellen:

1
2
3
4
5
6
# Push und MR-Erstellung in einem Schritt
git push -u origin feature/user-dashboard \
  -o merge_request.create \
  -o merge_request.target=main \
  -o merge_request.title="feat: add user dashboard" \
  -o merge_request.remove_source_branch

Code Reviews

Code Reviews sind einer der wichtigsten Qualitätsmechanismen. Best Practices:

Als Reviewer:

  • Lies die MR-Beschreibung zuerst
  • Verstehe das Warum vor dem Wie
  • Inline-Kommentare für spezifisches Feedback
  • Konstruktiv bleiben: “Könnte man hier X verwenden?” statt “Das ist falsch”
  • Approve nur, wenn du den Code wirklich verstanden hast

Als Autor:

  • Halte MRs klein (< 400 Zeilen Diff wenn möglich)
  • Selbst-Review vor dem MR: Schau dir deinen eigenen Diff nochmal an
  • Reagiere auf Feedback zeitnah
  • Erkläre komplexe Stellen proaktiv in der Beschreibung

GitLab bietet verschiedene Feedback-Mechanismen:

1
2
3
4
5
6
# Inline-Kommentar
Klick auf die Zeilennummer im Diff → Kommentar schreiben

# Suggestion (direkt änderbarer Code-Vorschlag)
```suggestion
const MAX_RETRIES = 3;

Thread (Diskussion, die explizit resolved werden muss)

“Unresolved Discussion” blockiert den Merge

1
2
3
4
5
6
7
### Merge-Strategien

GitLab bietet drei Merge-Strategien:

**1. Merge Commit** (Standard)

  • Merge branch ‘feature/login’ into ‘main’ |
    | * feat: add login form | * feat: add auth service |/
  • previous commit on main ```

  • Erstellt einen Merge-Commit
  • Komplette Branch-History bleibt sichtbar
  • Gut für die Nachvollziehbarkeit

2. Squash and Merge

1
2
* feat: add login feature (squashed)
* previous commit on main
  • Alle Branch-Commits werden zu einem zusammengefasst
  • Saubere main-History
  • Detail-History geht verloren

3. Fast-Forward Merge

1
2
3
* feat: add auth service
* feat: add login form
* previous commit on main
  • Kein Merge-Commit, lineare History
  • Nur möglich wenn kein Divergenz vorliegt
  • Am “saubersten”, aber nicht immer möglich

Welche Strategie passt? Das hängt vom Team ab:

Strategie Wann sinnvoll
Merge Commit Team will nachvollziehen, wann welcher Branch gemerged wurde
Squash Viele kleine WIP-Commits, nur das Endergebnis zählt
Fast-Forward Kleine Änderungen, saubere lineare History gewünscht

Konflikte lösen

Wenn zwei Branches die gleiche Stelle in einer Datei ändern, entsteht ein Konflikt:

1
2
3
4
5
6
# Merge starten
git checkout main
git merge feature/login

# Git meldet: CONFLICT in auth.py
# Datei öffnen und Konfliktmarker auflösen:

Konfliktmarker sehen so aus:

1
2
3
4
5
6
def authenticate(user):
<<<<<<< HEAD
    return check_ldap(user)
=======
    return check_oauth(user)
>>>>>>> feature/login

Die Auflösung:

  1. Entscheide, welche Version korrekt ist (oder kombiniere beide)
  2. Entferne die Konfliktmarker (<<<<<<<, =======, >>>>>>>)
  3. Stage die aufgelöste Datei und committe
1
2
3
# Nach dem Auflösen
git add auth.py
git commit -m "fix: resolve merge conflict in auth module"

In GitLab kannst du einfache Konflikte direkt in der Web-UI lösen. Für komplexere Fälle empfiehlt sich die lokale Auflösung.

Bei --theirs oder --ours in Merge-Konflikten solltest du immer prüfen, ob die gewählte Seite nicht versehentlich wichtige Änderungen der anderen Seite verwirft.

Protected Branches

In GitLab kannst du Branches schützen, damit nicht jeder direkt pushen kann:

Settings → Repository → Protected Branches:

Einstellung Empfehlung
Branch main
Allowed to merge Maintainers
Allowed to push No one
Allowed to force push No
Require approval 1+ Approvals

Damit erzwingst du, dass alle Änderungen an main über Merge Requests laufen. Kein direktes Pushen, kein Force Push.

Weitere sinnvolle Schutzregeln:

  • Merge-Checks: Pipeline muss erfolgreich sein
  • Approval Rules: Mindestens ein Reviewer muss approven
  • Code Owners: Bestimmte Dateien/Verzeichnisse brauchen Review von spezifischen Personen

Branching-Strategien

Es gibt verschiedene Ansätze, wie ein Team mit Branches arbeitet:

GitLab Flow (empfohlen für die meisten Teams)

gitGraph
    commit id: "init"
    branch production
    checkout main
    commit id: "feat A"
    commit id: "feat B"
    checkout production
    merge main id: "deploy v1"
    checkout main
    commit id: "feat C"
    commit id: "fix D"
    checkout production
    merge main id: "deploy v2"
  • main ist der Entwicklungs-Branch
  • Feature-Branches gehen von main ab und werden per MR zurückgemerged
  • production (oder Environment-Branches) für Deployments
  • Einfach und übersichtlich

Git Flow (für komplexere Release-Zyklen)

gitGraph
    commit id: "init"
    branch develop
    commit id: "feat A"
    branch "feature/login"
    commit id: "login impl"
    checkout develop
    merge "feature/login" id: "merge feat"
    branch "release/1.0"
    commit id: "bump version"
    checkout main
    merge "release/1.0" id: "v1.0.0" tag: "v1.0.0"
    checkout develop
    merge "release/1.0" id: "back-merge"
  • main enthält nur Releases
  • develop ist der Integrations-Branch
  • Feature-, Release- und Hotfix-Branches
  • Mehr Overhead, aber klare Trennung

Trunk-Based Development (für erfahrene Teams mit guter CI/CD)

  • Alle arbeiten direkt auf main (mit sehr kurzlebigen Feature-Branches)
  • Feature Flags statt langlebige Branches
  • Setzt exzellente Test-Coverage und CI/CD voraus
  • Minimaler Branch-Overhead
Strategie Komplexität Geeignet für
GitLab Flow Niedrig Die meisten Teams
Git Flow Hoch Projekte mit festen Release-Zyklen
Trunk-Based Niedrig Teams mit starker CI/CD

Nützliche Git-Befehle

git stash

Änderungen temporär zur Seite legen, ohne zu committen:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Änderungen stashen
git stash

# Mit Beschreibung
git stash push -m "WIP: dashboard layout"

# Stash-Liste anzeigen
git stash list

# Letzten Stash wiederherstellen
git stash pop

# Bestimmten Stash wiederherstellen
git stash apply stash@{2}

# Stash löschen
git stash drop stash@{0}

git log

Die History effektiv durchsuchen:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Kompakte Darstellung mit Graph
git log --oneline --graph --all

# Commits eines bestimmten Autors
git log --author="Max"

# Commits der letzten Woche
git log --since="1 week ago"

# Commits die eine bestimmte Datei betreffen
git log -- path/to/file.py

# Suche in Commit-Messages
git log --grep="login"

# Änderungen in jedem Commit anzeigen
git log -p

git cherry-pick

Einen einzelnen Commit von einem anderen Branch übernehmen:

1
2
3
4
5
# Commit-Hash aus dem Log holen
git log --oneline feature/auth

# Commit auf den aktuellen Branch anwenden
git cherry-pick a3f2c1d

Nützlich für Hotfixes: Einen Fix-Commit von main auch auf einen Release-Branch anwenden.

git bisect

Automatisch den Commit finden, der einen Bug eingeführt hat:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Bisect starten
git bisect start

# Aktueller Stand ist kaputt
git bisect bad

# Dieser alte Commit war noch in Ordnung
git bisect good v1.0.0

# Git checkt jetzt automatisch Commits aus
# Du testest und sagst: good oder bad
git bisect good
git bisect bad
# ... bis der schuldige Commit gefunden ist

# Bisect beenden
git bisect reset

git reflog

Dein Sicherheitsnetz – zeigt alle Aktionen, auch gelöschte Commits:

1
2
3
4
5
6
7
8
9
10
# Reflog anzeigen
git reflog

# Beispiel: Versehentlich resetted? Kein Problem:
git reflog
# a3f2c1d HEAD@{0}: reset: moving to HEAD~3
# 7b4e2a1 HEAD@{1}: commit: feat: important feature

git checkout 7b4e2a1
# Oder: git reset --hard 7b4e2a1

git reflog bewahrt Referenzen standardmäßig 90 Tage auf. In dieser Zeit kannst du praktisch alles wiederherstellen.

.gitignore

Dateien und Verzeichnisse, die Git ignorieren soll:

# Build-Artefakte
/dist/
/build/
*.pyc
__pycache__/

# Dependencies
/node_modules/
/vendor/
/.venv/

# IDE
.idea/
.vscode/
*.swp
*.swo

# OS
.DS_Store
Thumbs.db

# Secrets (niemals committen!)
.env
*.key
*.pem
credentials.json

Nutze gitignore.io um passende .gitignore-Templates für deine Sprache und IDE zu generieren.

Falls du eine Datei bereits committed hast und sie nachträglich ignorieren willst:

1
2
3
4
# Datei aus dem Index entfernen (bleibt lokal erhalten)
git rm --cached .env
echo ".env" >> .gitignore
git commit -m "chore: remove .env from tracking"

IDE-Integration

Ein guter Editor macht die Arbeit mit Git deutlich komfortabler. Hier ein kurzer Überblick:

VS Code

VS Code hat die beste Git-Integration von Haus aus:

  • Source Control Panel (Ctrl+Shift+G): Staging, Commits, Diffs
  • GitLens (Extension): Blame, History, Vergleiche – ein Muss
  • GitLab Workflow (Extension): MRs direkt in VS Code reviewen
1
2
3
# Empfohlene Extensions
ext install eamodio.gitlens
ext install GitLab.gitlab-workflow

Neovim / LazyVim

Für Terminal-Enthusiasten:

  • fugitive.vim: Der Git-Wrapper schlechthin (:Git blame, :Git diff)
  • gitsigns.nvim: Zeigt Änderungen im Gutter an, Inline-Blame
  • diffview.nvim: Diff-Ansicht direkt in Neovim
1
2
3
4
-- In der LazyVim-Config
{ "tpope/vim-fugitive" },
{ "lewis6991/gitsigns.nvim" },
{ "sindrets/diffview.nvim" },

JetBrains (IntelliJ, PyCharm, etc.)

JetBrains-IDEs haben eine starke eingebaute Git-Integration:

  • Git Tool Window: Log, Branches, Stash
  • Annotate (Blame): Rechtsklick → Git → Annotate
  • Resolve Conflicts: Visueller 3-Way-Merge
  • GitLab Integration: Plugin für MR-Management

Die IDE-Integration ist ein eigenes Thema. Ein detaillierter Post zu Git in verschiedenen Editoren folgt.

GitLab für Dokumentation

Code allein reicht nicht — wer einen Service betreibt, braucht auch Dokumentation. Wie startet man den Service neu? Was tun bei einem Ausfall? Welche Konfiguration wurde warum gewählt? Genau solche Fragen beantwortet ein Betriebshandbuch.

Der Docs-as-Code-Ansatz behandelt Dokumentation mit denselben Werkzeugen wie Code: Git für Versionierung, Merge Requests für Reviews, CI/CD für automatische Builds.

flowchart LR
    subgraph Repo["GitLab Repository"]
        A["Source Code"] --- B["Dokumentation"]
    end
    Repo --> C["Merge Request"]
    C --> D["Review"]
    D --> E["Merge"]
    E --> F["CI/CD Build"]
    F --> G["App Deploy"]
    F --> H["Docs Deploy"]

README als erste Anlaufstelle

Jedes Repository braucht ein gutes README.md. Für Homelab-Services hat sich folgende Struktur bewährt:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# Service-Name

Kurze Beschreibung, was der Service macht.

## Voraussetzungen

- Docker + Docker Compose
- Netzwerk-Zugang zu X

## Installation

1. Repo klonen
2. `.env` Datei anlegen
3. `docker compose up -d`

## Konfiguration

Wichtige Umgebungsvariablen und Config-Dateien.

## Backup & Restore

Wie werden Daten gesichert und wiederhergestellt?

## Troubleshooting

Häufige Probleme und ihre Lösung.

Das README ist der Einstiegspunkt für jeden, der das Projekt zum ersten Mal sieht — auch für dich selbst in sechs Monaten.

GitLab Wiki

Jedes GitLab-Projekt bringt ein eingebautes Wiki mit. Es eignet sich besonders für Dokumentation, die über ein einzelnes README hinausgeht — zum Beispiel ein Betriebshandbuch.

Typische Wiki-Struktur für einen Homelab-Service:

Seite Inhalt
Home Übersicht, Quick Links
Installation Schritt-für-Schritt Setup
Konfiguration Alle Parameter erklärt
Backup Backup-Strategie und Restore
Monitoring Health-Checks, Alerting
Troubleshooting Bekannte Probleme und Lösungen
Changelog Wichtige Änderungen

Das Wiki ist direkt über die GitLab-Oberfläche erreichbar: Projekt → Plan → Wiki. Du kannst Seiten im Browser bearbeiten oder das Wiki lokal klonen und mit deinem Editor pflegen:

1
2
# Wiki ist ein separates Git-Repo
git clone [email protected]:homelab/mein-projekt.wiki.git

Das Wiki ist ein separates Git-Repository. Es wird nicht automatisch mit dem Projekt-Repo gesichert. Denke daran, es in deine Backup-Strategie aufzunehmen.

GitLab Pages

Für professionelle Dokumentation kannst du mit GitLab Pages eine statische Website direkt aus deinem Repository generieren. Beliebte Generatoren sind MkDocs (Python), Jekyll (Ruby) und Hugo (Go).

Beispiel mit MkDocs Material:

1
2
3
4
5
6
7
8
9
10
11
12
# .gitlab-ci.yml
pages:
  stage: deploy
  image: python:3.12-slim
  script:
    - pip install mkdocs-material
    - mkdocs build --site-dir public
  artifacts:
    paths:
      - public
  only:
    - main

Damit wird bei jedem Push auf main automatisch die Dokumentation gebaut und unter https://<namespace>.gitlab.io/<projekt>/ bereitgestellt.

GitLab Pages können sowohl öffentlich als auch auf angemeldete User beschränkt werden. Für interne Betriebsdokumentation lässt sich der Zugriff unter Settings → General → Visibility einschränken.

Docs-as-Code Workflow

Der größte Vorteil von Dokumentation in Git: Sie durchläuft denselben Review-Prozess wie Code.

  • Doku-Änderungen kommen als Merge Request — Teammitglieder können reviewen
  • Code und Doku im selben Commit ändern, wenn beides zusammengehört
  • Changelog automatisch aus Commit-Messages generieren
  • Versionierung — du kannst jederzeit nachschauen, wie die Doku vor drei Monaten aussah

Best Practice: Aktualisiere die Dokumentation im selben Merge Request wie die Code-Änderung. So bleibt die Doku nie hinter dem Code zurück.

Im nächsten Abschnitt zu CI/CD siehst du, wie sich Doc-Builds automatisieren lassen — damit die Dokumentation bei jedem Merge automatisch neu gebaut und deployed wird.

Praxis: Betriebshandbuch aufbauen

Für ein Homelab-Betriebshandbuch empfiehlt sich ein dediziertes Repository mit folgender Struktur:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
homelab-docs/
├── docs/
│   ├── index.md              # Übersicht
│   ├── netzwerk/
│   │   ├── dns.md            # Pi-hole, AdGuard
│   │   ├── vpn.md            # WireGuard
│   │   └── reverse-proxy.md  # Nginx Proxy Manager
│   ├── services/
│   │   ├── gitlab.md         # GitLab Setup
│   │   ├── homeassistant.md  # Home Assistant
│   │   └── monitoring.md     # Grafana, Prometheus
│   └── runbooks/
│       ├── backup-restore.md # Disaster Recovery
│       └── neue-vm.md        # VM-Provisionierung
├── mkdocs.yml
└── .gitlab-ci.yml

Dokumentiere während du baust, nicht danach. Wenn du einen neuen Service einrichtest, schreibe die Doku parallel dazu. Der Aufwand ist minimal, solange alles noch frisch im Kopf ist.

Dokumentations-Ansätze im Vergleich

Ansatz Wann sinnvoll Vorteile Nachteile
README.md Projekt-Doku, Quick Start Direkt im Repo, kein Setup Begrenzt auf eine Datei
GitLab Wiki Team-Wissen, Betriebshandbuch Einfach, kein Build nötig Separates Repo, begrenzte Struktur
GitLab Pages User-Doku, API-Docs Professionell, durchsuchbar Build-Pipeline nötig
Extern (Confluence) Enterprise, Non-Tech-User WYSIWYG-Editor Kein Git-Workflow, Kosten

Für die meisten Homelab-Projekte reicht ein gutes README. Sobald die Dokumentation über ein einzelnes Projekt hinausgeht — zum Beispiel ein zentrales Betriebshandbuch — lohnt sich der Umstieg auf GitLab Pages mit MkDocs.

CI/CD anreissen

Was ist CI/CD?

Continuous Integration (CI) bedeutet, dass bei jedem Push automatisch Tests und Builds laufen. Continuous Delivery/Deployment (CD) geht einen Schritt weiter und deployed automatisch.

flowchart LR
    A["Push"] --> B["Build"]
    B --> C["Test"]
    C --> D["Deploy<br/>Staging"]
    D --> E["Deploy<br/>Production"]

    style A fill:#1a1e24,stroke:#fc6d26,color:#fff
    style B fill:#1a1e24,stroke:#fdb45c,color:#fff
    style C fill:#1a1e24,stroke:#fdb45c,color:#fff
    style D fill:#1a1e24,stroke:#27c93f,color:#fff
    style E fill:#1a1e24,stroke:#27c93f,color:#fff

In GitLab definierst du die Pipeline in einer .gitlab-ci.yml im Root deines Projekts.

Minimalbeispiel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
stages:
  - build
  - test
  - deploy

build:
  stage: build
  image: node:20
  script:
    - npm ci
    - npm run build
  artifacts:
    paths:
      - dist/

test:
  stage: test
  image: node:20
  script:
    - npm ci
    - npm test

deploy:
  stage: deploy
  script:
    - echo "Deploying to production..."
    - scp -r dist/ user@server:/var/www/app/
  only:
    - main
  when: manual

Die Pipeline:

  1. Build: Installiert Dependencies und baut die App
  2. Test: Führt Tests aus
  3. Deploy: Deployed auf den Server (nur bei main, manuell ausgelöst)

CI/CD in GitLab ist ein umfangreiches Thema. Ein dedizierter Post zu Pipelines, Runners und fortgeschrittenen Konfigurationen folgt.

Tipps für die Praxis

Conventional Commits

Ein standardisiertes Format für Commit-Messages, das auch Tools (Changelogs, Semantic Versioning) nutzen können:

1
2
3
4
5
<type>(<scope>): <description>

[optional body]

[optional footer]

Die wichtigsten Types:

Type Bedeutung
feat Neues Feature
fix Bugfix
docs Dokumentation
style Formatierung (kein Code-Change)
refactor Refactoring (kein Feature, kein Fix)
test Tests hinzufügen/ändern
chore Maintenance (Dependencies, Build etc.)
ci CI/CD-Konfiguration

Beispiele:

1
2
3
4
git commit -m "feat(auth): add OAuth2 login flow"
git commit -m "fix(api): handle null response in user endpoint"
git commit -m "docs: update README with setup instructions"
git commit -m "chore(deps): update express to 4.19.0"

Branch-Hygiene

Tote Branches sind Ballast. Halte dein Repository sauber:

1
2
3
4
5
6
7
8
9
10
11
# Lokale Branches anzeigen, die bereits gemerged sind
git branch --merged main

# Gemergete Branches löschen (außer main und develop)
git branch --merged main | grep -v "main\|develop" | xargs git branch -d

# Remote-Branches aufräumen (gelöschte Branches entfernen)
git fetch --prune

# Oder automatisch bei jedem Fetch
git config --global fetch.prune true

Atomic Commits

Jeder Commit sollte den Code in einem funktionierenden Zustand hinterlassen. Das bedeutet:

  • Nicht mitten in einer Änderung committen
  • Nicht mehrere unrelated Änderungen in einem Commit
  • Tests sollten nach jedem Commit grün sein
  • Nutze git add -p um nur Teile einer Datei zu stagen
1
2
3
4
5
6
# Interaktives Staging: Einzelne Hunks auswählen
git add -p

# Zeigt jeden geänderten Block und fragt:
# Stage this hunk [y,n,q,a,d,s,e,?]?
# y = stage, n = skip, s = split into smaller hunks

Git Hooks

Git Hooks sind Skripte, die bei bestimmten Events automatisch ausgeführt werden:

1
2
3
4
5
6
7
8
9
10
# Pre-Commit Hook: Linting vor jedem Commit
cat > .git/hooks/pre-commit << 'EOF'
#!/bin/sh
npm run lint
if [ $? -ne 0 ]; then
    echo "Lint errors found. Fix them before committing."
    exit 1
fi
EOF
chmod +x .git/hooks/pre-commit

Häufig genutzte Hooks:

Hook Wann Typische Verwendung
pre-commit Vor dem Commit Linting, Formatting
commit-msg Nach Eingabe der Message Message-Format prüfen
pre-push Vor dem Push Tests ausführen
post-merge Nach einem Merge Dependencies installieren

Schau dir pre-commit an – ein Framework das Git Hooks projektübergreifend managebar macht.

Backup-Strategie

Git ist verteilt, aber ein Backup-Konzept schadet nicht:

  • Mirror-Repositories: git push --mirror auf einen zweiten Server
  • GitLab Backup: Eingebaute Backup-Funktion (gitlab-backup create)
  • Wichtig: Auch LFS-Objekte und CI/CD-Variablen sichern
1
2
3
# Mirror auf einen Backup-Server pushen
git remote add backup git@backup-server:team/project.git
git push --mirror backup

Fazit

Git und GitLab bilden zusammen ein mächtiges Ökosystem für die Softwareentwicklung. Die Lernkurve ist am Anfang steil, aber die Investition lohnt sich:

  • Git Grundlagen beherrschen: Commits, Branches, Merge/Rebase
  • Workflow etablieren: Feature-Branches, Merge Requests, Code Reviews
  • Branch Protection einrichten: Qualität über Geschwindigkeit
  • Konventionen im Team festlegen: Commit-Messages, Branch-Namen
  • Dokumentation pflegen: README, Wiki, Betriebshandbuch als Code
  • CI/CD nutzen: Automatisierte Tests und Deployments

Der in diesem Post beschriebene Workflow skaliert vom Ein-Personen-Homelab-Projekt bis zum großen Entwicklerteam. Starte einfach und füge Komplexität nur hinzu, wenn du sie wirklich brauchst.

In kommenden Posts schauen wir uns die CI/CD-Pipeline-Konfiguration und die IDE-Integration im Detail an.

Dieser Eintrag ist vom Autor unter CC BY 4.0 lizensiert.