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/configverschiedene 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 diffsiehst du Änderungen im Working Directory, mitgit diff --stageddie 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.0 → v1.0.1 |
Patch: Bugfix, keine neuen Features |
v1.0.0 → v1.1.0 |
Minor: Neues Feature, abwärtskompatibel |
v1.0.0 → v2.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:
- New Project → Create blank project
- Name, Beschreibung und Visibility (Private/Internal/Public) festlegen
- Optional: README und
.gitignoreinitialisieren
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 Edit → Web 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:
- Branch erstellen vom aktuellen
main - Commits mit den Änderungen
- Push zum Remote-Repository
- Merge Request in GitLab erstellen
- Code Review durch Teammitglieder
- Merge in
mainnach 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:
- Merge Requests → New merge request
- Source Branch:
feature/user-dashboard - Target Branch:
main - 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:
- Entscheide, welche Version korrekt ist (oder kombiniere beide)
- Entferne die Konfliktmarker (
<<<<<<<,=======,>>>>>>>) - 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
--theirsoder--oursin 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"
mainist der Entwicklungs-Branch- Feature-Branches gehen von
mainab 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"
mainenthält nur Releasesdevelopist 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 reflogbewahrt 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:
- Build: Installiert Dependencies und baut die App
- Test: Führt Tests aus
- 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 -pum 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 --mirrorauf 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.