15%

15% auf alle Hosting-Dienste sparen

Teste deine Fähigkeiten und erhalte Rabatt auf jeden Hosting-Plan

Benutze den Code:

Skills
Anfangen
14.10.2024

Git Versionskontrolle: Die vollständige technische Referenz für Entwickler

Git ist ein verteiltes Versionskontrollsystem (DVCS), das Snapshots des Dateibaums eines Projekts über die Zeit aufzeichnet und es einer beliebigen Anzahl von Mitwirkenden ermöglicht, parallel zu arbeiten, ohne die Änderungen der anderen zu überschreiben. Jeder Entwickler hält eine vollständige Kopie des Repositorys – einschließlich der gesamten Commit-Historie – auf seinem lokalen Rechner, wodurch jeder einzelne Ausfallpunkt eliminiert und vollständig offline arbeitsfähige Workflows ermöglicht werden.

Git wurde von Linus Torvalds im April 2005 entwickelt, um BitKeeper für die Linux-Kernel-Entwicklung zu ersetzen, und wurde von Grund auf nach drei nicht verhandelbaren Anforderungen konzipiert: Geschwindigkeit, Datenintegrität und Unterstützung für nicht-lineare, verteilte Workflows. Diese Designziele definieren noch immer, was Git grundlegend von seinen Vorgängern unterscheidet und warum es mehr als zwei Jahrzehnte später das dominante VCS bleibt.

Wie sich Git von zentralisierter Versionskontrolle unterscheidet

Das Verständnis von Gits Architektur erfordert einen direkten Vergleich mit zentralisierten Systemen wie Subversion (SVN) oder CVS, bei denen ein einziger autoritativer Server das kanonische Repository hält und Entwickler flache Arbeitskopien auschecken.

DimensionGit (Verteilt)SVN (Zentralisiert)
Repository-ModellVollständiger Klon auf jedem KnotenDünne Arbeitskopie, Server hält Historie
Offline-FähigkeitVollständiges Commit, Branch, Diff, LogNur lesend; Commits erfordern Server
Branching-KostenNahezu null (Pointer-Manipulation)Aufwändiges Verzeichnis-Kopieren
Einzelner AusfallpunktKeiner — jeder Klon kann wiederherstellenServerausfall stoppt alle Commits
Merge-StrategieDrei-Wege-Merge + RebaseNur Drei-Wege-Merge
HistorienintegritätSHA-1/SHA-256 Content-HashingSequenzielle Revisionsnummern
NetzwerkabhängigkeitNur für Push/Pull/FetchNahezu jede Operation
Partielles CheckoutNicht nativ unterstütztUnterstützt (Sparse Checkout)
LernkurveSteilere anfängliche KurveSanfter für SVN-Veteranen
Verbreitung (2024)~95% der professionellen TeamsLegacy-Unternehmensumgebungen

Das verteilte Modell bedeutet, dass selbst wenn eine Hosting-Plattform wie GitHub einen Ausfall erlebt, der lokale Klon jedes Entwicklers ein vollständiges, autoritatives Backup der gesamten Projekthistorie ist.

Kernarchitektur: Was Git tatsächlich speichert

Git speichert keine Diffs. Es speichert Snapshots. Jeder Commit zeigt auf ein Tree-Objekt, das den vollständigen Zustand jeder verfolgten Datei zu diesem Zeitpunkt repräsentiert. Wenn sich eine Datei zwischen zwei Commits nicht geändert hat, speichert Git einen Zeiger auf den vorherigen Blob anstatt ihn zu duplizieren — so erreicht Git sowohl Vollständigkeit als auch Speichereffizienz.

Die vier grundlegenden Objekttypen in Gits Objektspeicher (.git/objects/) sind:

  • Blob — roher Dateiinhalt, adressiert durch SHA-Hash
  • Tree — eine Verzeichnisliste, die Dateinamen auf Blob- oder Subtree-Hashes abbildet
  • Commit — ein Zeiger auf einen Tree, null oder mehr übergeordnete Commits, Autoren-Metadaten und eine Nachricht
  • Tag — ein annotierter Zeiger auf einen bestimmten Commit, verwendet für Release-Markierungen

Jedes Objekt ist unveränderlich und inhaltsadressiert. Das Ändern eines einzelnen Bytes in einer Datei erzeugt einen völlig anderen SHA-Hash, der sich durch die Tree- und Commit-Objekte nach oben fortsetzt. Deshalb ist Gits Historie kryptografisch manipulationssicher — man kann einen vergangenen Commit nicht stillschweigend ändern, ohne jeden nachfolgenden Commit-Hash zu verändern.

Der Staging-Bereich (auch Index genannt, gespeichert unter .git/index) ist eine Binärdatei, die den vorgeschlagenen nächsten Commit enthält. Dieses Drei-Zonen-Modell — Arbeitsverzeichnis, Index, Repository — ist Gits am meisten missverstandenes Architekturmerkmal und die Quelle der meisten Verwirrung bei Anfängern.

Git installieren und konfigurieren

Bevor Sie Befehle ausführen, überprüfen Sie Ihre Installation und konfigurieren Sie Ihre Identität. Git bettet Autoreninformationen in jedes Commit-Objekt ein, und eine falsch konfigurierte Identität ist eine der häufigsten Ursachen für unübersichtliche Commit-Historien in gemeinsamen Repositorys.

# Verify installation
git --version

# Set global identity (stored in ~/.gitconfig)
git config --global user.name "Your Name"
git config --global user.email "you@example.com"

# Set default branch name to 'main' (modern convention)
git config --global init.defaultBranch main

# Set preferred editor for commit messages
git config --global core.editor "vim"

# Enable colored output
git config --global color.ui auto

# Verify configuration
git config --list

Die Konfiguration ist mehrschichtig: --system (alle Benutzer, /etc/gitconfig), --global (aktueller Benutzer, ~/.gitconfig) und --local (Repository, .git/config). Spezifischere Bereiche überschreiben allgemeinere.

Wesentliche Git-Befehle: Vollständige Referenz

Initialisieren und Klonen

git init erstellt ein neues Repository, indem ein .git/-Verzeichnis in den aktuellen Ordner geschrieben wird. Es werden keine Commits erstellt — das Repository startet leer.

git init
git init my-project        # Initialize into a new subdirectory
git init --bare repo.git   # Bare repository (no working tree, used for servers)

Ein Bare-Repository enthält nur den Objektspeicher und Refs — kein Arbeitsverzeichnis. Dies ist das korrekte Format für ein Remote-Repository, in das mehrere Entwickler pushen. Wenn Sie Git selbst auf einem VPS Hosting-Server hosten, initialisieren Sie gemeinsame Repositorys immer als Bare.

git clone erstellt eine vollständige lokale Kopie eines Remote-Repositorys, einschließlich aller Branches, Tags und der Historie.

git clone https://github.com/user/repo.git
git clone git@github.com:user/repo.git          # SSH transport (preferred for auth)
git clone --depth 1 https://github.com/user/repo.git  # Shallow clone (latest commit only)
git clone --branch develop https://github.com/user/repo.git  # Clone specific branch

Shallow Clones (--depth) sind nützlich für CI/CD-Pipelines, bei denen Sie nur den aktuellen Zustand benötigen, nicht die vollständige Historie. Sie reduzieren die Klonzeit bei großen Repositorys erheblich, verhindern jedoch einige historienabhängige Operationen wie git bisect.

Zustand inspizieren

git status ist der am häufigsten ausgeführte Befehl in jedem Workflow. Er zeigt den Drei-Zonen-Zustand Ihres Repositorys.

git status
git status -s    # Short format: two-column status codes
git status -sb   # Short format with branch info

git diff vergleicht Inhalte über Zonen oder Commits hinweg.

git diff                    # Working directory vs. index (unstaged changes)
git diff --staged           # Index vs. last commit (what will be committed)
git diff HEAD               # Working directory vs. last commit (all changes)
git diff main..feature      # Compare tips of two branches
git diff abc123..def456     # Compare two specific commits
git diff --stat             # Show changed files and line counts only

git log durchläuft den Commit-Graphen. Seine Filteroptionen gehören zu Gits leistungsstärksten und am wenigsten genutzten Funktionen.

git log
git log --oneline --graph --decorate --all   # Visual branch graph
git log -p                                   # Show patch (diff) for each commit
git log --author="Jane"                      # Filter by author
git log --since="2 weeks ago"               # Filter by date
git log --grep="fix:"                        # Filter by commit message pattern
git log -- path/to/file                      # History of a specific file
git log --follow -- path/to/file             # Follow renames

Die Kombination --graph --oneline --decorate --all ist so universell nützlich, dass die meisten Entwickler einen Alias dafür anlegen:

git config --global alias.lg "log --oneline --graph --decorate --all"

Staging und Committing

git add filename.py          # Stage a specific file
git add src/                 # Stage an entire directory
git add .                    # Stage all changes in current directory
git add -p                   # Interactive patch staging (stage hunks, not whole files)
git add -u                   # Stage modifications and deletions, but not new files

Interaktives Staging (git add -p) ist eine der leistungsstärksten und am wenigsten genutzten Funktionen von Git. Es ermöglicht Ihnen, einzelne Hunks innerhalb einer Datei zu überprüfen und selektiv zu stagen, was präzise, atomare Commits ermöglicht, selbst wenn Ihr Arbeitsverzeichnis mehrere nicht zusammenhängende Änderungen enthält.

git commit -m "feat: add OAuth2 token refresh logic"
git commit --amend           # Modify the most recent commit (message or content)
git commit --amend --no-edit # Amend content without changing the message
git commit -v                # Open editor showing full diff of staged changes

Kritische Regel: Ändern Sie niemals Commits, die bereits in ein gemeinsames Remote gepusht wurden. Das Amenden überschreibt den Commit-Hash und zwingt Mitarbeiter dazu, ihre lokalen Branches zu rebasen oder zurückzusetzen.

Pushen und Pullen

git push origin main
git push origin feature/auth     # Push a specific branch
git push -u origin feature/auth  # Push and set upstream tracking
git push --force-with-lease      # Safer force push (fails if remote has new commits)
git push origin --delete old-branch  # Delete a remote branch
git push --tags                  # Push all local tags

Bevorzugen Sie --force-with-lease gegenüber --force, wenn Sie die Remote-Historie neu schreiben müssen. Es prüft, ob niemand anderes seit Ihrem letzten Fetch gepusht hat, und verhindert so versehentlichen Datenverlust.

git pull origin main
git pull --rebase origin main    # Fetch and rebase instead of merge
git pull --ff-only               # Only fast-forward; abort if a merge commit would be created

git fetch lädt Remote-Änderungen herunter, ohne Ihr Arbeitsverzeichnis oder den aktuellen Branch zu berühren. Dies ist der sichere Weg, um vorgelagerte Änderungen zu inspizieren, bevor Sie sie integrieren.

git fetch origin
git fetch --all          # Fetch from all remotes
git fetch --prune        # Remove remote-tracking branches that no longer exist upstream

Branching und Merging: Der Kern-Workflow

Gits Branching-Modell ist sein architektonisch bedeutendstes Merkmal. Ein Branch ist einfach ein benannter Zeiger (eine 41-Byte-Datei in .git/refs/heads/) auf einen Commit-Hash. Das Erstellen eines Branches ist unabhängig von der Repository-Größe sofortig.

Branch-Verwaltung

git branch                        # List local branches
git branch -a                     # List all branches (local and remote-tracking)
git branch -v                     # List branches with last commit info
git branch feature/user-auth      # Create a new branch
git branch -d feature/user-auth   # Delete merged branch
git branch -D feature/user-auth   # Force delete (even if unmerged)
git branch -m old-name new-name   # Rename a branch

Branches wechseln

Modernes Git (2.23+) trennt die Aufgaben von git checkout in zwei dedizierte Befehle:

git switch main                   # Switch to existing branch
git switch -c feature/payments    # Create and switch in one step
git restore filename.py           # Discard working directory changes to a file
git restore --staged filename.py  # Unstage a file (remove from index)

git checkout funktioniert weiterhin für all diese Fälle, aber git switch und git restore haben klarere, weniger mehrdeutige Semantik und sollten in modernen Workflows bevorzugt werden.

Merge-Strategien

git merge feature/user-auth           # Standard merge (creates merge commit if needed)
git merge --no-ff feature/user-auth   # Always create merge commit (preserves branch topology)
git merge --squash feature/user-auth  # Squash all branch commits into one staged change
git merge --abort                     # Abort an in-progress conflicted merge

Fast-Forward-Merge tritt auf, wenn der Ziel-Branch nicht vom Quell-Branch abgewichen ist — Git bewegt den Zeiger einfach vorwärts. Es wird kein Merge-Commit erstellt. --no-ff erzwingt einen Merge-Commit auch in diesem Fall, was die visuelle Historie von Feature-Branches in git log --graph bewahrt.

Squash-Merge fasst alle Commits eines Feature-Branches in eine einzige gestagete Änderung zusammen, die Sie dann manuell committen. Dies erzeugt eine saubere lineare Historie auf main, verwirft jedoch die granulare Commit-Historie des Feature-Branches.

Rebasing

git rebase spielt Commits von einem Branch auf einem anderen ab und schreibt deren Hashes neu, um eine lineare Historie zu erstellen.

git rebase main                  # Rebase current branch onto main
git rebase -i HEAD~5             # Interactive rebase: edit last 5 commits
git rebase --onto main server client  # Transplant client branch onto main, excluding server
git rebase --abort               # Abort a rebase in progress
git rebase --continue            # Continue after resolving a conflict

Interaktives Rebase (-i) ist das Commit-Hygiene-Werkzeug des Profis. Es ermöglicht Ihnen, Commits neu zu ordnen, zu squashen, zu bearbeiten, zu verwerfen oder aufzuteilen, bevor Sie sie teilen. Häufiger Anwendungsfall: Bereinigung eines unübersichtlichen Feature-Branches vor dem Öffnen eines Pull Requests.

StrategieHistorieAnwendungsfallRisiko
Merge (Standard)Nicht-linear, bewahrt BranchesLanglebige Feature-BranchesUnübersichtliches `git log`
Merge `–no-ff`Nicht-linear, explizite Merge-CommitsErzwungene Branch-TopologieWie oben
Merge `–squash`Linear, ein Commit pro FeatureSauberer Main-BranchVerliert granulare Historie
RebaseLinear, keine Merge-CommitsPersönliche Branches, Pre-PR-BereinigungSchreibt Hashes neu; gefährlich auf gemeinsamen Branches
Cherry-pickSelektiv, linearBackporting von FixesDoppelte Commits über Branches hinweg

Die goldene Regel des Rebasings: Rebasen Sie niemals Commits, die auf einem öffentlichen, gemeinsamen Branch existieren. Rebasing schreibt Commit-Hashes neu. Wenn ein Teammitglied Arbeit auf diesen Commits aufgebaut hat, wird seine Historie abweichen und er wird mit einer schmerzhaften Abstimmung konfrontiert.

Merge-Konflikte lösen

Konflikte treten auf, wenn zwei Branches denselben Bereich derselben Datei ändern. Git markiert den Konflikt in der Datei mit Standard-Konfliktmarkierungen:

<<<<<<< HEAD
const timeout = 30000;
=======
const timeout = 60000;
>>>>>>> feature/increase-timeout

Auflösungs-Workflow:

# After a conflicted merge or rebase
git status                    # Identify conflicted files (marked as "both modified")
# Edit each conflicted file, remove markers, keep correct content
git add resolved-file.js      # Mark as resolved
git commit                    # Complete the merge (message is pre-populated)

Für komplexe Konflikte bietet ein Drei-Wege-Merge-Tool eine klarere Ansicht:

git mergetool                 # Launch configured merge tool (vimdiff, meld, etc.)
git config --global merge.tool vimdiff

Änderungen rückgängig machen: Die Entscheidungsmatrix

Die Wahl des falschen Rückgängig-Befehls ist eine der häufigsten Arten, wie Entwickler Arbeit verlieren oder die gemeinsame Historie beschädigen. Die richtige Wahl hängt von zwei Variablen ab: wo die Änderung liegt und ob sie gepusht wurde.

SzenarioBefehlSchreibt Historie neuSicher auf gemeinsamem Branch
Datei aus Staging entfernen`git restore –staged file`NeinJa
Arbeitsverzeichnis-Änderungen verwerfen`git restore file`NeinJa
Letzten Commit rückgängig machen, Änderungen gestaged behalten`git reset –soft HEAD~1`JaNein
Letzten Commit rückgängig machen, Änderungen ungestaged behalten`git reset HEAD~1`JaNein
Letzten Commit rückgängig machen, alle Änderungen verwerfen`git reset –hard HEAD~1`JaNein
Einen gepushten Commit sicher rückgängig machen`git revert <hash>`NeinJa
Eine Datei aus der gesamten Historie entfernen`git filter-repo`JaNein
git reset --soft HEAD~1      # Undo commit, keep changes in index
git reset HEAD~1             # Undo commit, keep changes in working dir
git reset --hard HEAD~1      # Undo commit, discard all changes permanently

git revert abc1234           # Create new commit that inverts abc1234
git revert HEAD~3..HEAD      # Revert last 3 commits (creates 3 revert commits)
git revert -n HEAD~3..HEAD   # Stage the reversals without committing (batch revert)

git reset --hard ist durch normale Git-Befehle nicht rückgängig zu machen. Wenn Sie ihn versehentlich ausführen, ist Ihr einziger Wiederherstellungspfad git reflog, das jede Position aufzeichnet, auf die HEAD für ungefähr 90 Tage gezeigt hat.

git reflog                   # Show HEAD movement history with hashes
git checkout -b recovery abc1234  # Recover by creating a branch at the lost commit

Erweiterte Befehle für Produktions-Workflows

git stash

git stash speichert Ihren aktuellen Arbeitsverzeichnis- und Index-Zustand auf einem Stack und gibt Ihnen einen sauberen Arbeitsbaum zum Kontextwechsel.

git stash                        # Stash tracked changes
git stash -u                     # Include untracked files
git stash push -m "WIP: auth refactor"  # Stash with a descriptive name
git stash list                   # List all stash entries
git stash pop                    # Apply most recent stash and remove it from stack
git stash apply stash@{2}        # Apply specific stash without removing it
git stash drop stash@{2}         # Delete a specific stash entry
git stash branch feature/wip     # Create a new branch from a stash

git cherry-pick

git cherry-pick abc1234                    # Apply a single commit to current branch
git cherry-pick abc1234 def5678            # Apply multiple commits
git cherry-pick abc1234 --no-commit        # Apply changes without committing
git cherry-pick main~3..main              # Apply a range of commits

Cherry-pick ist der Standardmechanismus für das Backporting von Bug-Fixes auf Wartungs-Branches. Wenn Sie eine kritische Sicherheitslücke auf main beheben, cherry-picken Sie diesen Commit auf v2.1-stable und v2.0-stable, ohne nicht zusammenhängende Features zu mergen.

git bisect

git bisect führt eine binäre Suche durch die Commit-Historie durch, um den genauen Commit zu finden, der einen Bug eingeführt hat. Es ist eines von Gits leistungsstärksten und am wenigsten bekannten Debugging-Werkzeugen.

git bisect start
git bisect bad                   # Mark current commit as broken
git bisect good v2.3.0           # Mark a known-good commit or tag
# Git checks out the midpoint commit automatically
# Test your code, then:
git bisect good                  # If this commit is fine
git bisect bad                   # If this commit is broken
# Repeat until Git identifies the first bad commit
git bisect reset                 # Return to original HEAD when done

Bei einem Repository mit 1.000 Commits zwischen dem guten und dem schlechten Punkt findet git bisect den Verursacher in höchstens 10 Schritten.

git tag

Tags markieren bestimmte Commits als bedeutsam — typischerweise Release-Versionen.

git tag v1.4.2                          # Lightweight tag (just a pointer)
git tag -a v1.4.2 -m "Release 1.4.2"   # Annotated tag (recommended; stores metadata)
git tag -a v1.4.2 abc1234              # Tag a specific past commit
git push origin v1.4.2                 # Push a specific tag
git push origin --tags                 # Push all tags
git tag -d v1.4.2                      # Delete local tag
git push origin --delete v1.4.2        # Delete remote tag

Verwenden Sie immer annotierte Tags für Releases. Sie speichern den Namen, die E-Mail, das Datum und eine Nachricht des Taggers und können mit GPG signiert werden. Leichtgewichtige Tags sind nur für temporäre lokale Lesezeichen geeignet.

git worktree

git worktree ermöglicht es, mehrere Arbeitsverzeichnisse gleichzeitig aus demselben Repository auszuchecken — jedes auf einem anderen Branch. Dies eliminiert die Notwendigkeit, Arbeit zu stashen oder zu committen, wenn Sie zu einem Hotfix wechseln müssen.

git worktree add ../hotfix-branch hotfix/critical-auth-bug
git worktree list
git worktree remove ../hotfix-branch

Dies ist besonders wertvoll auf einem Dedicated Server, der eine CI/CD-Pipeline betreibt, bei der mehrere Build-Jobs gleichzeitig Zugriff auf verschiedene Branches desselben Repositorys benötigen, ohne sich gegenseitig zu beeinträchtigen.

Git-Workflows für Teams

Die richtige Branching-Strategie hängt von Ihrem Release-Rhythmus und der Teamgröße ab. Es gibt drei dominante Modelle:

Feature-Branch-Workflow

Jedes Feature oder jeder Fix lebt auf seinem eigenen Branch. Entwickler öffnen Pull Requests, um in main zu mergen. Einfach und effektiv für die meisten Teams.

Gitflow

Definiert langlebige main– und develop-Branches sowie kurzlebige feature/-, release/– und hotfix/-Branches mit strikten Merge-Regeln. Geeignet für Software mit expliziten versionierten Releases (Bibliotheken, gepackte Anwendungen).

Trunk-Based Development

Entwickler committen direkt auf main (oder verwenden sehr kurzlebige Branches, die innerhalb eines Tages gemergt werden). Verlässt sich stark auf Feature-Flags, um unvollständige Arbeit zu verbergen. Bevorzugt von hochgeschwindigkeits-Teams, die Continuous Deployment praktizieren.

WorkflowRelease-RhythmusTeamgrößeCI/CD-Komplexität
Feature BranchFlexibelBeliebigNiedrig
GitflowGeplante ReleasesMittel–GroßMittel
Trunk-BasedContinuous DeploymentBeliebigHoch

Git-Repositorys hosten: Selbst gehostet vs. verwaltete Plattformen

Für Teams, die Datensouveränität, Compliance oder private Infrastruktur benötigen, ist das Selbst-Hosten eines Git-Servers eine praktikable und oft notwendige Wahl. Optionen umfassen Gitea (leichtgewichtig, Go-basiert), GitLab CE (vollständige DevOps-Plattform) und Forgejo (Gitea-Fork mit Community-Governance).

Eine minimale selbst gehostete Gitea-Instanz läuft komfortabel auf einem VPS Hosting-Plan mit 2 vCPUs und 2 GB RAM. Für größere Teams oder GitLab CE mit CI-Runnern sind 4–8 GB RAM das praktische Minimum.

Beim Selbst-Hosten sichern Sie Ihren Git-Server mit:

  • SSH-Schlüssel-Authentifizierung (Passwort-Authentifizierung vollständig deaktivieren)
  • HTTPS mit einem gültigen Zertifikat — SSL Certificates sind unerlässlich zum Schutz von Anmeldedaten während der Übertragung
  • Firewall-Regeln, die die Git-Port-Exposition einschränken (22 oder benutzerdefinierter SSH-Port, 443 für HTTPS)
  • Regelmäßige automatisierte Backups der .git Bare-Repository-Verzeichnisse
  • Webhook-Secrets für CI/CD-Integrationen

Für Teams, die Git-basierte Deployment-Pipelines verwenden und auch Web-Infrastruktur verwalten, bietet die Kombination eines selbst gehosteten Git-Servers mit einem VPS mit cPanel integrierte Deployment-Hooks neben vertrauten Hosting-Verwaltungstools.

Git Hooks: Qualitätsgates automatisieren

Git Hooks sind Skripte, die automatisch an bestimmten Punkten im Git-Lebenszyklus ausgeführt werden. Sie befinden sich in .git/hooks/ und werden standardmäßig nicht in das Repository committet (verwenden Sie ein Tool wie pre-commit oder husky, um sie zu teilen).

Wichtige Hooks für Produktions-Workflows:

HookAuslöserHäufige Verwendung
`pre-commit`Bevor der Commit erstellt wirdLinter, Formatter, Tests ausführen
`commit-msg`Nachdem die Commit-Nachricht geschrieben wurdeConventional-Commit-Format durchsetzen
`pre-push`Vor dem Push zum RemoteVollständige Test-Suite ausführen
`post-receive`Nachdem das Remote einen Push empfangen hatDeployment auslösen, Benachrichtigungen senden
`pre-rebase`Bevor Rebase beginntRebasing gemeinsamer Branches verhindern
# Example pre-commit hook: reject commits with debug print statements
#!/bin/bash
if git diff --cached | grep -E '^+.*(console.log|debugger|print("DEBUG)'; then
  echo "ERROR: Debug statement detected. Remove before committing."
  exit 1
fi

Der post-receive-Hook auf einem Bare-Server-Repository ist die Grundlage für einfaches Git-basiertes Deployment: Push zum Server, der Hook checkt den neuen HEAD in das Web-Root aus, führt Build-Schritte aus und startet Dienste neu — keine externe CI-Plattform erforderlich.

.gitignore: Repositorys sauber halten

Die .gitignore-Datei teilt Git mit, welche Dateien und Muster unverfolgt bleiben sollen. Sie sollte in das Repository committet und sorgfältig gepflegt werden.

# Dependencies
node_modules/
vendor/

# Build artifacts
dist/
build/
*.o
*.pyc
__pycache__/

# Environment and secrets — NEVER commit these
.env
.env.local
*.pem
*.key
config/secrets.yml

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

# OS files
.DS_Store
Thumbs.db

Kritische Falle: Wenn eine Datei bereits verfolgt wurde, bevor sie zu .gitignore hinzugefügt wurde, wird Git sie weiterhin verfolgen. Sie müssen sie explizit aus der Verfolgung entfernen:

git rm --cached path/to/sensitive-file
git commit -m "chore: stop tracking secrets file"

Committen Sie niemals Anmeldedaten, API-Schlüssel oder private Schlüssel in ein Repository — auch nicht in ein privates. Verwenden Sie Umgebungsvariablen, Secrets-Manager (HashiCorp Vault, AWS Secrets Manager) oder .env-Dateien, die .gitignored sind.

Performance-Optimierung für große Repositorys

Standard-Git verschlechtert sich bei Repositorys mit Millionen von Dateien oder Gigabytes an binären Assets. Gegenmaßnahmen:

  • Git LFS (Large File Storage): Ersetzt große Binärdateien durch Pointer-Dateien im Repository und speichert den eigentlichen Inhalt auf einem separaten LFS-Server. Unerlässlich für Repositorys mit Medien, ML-Modellgewichten oder kompilierten Binärdateien.
  • Partial Clone: git clone --filter=blob:none lädt Commits und Trees herunter, ruft aber Blobs bei Bedarf ab. Reduziert die anfängliche Klongröße für große Monorepos erheblich.
  • Sparse Checkout: git sparse-checkout set path/to/subdir checkt nur eine Teilmenge des Arbeitsbaums aus. Nützlich in Monorepos, wo ein Entwickler nur in einem Service-Verzeichnis arbeitet.
  • Commit-Graph-Datei: git commit-graph write --reachable berechnet den Commit-Graphen vor und beschleunigt Operationen wie git log --graph und Erreichbarkeitsabfragen bei großen Historien.
  • git maintenance start: Plant Hintergrund-Wartungsaufgaben (Loose-Object-Packing, Commit-Graph-Updates, Fetch-Prefetch), um Repository-Operationen über die Zeit schnell zu halten.

Technische Schlüssel-Checkliste

Bevor Sie Ihr Git-Setup als produktionsbereit betrachten, überprüfen Sie jedes der folgenden Punkte:

  • Identität konfiguriert: user.name und user.email korrekt im entsprechenden Konfigurationsbereich gesetzt
  • SSH-Schlüssel in Verwendung: Passwort-Authentifizierung zu Remotes durch SSH-Schlüsselpaare oder token-basiertes HTTPS ersetzt
  • .gitignore committet: Secrets, Build-Artefakte und OS-Dateien vor dem ersten Commit ausgeschlossen
  • Standard-Branch main benannt: init.defaultBranch global gesetzt, um veraltete master-Benennung zu vermeiden
  • Commit-Nachrichten folgen einer Konvention: Conventional Commits (feat:, fix:, chore:) oder teamvereinbartes Format über commit-msg-Hook durchgesetzt
  • git revert für öffentliche Historie: git reset --hard nur auf lokalen, nicht gepushten Commits verwendet
  • --force-with-lease statt --force: Verhindert versehentliches Überschreiben der Pushes von Teammitgliedern
  • Annotierte Tags für Releases: git tag -a mit einer Nachricht, keine leichtgewichtigen Tags
  • Hooks über pre-commit oder husky geteilt: Qualitätsgates konsistent im gesamten Team durchgesetzt
  • Git LFS konfiguriert, wenn das Repository binäre Assets über 1 MB enthält
  • Bare-Repository auf Server: Selbst gehostete Remotes mit git init --bare initialisiert
  • Regelmäßiges git fetch --prune: Remote-Tracking-Branches mit dem tatsächlichen Remote-Zustand synchron gehalten

Häufig gestellte Fragen

Was ist der Unterschied zwischen git fetch und git pull?

git fetch lädt Commits, Branches und Tags vom Remote in Ihre lokalen Remote-Tracking-Refs herunter (z.B. origin/main), ohne Ihr Arbeitsverzeichnis oder den aktuellen Branch zu berühren. git pull ist git fetch gefolgt unmittelbar von git merge (oder git rebase, wenn konfiguriert). Verwenden Sie git fetch, wenn Sie vorgelagerte Änderungen inspizieren möchten, bevor Sie sie integrieren.

Wann sollte ich git rebase statt git merge verwenden?

Verwenden Sie Rebase, um Ihren lokalen Feature-Branch zu linearisieren, bevor Sie einen Pull Request öffnen, um die Projekthistorie lesbar zu halten. Rebasen Sie niemals einen Branch, den andere Entwickler bereits geklont haben oder auf dem sie Arbeit aufgebaut haben — das Neuschreiben veröffentlichter Commit-Hashes zwingt alle anderen, abweichende Historien manuell abzustimmen.

Wie entferne ich dauerhaft eine sensible Datei, die versehentlich committet wurde?

Verwenden Sie git filter-repo (den modernen Ersatz für git filter-branch): git filter-repo --path secrets.env --invert-paths. Dies schreibt die gesamte Repository-Historie neu und entfernt die Datei aus jedem Commit. Nach dem Neuschreiben alle Branches und Tags force-pushen, dann die exponierten Anmeldedaten sofort rotieren — gehen Sie davon aus, dass sie kompromittiert sind, unabhängig davon, wie schnell Sie handeln.

Was ist ein Detached-HEAD-Zustand und wie erholt man sich davon?

Detached HEAD bedeutet, dass Ihr HEAD-Zeiger direkt auf einen bestimmten Commit-Hash verweist anstatt auf einen Branch-Namen. Alle Commits, die Sie machen, gehören keinem Branch an und werden unerreichbar, nachdem Sie wechseln. Zur Wiederherstellung: git switch -c new-branch-name, um die Commits an einen neuen Branch anzuhängen, oder git switch main, um sie zu verwerfen.

Wie behandelt Git Binärdateien anders als Textdateien?

Git speichert Binärdateien als opake Blobs — es kann keine aussagekräftigen zeilenweisen Diffs berechnen oder automatische Merges auf ihnen durchführen. Konflikte in Binärdateien müssen durch die vollständige Auswahl einer Version gelöst werden. Für Repositorys mit erheblichen binären Assets konfigurieren Sie Git LFS, um Binärdateien extern zu speichern und das Repository selbst schlank und schnell zu halten.

15%

15% auf alle Hosting-Dienste sparen

Teste deine Fähigkeiten und erhalte Rabatt auf jeden Hosting-Plan

Benutze den Code:

Skills
Anfangen