Git ist seit 2005 das weltweit dominierende Werkzeug für verteilte Versionsverwaltung. Geschrieben hat es Linus Torvalds, ursprünglich für die Linux-Kernel-Entwicklung; heute wird es weit über Quellcode hinaus eingesetzt. In unserem Alltag versionieren wir mit Git auch TEI-Editionsdaten, Server-Konfigurationen und strukturierte Markdown-Inhalte.
Verteilt heisst: jede Kopie ist vollständig
Anders als die alten zentralen Versionssysteme (CVS, Subversion) hat in Git jede:r Mitwirkende eine vollständige Kopie der gesamten Historie. Es gibt deshalb keinen «Master-Server», sondern nur Konventionen: Wir vereinbaren ein Repo (z. B. auf GitHub) als gemeinsamen Synchronisationspunkt, aber technisch sind alle Kopien gleichwertig. Das macht Branching billig, Offline-Arbeit selbstverständlich und vor allem die Historie selbst zur Datenstruktur — jeder Commit ist ein Snapshot, identifiziert durch einen kryptografischen Hash, verkettet mit seinen Vorgängern.
Die vier Datenspeicher
Lokal hält Git die Daten an drei Orten parallel — und tauscht sie mit einem (oder mehreren) entfernten Repos aus:
- Working Tree — die Dateien, mit denen du gerade arbeitest.
- Stage (auch Index) — eine Zwischenstufe, in der man auswählt, welche Änderungen in den nächsten Commit gehen sollen.
- Local Repo — die Historie aller Commits dieses Klons, gespeichert im
.git-Ordner. - Remote Repo — eine andere Kopie, typischerweise auf einem Server (GitHub, GitLab, eigener Host).
Die Befehle in der Grafik sind die häufigsten Bewegungen zwischen diesen Stores. Wer das Modell einmal verinnerlicht hat, versteht alle weiteren Git-Befehle als Variationen davon.
Alltäglich gebrauchte Kommandos
git status -s # was hat sich geändert?
git diff # unstaged Änderungen
git diff --staged # staged Änderungen
git add <datei> # zur nächsten Aufnahme markieren
git add -p # interaktiv, hunk für hunk
git commit -m "Beschreibung"
git log --oneline --graph --decorate -20 # kompakte Historie
git push # eigene Commits zum Remote
git pull --rebase # Remote-Stand übernehmen
Branches
Branches sind in Git billig — ein Branch ist nicht mehr als ein Pointer auf einen Commit. Daher: lieber häufiger neue Branches anlegen als versuchen, alles im Hauptbranch zu jonglieren.
git switch -c feature/abc # Branch erstellen + wechseln
git switch main # zurück
git merge feature/abc # zurückführen
git branch -d feature/abc # nach Merge aufräumen
git switch und git restore (seit 2.23) sind die modernen Alternativen zum überladenen git checkout.
Rückgängig machen
Drei Mechanismen mit unterschiedlicher Tragweite:
git restore <datei>— Datei aus dem Working Tree zurücksetzen (Änderungen verwerfen).git reset --soft HEAD~1— letzten Commit aus dem Branch nehmen, Änderungen behalten. Nur lokal!git revert <commit>— sicherer Weg für Geschichte, die schon publiziert ist: ein neuer Commit, der den alten rückwärts anwendet.
Faustregel: reset ist destruktiv für nicht-publizierte Arbeit; revert ist die sichere Variante für Geschichte, die schon hochgeladen ist.
Stash — Arbeit zwischenparken
Wenn du mitten in einer Änderung schnell etwas anderes machen musst:
git stash # alles wegpacken (inkl. -u für untracked)
git switch andere-aufgabe
…
git switch zurück
git stash pop # zurückholen
Konfiguration, die viel Ärger spart
git config --global init.defaultBranch main
git config --global pull.rebase true # statt Merge-Commits beim Pull
git config --global push.autoSetupRemote true # neuer Branch wird beim ersten Push gleich getracked
git config --global rerere.enabled true # Konflikt-Lösungen merken
.gitignore-Pattern
Eine kleine Falle, die uns selbst kürzlich erwischt hat: Pattern ohne führenden / matchen überall im Repo. wp-content/ ignoriert also auch site/public/wp-content/. Ausnahmen mit ! regeln:
wp-content/
!site/public/wp-content/