Konfiguration & Initialisierung
Globale & lokale Konfiguration
Git speichert die Konfiguration auf drei Ebenen: System (/etc/gitconfig), global (~/.gitconfig für den Benutzer) und lokal (.git/config pro Repository). Niedrigere Ebenen überschreiben höhere. Legen Sie immer user.name und user.email vor dem Committen fest, sonst verwenden Commits eine unbrauchbare Standardidentität. Das Setzen von init.defaultBranch auf main vermeidet den veralteten master-Standard und entspricht modernen Konventionen.
# set user identity (required for commits)
git config --global user.name "Alice Lee"
git config --global user.email "[email protected]"
# set default editor and branch name
git config --global core.editor "code --wait"
git config --global init.defaultBranch main
# view all settings and their origin
git config --list --show-origin
# edit config files directly
git config --global --edit # ~/.gitconfig
git config --edit # repo .git/configRepositories erstellen & klonen
git init erstellt ein leeres Repository, indem es ein verstecktes .git-Verzeichnis hinzufügt, das alle Versionsdaten speichert. git clone kopiert ein Remote-Repository inklusive des vollständigen Verlaufs. Verwenden Sie --depth 1 für einen flachen Klon, wenn Sie nur den neuesten Snapshot benötigen (z.B. CI-Builds) — es reduziert die Download-Größe drastisch. --single-branch vermeidet das Abrufen unrelateder Branches.
# create a new repo from scratch in current dir
mkdir my-app && cd my-app
git init
# clone a remote repository
git clone https://github.com/user/repo.git
# clone into a specific folder name
git clone https://github.com/user/repo.git my-folder
# clone a single branch (saves bandwidth)
git clone -b dev --single-branch https://github.com/user/repo.git
# shallow clone: only the latest commit
git clone --depth 1 https://github.com/user/repo.gitAliase & Tastenkürzel
Aliase ermöglichen es, kürzere Namen für häufig verwendete Befehle oder Befehlssequenzen zu definieren. Sie werden im Abschnitt [alias] Ihrer gitconfig gespeichert. Ein Alias, der mit ! beginnt, wird als Shell-Befehl ausgeführt und ermöglicht komplexe Workflows. Der obige lg-Alias erzeugt einen kompakten visuellen Verlaufsgraphen, der äußerst nützlich zum Verstehen der Branch-Struktur ist.
# create shortcuts for common commands
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit
git config --global alias.st status
git config --global alias.lg "log --oneline --graph --all"
# now use them
git co main
git lg
# alias that runs an external command (starts with !)
git config --global alias.unstage "reset HEAD --"
git unstage file.txtHilfe & Dokumentation
Git wird mit umfassender integrierter Dokumentation ausgeliefert. git help <Befehl> öffnet die Manpage in Ihrem Pager. Das Flag -h gibt eine kurze einseitige Zusammenfassung der Optionen. Die Anleitungen (git help -g) umfassen ein Tutorial, ein Glossar und eine Alltags-Workflow-Referenz — hervorragend für Anfänger, die die Terminologie lernen.
# open the full manual for a command
git help commit
git commit --help
# show a concise synopsis
git commit -h
# list all git commands
git help -a
# list all guides (tutorial, glossary, etc.)
git help -g
git help glossary.gitignore-Muster
.gitignore teilt Git mit, welche Dateien von der Versionskontrolle ausgeschlossen werden sollen — unerlässlich für Build-Artefakte, Abhängigkeiten und Secrets. Muster verwenden Glob-Syntax; ein abschließender Schrägstrich entspricht Verzeichnissen. Ein vorgestelltes ! negiert ein Muster und erzwingt das Tracking einer Datei. .gitignore selbst sollte committet werden, damit das Team die Ignore-Regeln teilt. Bereits getrackte Dateien sind von neuen Ignore-Mustern nicht betroffen — entfernen Sie sie zuerst mit git rm --cached.
# .gitignore file — patterns for files to skip
node_modules/
*.log
.env
.env.local
dist/
build/
# but track this specific file even if it matches
!important.log
# ignore all .txt files in build/ but not subdirs
build/*.txt
# ignore everything in a folder except one file
secrets/*
!secrets/template.envStaging & Committen
Status & Staging
Git verwendet ein zweistufiges Modell: Änderungen gelangen in den Staging-Bereich (Index), bevor sie committet werden. git status zeigt, was modifiziert, gestagt und ungetrackt ist. git add -p ermöglicht das Stagen einzelner Hunks eines Patches — unschätzbar, um einen unordentlichen Working Tree in fokussierte, logische Commits aufzuteilen. Verwenden Sie git restore --staged (der moderne Befehl), um das Staging aufzuheben, ohne Ihre Änderungen zu verlieren.
# see current state of working tree
git status
git status -s # short format
git status -sb # short + branch info
# stage changes
git add file.txt # one file
git add src/ # a directory
git add . # all changes in repo
git add -p # stage interactively by hunk
# unstage a file (keep changes in working dir)
git restore --staged file.txt
git reset HEAD file.txt # older syntaxÄnderungen committen
Ein Commit zeichnet einen Snapshot der gestagten Änderungen auf. Schreiben Sie Messages im Imperativ ('add feature' nicht 'added feature'). Das Flag -a stagt nur bereits getrackte Dateien — neue Dateien benötigen weiterhin git add. --amend schreibt den letzten Commit um; verwenden Sie es, um einen Tippfehler zu beheben oder eine vergessene Datei hinzuzufügen, aber amend Sie niemals Commits, die Sie bereits zu einem geteilten Branch gepusht haben.
# commit staged changes with a message
git commit -m "feat: add login form"
# multi-line commit message
git commit -m "feat: add login form" -m "Closes #42"
# stage tracked files AND commit in one step
git commit -am "fix: correct typo"
# amend the previous commit (keep message)
git commit --amend --no-edit
# amend and edit the message
git commit --amend -m "feat: add login form (v2)"Commit-Message-Konventionen
Conventional Commits ist eine weit verbreitete Spezifikation für strukturierte Commit-Messages. Das Typ-Präfix (feat, fix, docs usw.) ermöglicht automatisierte Changelog-Generierung und semantische Versionierung. Der !-Marker zeigt einen Breaking Change an. Eine Leerzeile trennt den Betreff (<=50 Zeichen) vom Body und eine weitere Leerzeile trennt Footer wie 'Closes #123', die Issues auf GitHub automatisch schließen.
# Conventional Commits format
feat: add user registration endpoint
fix: resolve crash on empty cart
docs: update API reference
style: format login component
refactor: extract validation logic
test: add unit tests for parser
chore: upgrade dependencies
# with scope and breaking change marker
feat(api): add pagination to list endpoint
fix!: change default port (BREAKING CHANGE)
# with body and footer
feat: add dark mode
Implement theme toggle using CSS variables.
Closes #128Verlauf mit log ansehen
git log ist das primäre Werkzeug zum Erkunden des Verlaufs. --oneline --graph --all ist die nützlichste Kombination, um die Branch-Struktur auf einen Blick zu verstehen. Sie können nach Autor, Datumsbereich oder Nachrichteninhalt mit --grep filtern. --stat zeigt, welche Dateien sich geändert haben und wie viele Zeilen, während --patch den vollständigen Diff jedes Commits zeigt.
# full history with details
git log
git log --oneline # one line per commit
git log --oneline --graph --all # visual branch graph
git log -n 5 # last 5 commits
# filter by author, date, or message
git log --author="Alice"
git log --since="2 weeks ago"
git log --grep="fix"
# show files changed in each commit
git log --stat
git log --patch # full diffsDiff & Show
git diff vergleicht Snapshots — ohne Argumente zeigt es ungestagte Änderungen gegenüber dem Index. --staged vergleicht den Index mit HEAD. git show zeigt die Metadaten und den Patch eines einzelnen Commits. Die HEAD:path-Syntax ermöglicht es, den Inhalt einer beliebigen Datei bei jedem Commit einzusehen, ohne sie auszuchecken — praktisch, um alte Versionen wiederherzustellen oder den Verlauf zu inspizieren.
# compare working tree, index, and commits
git diff # unstaged changes
git diff --staged # staged but uncommitted
git diff HEAD # all changes vs last commit
git diff main feature # compare two branches
git diff abc1234 def5678 # compare two commits
# inspect a single commit
git show HEAD # latest commit diff + metadata
git show abc1234
git show HEAD:file.txt # view a file at a given commitBranching & Merging
Branches erstellen & wechseln
Branches in Git sind leichtgewichtige Zeiger auf einen Commit — das Erstellen eines Branches erfolgt fast augenblicklich. git switch (Git 2.23+) ist die moderne, sicherere Alternative zu checkout zum Wechseln von Branches und reserviert checkout für das Wiederherstellen von Dateien. -d verweigert das Löschen eines nicht gemergten Branches (schützt Ihre Arbeit); -D erzwingt das Löschen. Löschen Sie Branches immer nach dem Mergen, um die Branch-Liste sauber zu halten.
# list branches
git branch # local branches
git branch -a # local + remote
git branch -vv # with tracking info
# create and switch
git branch feature # create only
git checkout feature # switch to it
git checkout -b feature # create + switch (classic)
git switch -c feature # create + switch (modern)
# delete branches
git branch -d feature # safe delete (merged only)
git branch -D feature # force deleteBranches mergen
Ein Fast-Forward-Merge bewegt einfach den Branch-Zeiger vorwärts, wenn das Ziel keine neuen Commits hat — und erzeugt so einen linearen Verlauf. --no-ff erzwingt einen Merge-Commit und bewahrt die Tatsache, dass ein Branch existierte (nützlich für Feature-Tracking). --squash kombiniert alle Branch-Commits zu einer einzigen gestagten Änderung, die Sie dann einmal committen — großartig, um einen unruhigen Feature-Verlauf vor der Integration in main zu bereinigen.
# merge feature into main
git checkout main
git merge feature
# fast-forward merge (default when possible)
# main just moves forward to feature's commit
# create a merge commit (preserves branch history)
git merge --no-ff feature -m "Merge feature branch"
# squash all feature commits into one
git merge --squash feature
git commit -m "feat: add feature (squashed)"
# abort a merge with conflicts
git merge --abortMerge-Konflikte lösen
Konflikte treten auf, wenn dieselben Zeilen auf zwei Branches unterschiedlich geändert wurden. Git fügt Konflikt-Marker (<<<<<<<, =======, >>>>>>>) ein, die beide Seiten zeigen. Lösen Sie den Konflikt, indem Sie die Datei in den gewünschten Endzustand bearbeiten, dann git add, um sie als gelöst zu markieren. Committen Sie, um den Merge abzuschließen. git mergetool startet ein visuelles Diff-Tool. Wenn Sie überfordert sind, bringt git merge --abort Sie in den Pre-Merge-Zustand zurück.
# a conflict produces markers in the file
# <<<<<<< HEAD
# my changes (current branch)
# =======
# their changes (incoming branch)
# >>>>>>> feature
# edit the file to resolve, then:
git add resolved-file.txt
git commit # finalize the merge
# use a merge tool
git mergetool
# see which files conflict
git status
# abandon the merge
git merge --abortRebasing
Rebase spielt die Commits Ihres Branches auf einen anderen Branch ab und erzeugt einen linearen Verlauf ohne Merge-Commits. Interaktives Rebase (-i) ist ein mächtiges Werkzeug: squash mergt Commits, reword bearbeitet Messages, drop entfernt Commits, edit pausiert, um einen Commit zu modifizieren. NIEMALS Commits rebasen, die bereits gepusht und geteilt wurden — es schreibt den Verlauf um und beschädigt die Repositories der Teammitglieder. Verwenden Sie Rebase nur auf Ihren eigenen lokalen Branches.
# rebase feature onto main (replay feature commits)
git checkout feature
git rebase main
# interactive rebase — rewrite last 5 commits
git rebase -i HEAD~5
# options: pick, reword, squash, fixup, drop, edit
# continue, skip, or abort during a rebase
git rebase --continue
git rebase --skip
git rebase --abort
# rebase while pulling
git pull --rebase origin mainCherry-Picking & Reflog
Cherry-pick wendet einen einzelnen Commit aus einem anderen Branch auf Ihren aktuellen Branch an — nützlich zum Backporten eines Bugfixes, ohne den gesamten Branch zu mergen. Das Reflog ist ein lokales Protokoll jeder HEAD-Bewegung (Commits, Checkouts, Resets), das ~90 Tage aufbewahrt wird. Es ist Ihr Sicherheitsnetz: Selbst nach einem destruktiven Reset können Sie den alten Commit-Hash im Reflog finden und wiederherstellen. Reflog-Daten sind nur lokal und werden nie gepusht.
# apply a specific commit onto current branch
git cherry-pick abc1234
git cherry-pick abc1234 def5678 # multiple commits
git cherry-pick abc1234..def5678 # range (exclusive start)
# reflog: record of where HEAD has been
git reflog
git reflog show feature
# recover a 'lost' commit
git reset --hard HEAD@{2}
# view a branch's history of moves
git reflog show mainRemote-Repositories
Remotes verwalten
Ein Remote ist eine benannte Referenz auf ein anderes Repository, typischerweise origin für Ihren Fork und upstream für das Originalprojekt. git remote -v zeigt die Fetch- und Push-URLs. Forks auf GitHub verwenden das upstream-Remote, um mit dem Original zu synchronisieren: Fetch von upstream, Merge oder Rebase, dann Push zu origin. set-url ist praktisch, um zwischen HTTPS- und SSH-Authentifizierung zu wechseln.
# list configured remotes
git remote -v
git remote show origin
# add a remote
git remote add origin https://github.com/user/repo.git
# add an upstream remote (for forks)
git remote add upstream https://github.com/original/repo.git
# rename or remove
git remote rename origin upstream
git remote remove origin
# change a remote URL (e.g. HTTPS to SSH)
git remote set-url origin [email protected]:user/repo.gitFetch, Pull & Push
fetch lädt Remote-Daten herunter, lässt aber Ihren Working Tree unangetastet — sicher zum Inspizieren vor dem Mergen. pull = fetch + merge (oder rebase mit --rebase). Der erste Push eines neuen Branches benötigt -u, um Tracking einzurichten, damit zukünftige git push/pull ohne Argumente funktionieren. --force-with-lease ist die sichere Alternative zu --force: Es überschreibt das Remote nur, wenn niemand anderes in der Zwischenzeit gepusht hat, und verhindert versehliches Überschreiben der Arbeit der Teammitglieder.
# download remote changes without merging
git fetch origin
git fetch --all --prune # all remotes, drop deleted branches
# fetch + merge in one step
git pull
git pull --rebase # rebase instead of merge
# push local commits to remote
git push origin main
git push -u origin feature # push + set upstream tracking
git push # subsequent pushes (uses tracking)
# force push (rewrites remote history — DANGER)
git push --force-with-lease # safer than --forceTracking & Synchronisieren von Branches
Tracking-Branches verknüpfen einen lokalen Branch mit einem Remote-Branch, sodass git pull und git push wissen, wohin sie fetchen/pushen sollen, ohne dies anzugeben. -u (kurz für --set-upstream-to) richtet dies beim ersten Push ein. Wenn Teammitglieder Remote-Branches löschen, werden Ihre lokalen Remote-Tracking-Refs veraltet — git remote prune origin bereinigt diese. git fetch --prune macht dies automatisch während des Fetchens.
# set upstream for current branch
git branch -u origin/main
git branch --set-upstream-to=origin/main
# create a local branch tracking a remote one
git checkout -b feature origin/feature
git switch feature # auto-detects tracking branch
# delete a remote branch
git push origin --delete feature
# list all remote-tracking branches
git branch -r
git remote prune origin # remove stale remote refsPull-Request-Workflow
Der Standard-GitHub-Flow: Erstellen Sie einen Feature-Branch, pushen Sie ihn, öffnen Sie einen Pull Request zur Überprüfung und löschen Sie den Branch nach dem Mergen. Für Forks ermöglicht Ihnen das upstream-Remote, Änderungen aus dem Original-Repository zu pullen. Das regelmäßige Synchronisieren Ihres Fork-Mains mit upstream verhindert später große, schmerzhafte Merges. Viele Teams aktivieren 'auto-delete branch on merge', um die Branch-Liste ordentlich zu halten.
# typical feature workflow
git checkout -b feature/login
# ... make changes, commit ...
git push -u origin feature/login
# create PR on GitHub, then after merge:
git checkout main
git pull origin main
git branch -d feature/login
# sync a fork with its upstream
git fetch upstream
git checkout main
git merge upstream/main
git push origin mainBare-Repositories & Mirrors
Ein Bare-Repository hat keinen Working Tree — es speichert nur die .git-Daten. Bare-Repos werden auf Servern (wie selbst gehostetem Git) als zentrales Remote verwendet, zu dem mehrere Personen pushen und von dem sie pullen. --mirror klont alles inklusive Remote-Tracking-Refs und wird für Backups oder die Migration eines Repos zwischen Hosts verwendet. --all pusht alle Branches; --tags pusht alle Tags.
# create a bare repo (no working tree) — for servers
git init --bare project.git
# mirror clone (full copy including all refs)
git clone --mirror https://github.com/user/repo.git
# push all branches and tags
git push --all
git push --tags
# push a specific branch to a specific remote
git push origin local-name:remote-nameÄnderungen rückgängig machen
Reset: Soft, Mixed, Hard
reset bewegt den aktuellen Branch-Zeiger. --soft behält Ihre Änderungen gestagt (nur der Commit wird rückgängig gemacht) — ideal zum Neu-Committen. --mixed (Standard) hebt das Staging auf, behält aber die Working-Tree-Änderungen. --hard verwirft alles dauerhaft — Ihre einzige Wiederherstellung ist das Reflog. Verwenden Sie niemals --hard auf Commits, die Sie gepusht haben, da es den geteilten Verlauf umschreibt und Divergenz verursacht.
# reset moves HEAD and optionally the index/worktree
git reset --soft HEAD~1 # undo commit, keep staged
git reset --mixed HEAD~1 # undo commit + unstage (DEFAULT)
git reset --hard HEAD~1 # undo commit + discard changes
# reset to a specific commit
git reset --hard abc1234
# reset a single file to HEAD
git reset HEAD file.txt # unstage
git checkout -- file.txt # discard working changesRevert (sicheres Rückgängigmachen)
Im Gegensatz zu reset (das den Verlauf umschreibt) fügt revert einen neuen Commit hinzu, der den Zielcommit invertiert — sicher für geteilte Branches, da der Verlauf erhalten bleibt. Dies ist die korrekte Methode, um eine Änderung rückgängig zu machen, die bereits gepusht wurde. Das Reverten eines Merge-Commits erfordert -m 1, um anzugeben, welche Elternlinie beibehalten werden soll (1 = der Branch, in den Sie gemergt haben).
# revert creates a NEW commit that undoes another
git revert abc1234
git revert HEAD # undo last commit
# revert a range
git revert HEAD~3..HEAD
# revert without committing (stage the inverse)
git revert --no-commit abc1234
# revert a merge commit
git revert -m 1 abc1234 # -m 1 = keep main branch parentRestore & Clean
git restore (Git 2.23+) ist der moderne, fokussierte Befehl für Working-Tree-Operationen und trennt die Zuständigkeiten von checkout. --staged hebt das Staging auf, ohne die Working-Änderungen zu berühren. git clean entfernt ungetrackte Dateien — führen Sie es immer zuerst mit -n (Dry Run) aus, um eine Vorschau zu erhalten, was gelöscht wird. -x ist aggressiv: Es löscht auch gitignore-Dateien, was für einen sauberen Build nützlich ist, aber Secrets oder Build-Outputs löschen kann.
# discard unstaged changes in a file
git restore file.txt
git checkout -- file.txt # older syntax
# unstage a file (keep working changes)
git restore --staged file.txt
# restore a file from a specific commit
git restore --source=abc1234 file.txt
# remove untracked files
git clean -n # dry run (preview)
git clean -fd # remove untracked files + dirs
git clean -fdx # also remove ignored filesAmend & Fixup
--amend schreibt den letzten Commit um — praktisch, um einen Tippfehler zu beheben oder eine vergessene Datei hinzuzufügen, aber amend Sie niemals gepushte Commits. Der Fixup-Workflow ist elegant: Erstellen Sie Fixup-Commits, während Sie kleine Probleme bemerken, dann ordnet git rebase -i --autosquash diese automatisch neu an und squasht sie in ihre Ziel-Commits. Dies hält den Verlauf sauber, während Sie kleine Fixes inkrementell committen können.
# amend the last commit (message + content)
git add forgotten-file.txt
git commit --amend --no-edit
# change only the commit message
git commit --amend -m "better message"
# create a fixup commit (for later autosquash)
git commit --fixup=abc1234
# squash fixups during interactive rebase
git rebase -i --autosquash abc1234~1Reflog-Wiederherstellung
Das Reflog ist Ihr Sicherheitsnetz. Es zeichnet jeden Commit, Checkout, Reset und Rebase auf — sogar Operationen, die Commits 'zerstören'. Einträge bleiben ~90 Tage erhalten. Wenn Sie versehentlich reset --hard ausführen oder einen Branch löschen, finden Sie den verwaisten Commit-Hash im Reflog und setzen ihn zurück oder erstellen einen neuen Branch, der darauf zeigt. Das Reflog ist nur lokal, sodass dies auch offline funktioniert.
# reflog records every HEAD movement
git reflog
# abc1234 HEAD@{0}: reset: moving to abc1234
# def5678 HEAD@{1}: commit: feat: add x
# ghi9012 HEAD@{2}: checkout: moving to feature
# recover a 'lost' commit
git reset --hard def5678
# recover a deleted branch
git branch recovered-feature def5678
# reflog for a specific branch
git reflog show featureStashing & Workflows
Änderungen stagen
Stash legt uncommittete Änderungen ab, sodass Sie Branches wechseln oder Updates mit einem sauberen Tree pullen können. apply behält den Stash in der Liste (nützlich, wenn Sie ihn auf mehrere Branches anwenden möchten); pop wendet ihn an und entfernt ihn. Stashes sind ein LIFO-Stack, referenziert durch stash@{N}. Verwenden Sie clear mit Vorsicht — es verwirft dauerhaft alle Stashes.
# save uncommitted changes (reverts working tree to HEAD)
git stash
git stash push -m "wip: login form" # with a message
# list, show, apply
git stash list
git stash show -p stash@{0} # show diff
git stash apply # apply latest, keep stash
git stash pop # apply latest, drop stash
# apply a specific stash
git stash apply stash@{2}
# drop a stash
git stash drop stash@{0}
git stash clear # drop ALL stashesPartielles & selektives Stash
Diese Flags bieten feinkörnige Kontrolle darüber, was gestasht wird. --keep-index ist nützlich, wenn Sie einen logischen Commit gestagt haben, aber nur diese Änderungen testen möchten — stagen Sie den Rest, führen Sie Tests aus, dann pop. -u schließt ungetrackte Dateien ein (andernfalls bleiben sie in Ihrem Working Tree). -p lässt Sie spezifische Hunks auswählen, analog zu git add -p.
# stash only staged changes
git stash --staged
# stash only unstaged changes (keep staged)
git stash --keep-index
# stash interactively by hunk
git stash -p
# stash including untracked files
git stash -u
git stash --include-untracked
# stash everything (even ignored)
git stash -aStash-Branches & Create
git stash branch erstellt einen neuen Branch am ursprünglichen Eltern-Commit des Stash und wendet den Stash dort an — perfekt, wenn ein Stash aufgrund von Konflikten nicht mehr sauber auf den aktuellen Branch angewendet werden kann. Sie können einen Stash auch als Patch-Datei mit show -p für Archivierung oder Freigabe exportieren. Stashes sind lokal und werden nie gepusht, daher sollten sie nicht für die langfristige Speicherung verwendet werden.
# create a branch from a stash (great for conflicts)
git stash branch feature/wip stash@{0}
# create a commit from a stash without applying
git stash store -m "saved wip" stash@{0}
# apply a stash to a different branch
git checkout other-branch
git stash apply stash@{0}
# inspect stash contents
git stash show stash@{0} --stat
git stash show -p stash@{0} > patch.diffGit-Workflow-Modelle
GitHub Flow ist der einfachste: ein main-Branch, Feature-Branches mit PRs, Deployen beim Mergen — ideal für Continuous Deployment. Git Flow (Vincent Driessens Modell) fügt develop-, release- und hotfix-Branches für strukturiertes Release-Management hinzu — geeignet für versionierte Produkte. Trunk-Based Development verwendet sehr kurzlebige Branches und wird von hochperformanten DevOps-Teams für maximale Integrationsgeschwindigkeit bevorzugt.
# GitHub Flow (simple, popular)
# main is always deployable; feature branches + PRs
git checkout -b feature/x
git push -u origin feature/x
# open PR, review, merge to main, deploy
# Git Flow (structured, with release branches)
# main: production releases
# develop: integration branch
# feature/*: features off develop
# release/*: release prep
# hotfix/*: urgent fixes off main
# Trunk-Based Development
# short-lived branches (1-2 days), frequent rebase on mainSubmodules
Submodules betten ein Git-Repository in ein anderes ein — nützlich, um eine Bibliothek über mehrere Projekte hinweg zu teilen, während sie unabhängig versioniert bleibt. Das Parent-Repo speichert einen Zeiger auf einen spezifischen Commit des Submodules. Klons fetchen standardmäßig keine Submodule-Inhalte; --recurse-submodules macht es in einem Schritt. Submodules können knifflig sein; für einfacheres Abhängigkeits-Management ziehen Sie Git subtrees oder einen Package Manager in Betracht.
# add another repo as a submodule
git submodule add https://github.com/user/lib.git libs/lib
# clone a repo with its submodules
git clone --recurse-submodules https://github.com/user/repo.git
# initialize submodules in an existing clone
git submodule update --init --recursive
# update submodules to their latest remote commit
git submodule update --remote
# record a submodule pointer change
git add libs/lib
git commit -m "chore: bump lib submodule"Inspektion & Debugging
Blame & Annotate
git blame (auch annotate genannt) zeigt den Commit und Autor für jede Zeile einer Datei — unerlässlich, um zu verstehen, warum Code so aussieht, wie er aussieht. -L beschränkt auf einen Zeilenbereich, nützlich für große Dateien. -w ignoriert reine Whitespace-Änderungen, und -C erkennt verschobenen oder kopierten Code aus einer anderen Datei und gibt Ihnen eine genauere Historie, wo Zeilen wirklich ihren Ursprung hatten.
# show who last changed each line
git blame file.txt
git blame -L 10,20 file.txt # only lines 10-20
git blame -e file.txt # show author email
git blame -w file.txt # ignore whitespace changes
git blame -C file.txt # detect moved lines across files
# GUI annotation in some editors
git gui blame file.txtBisect (Binärsuche Bugs)
bisect führt eine binäre Suche durch den Verlauf durch, um den genauen Commit zu finden, der einen Bug eingeführt hat. Sie markieren einen bekannten guten und einen bekannten schlechten Commit; Git checkt den Mittelpunkt aus, Sie testen, dann markieren Sie gut oder schlecht, und halbieren den Bereich jedes Mal. Mit einem Skript ist der gesamte Prozess vollständig automatisiert — eine massive Zeitersparnis für Regressionen in großen Verläufen.
# find the commit that introduced a bug
git bisect start
git bisect bad # current commit is broken
git bisect good v1.0.0 # v1.0.0 was working
# Git checks out a midpoint; test it, then:
git bisect good # or git bisect bad
# automate with a script that exits non-zero on bug
git bisect start HEAD v1.0.0 -- npm test
# finish and return to original branch
git bisect reset
# view the bisect log
git bisect logCode & Verlauf durchsuchen
git grep durchsucht getrackte Dateien im Working Tree — schneller als grep -r, da es den Index verwendet. Die -S 'pickaxe'-Option findet Commits, die einen spezifischen String hinzugefügt oder entfernt haben, unschätzbar zum Nachverfolgen, wann eine Funktion oder ein Bug eingeführt wurde. -G ist ähnlich, aber stimmt mit einem Regex überall im Diff überein. Kombiniert mit --author- und --since-Filtern können Sie jede Änderung im Verlauf eingrenzen.
# search working tree for a string
git grep "TODO"
git grep -n "TODO" -- "*.js"
git grep -i "error" src/
# search across all commits (history)
git log -S "functionName" --oneline # pickaxe: when added/removed
git log -G "functionName.*\(" --oneline # regex match in diffs
# search commit messages
git log --grep="fix.*login" --oneline
git log --author="Alice" --since="1 week ago"FSCK & dangling Objects
git fsck (File System Check) verifiziert die Integrität der Objekt-Datenbank und kann dangling Commits finden — nützlich für die Wiederherstellung, wenn das Reflog nicht ausreicht. git gc reorganisiert und komprimiert Objekte, um Speicherplatz zu sparen; --prune=now entfernt unerreichbare Objekte sofort. Git führt periodisch auto-gc aus, aber manuelles Ausführen kann ein großes Repo verkleinern. --aggressive berechnet Deltas für maximale Kompression neu.
# check repository integrity
git fsck --full
git fsck --unreachable
# find dangling (unreachable) commits & blobs
git fsck --lost-found
# garbage collect and prune old objects
git gc
git gc --prune=now
git gc --aggressive
# count objects and disk usage
git count-objects -vArchive & Bundle
git archive exportiert einen sauberen Snapshot eines Commits ohne das .git-Verzeichnis — ideal, um Releases zu verteilen oder Quellcode an jemanden zu senden, der den Verlauf nicht benötigt. git bundle verpackt ein Repo (oder einen Bereich von Commits) in eine einzelne Datei, die geklont oder gefetcht werden kann — perfekt, um Repos über Air-Gapped-Netzwerke oder per E-Mail zu übertragen, wenn Sie keinen Remote-Server verwenden können.
# export a snapshot as a tar/zip (no .git history)
git archive --format=zip --output=app.zip HEAD
git archive --format=tar HEAD | gzip > app.tar.gz
git archive -o release.zip v1.0.0
# bundle a repo (with history) into a single file
git bundle create repo.bundle --all
git bundle create patch.bundle main..feature
# clone from a bundle (offline transfer)
git clone repo.bundle new-repo
git fetch patch.bundle featureFortgeschrittene Techniken
Hooks
Hooks sind Skripte, die automatisch an spezifischen Punkten ausgeführt werden. Client-seitige Hooks (pre-commit, commit-msg, pre-push) erzwingen lokale Richtlinien wie Linting oder Tests. Server-seitige Hooks (pre-receive, post-receive) laufen auf dem Remote und können Branch-Protection erzwingen oder CI/CD triggern. Das Verzeichnis .git/hooks enthält Beispielskripte mit der Endung .sample — umbenennen zum Aktivieren. Tools wie Husky oder das pre-commit-Framework verwalten Hooks im Repo selbst für Team-Konsistenz.
# client-side hooks live in .git/hooks/
# pre-commit runs before a commit is created
# commit-msg validates the commit message
# pre-push runs before pushing to remote
# sample pre-commit hook (.git/hooks/pre-commit)
#!/bin/sh
npm run lint || exit 1
npm test || exit 1
# server-side hooks (on the remote)
# pre-receive, update, post-receive
# make a hook executable
chmod +x .git/hooks/pre-commitWorktrees
Worktrees ermöglichen es Ihnen, mehrere Working Directories für ein einzelnes Repository zu haben, jeweils auf einem anderen Branch — ohne zu klonen. Dies ist unbezahlbar, wenn Sie an einem Hotfix arbeiten müssen, während Sie den Working Tree Ihres Feature-Branches intakt halten, oder einen langen Build auf einem Branch ausführen, während Sie einen anderen bearbeiten. Alle Worktrees teilen sich dieselbe .git-Objekt-Datenbank, daher ist der Speicherplatzbedarf minimal.
# create a second working tree of the same repo
git worktree add ../app-feature feature/x
# list worktrees
git worktree list
# create a worktree with a new branch
git worktree add -b hotfix/y ../app-hotfix main
# remove a worktree
git worktree remove ../app-feature
# prune stale worktree metadata
git worktree pruneVerlauf filtern & umschreiben
Das Umschreiben des Verlaufs ist notwendig, wenn Secrets oder große Dateien committet wurden. git filter-repo ist der moderne, schnelle Ersatz für git filter-branch. BFG Repo-Cleaner ist eine benutzerfreundliche Alternative zum Entfernen großer Dateien oder Passwort-Muster. Nach dem Umschreiben müssen Sie force-pushen und alle Mitarbeiter benachrichtigen, neu zu klonen — alte Commits bleiben in ihren Reflogs bis zum Verfall. Rotieren Sie immer alle geleakten Secrets sofort.
# remove a file from ALL of history (sensitive data)
git filter-repo --path secrets.env --invert-paths
# (install git-filter-repo; the old filter-branch is deprecated)
# rewrite author info across all commits
git filter-repo --mailmap mailmap.txt
# split a subdirectory into its own repo
git filter-repo --subdirectory-filter libs/lib
# the simpler BFG Repo-Cleaner (Java tool)
bfg --delete-files *.env
bfg --replace-text passwords.txtSparse Checkout & Partial Clone
Partial Clone (--filter) fetcht Commits und Trees, lädt aber Blobs (Dateiinhalte) träge herunter, wenn Sie auf sie zugreifen — beschleunigt das Klonen riesiger Repos drastisch. Sparse Checkout beschränkt Ihren Working Tree auf spezifische Verzeichnisse, sodass Sie nur die Teile sehen, an denen Sie arbeiten. Zusammen machen sie enorme Monorepos handhabbar: Der Klon ist schnell und Ihr Working Tree bleibt klein.
# partial clone: download history on demand
git clone --filter=blob:none https://github.com/user/huge-repo.git
# sparse checkout: only certain directories
git clone --no-checkout https://github.com/user/repo.git
cd repo
git sparse-checkout init --cone
git sparse-checkout set src docs
git checkout main
# add a directory to the sparse set later
git sparse-checkout add tests
# disable sparse checkout (fetch everything)
git sparse-checkout disableReflog, Refspec & Notes
Refspecs geben explizite Kontrolle darüber, wie Refs während Fetch/Push abgebildet werden — nützlich für ungewöhnliche Workflows wie das Pushen eines lokalen Feature-Branches zu Remote-Main. git notes fügt Metadaten zu einem Commit hinzu, ohne ihn umzuschreiben, was praktisch für Review-Kommentare oder CI-Links ist. Notes werden in einem separaten Ref (refs/notes/commits) gespeichert und müssen explizit gepusht und gefetcht werden.
# refspec: explicit fetch/push mapping
git fetch origin "refs/heads/*:refs/remotes/origin/*"
git push origin "refs/heads/feature:refs/heads/main"
# add a note to a commit (without changing it)
git notes add -m "Reviewed by Alice" abc1234
git notes show abc1234
git log --show-notes
# configure where notes are stored
git config --global notes.displayRef "refs/notes/*"
# push notes to a remote
git push origin refs/notes/commitsBest Practices & Tipps
Commit-Hygiene
Gute Commits sind klein, atomar und in sich geschlossen: eine logische Änderung pro Commit. Dies macht Code-Review einfacher, Bisecting schneller und Reverts chirurgisch. Verwenden Sie git add -p, um nur die Hunks zu stagen, die zu einem einzelnen Anliegen gehören. Imperative Messages ('add' nicht 'added') lesen sich als Anweisungen an die Codebasis. Das Rebasen von Feature-Branches auf das neueste main vor dem Mergen hält den Verlauf linear und verständlich.
# commit small, focused, logical units
git add -p # stage only relevant hunks
git commit -m "fix: handle null user in login"
# write clear, imperative messages
# GOOD: "feat: add password reset endpoint"
# BAD: "stuff", "fix", "WIP", "asdf"
# one concern per commit
git add login.ts && git commit -m "feat: add login"
git add styles.css && git commit -m "style: format login"
# rebase before merging to keep history clean
git fetch && git rebase origin/mainBranch-Protection & Code-Review
Branch-Protection-Regeln verhindern Force-Pushes, erfordern PR-Reviews und gate Merges auf bestehender CI — essenziell für Team-Sicherheit. Das Erzwingen eines linearen Verlaufs erzwingt Rebase- oder Squash-Merges und hält den Verlauf lesbar. Signierte Commits (GPG oder SSH) beweisen die Autorschaft und verhindern Identitätsdiebstahl. Diese Einstellungen werden auf der Hosting-Plattform (GitHub/GitLab) konfiguriert, nicht in Git selbst, aber sie erzwingen gute Git-Hygiene organisationsweit.
# on GitHub/GitLab: protect the main branch
# - require pull request reviews
# - require status checks (CI) to pass
# - require linear history (no merge commits)
# - dismiss stale reviews on push
# - require signed commits
# enforce via config (GitHub CLI)
gh api repos/:owner/:repo/branches/main/protection \
-X PUT -f required_status_checks[strict]=true
# sign commits and verify on receive
git config --global commit.gpgsign true
git config --global gpg.format sshIgnoring & Secrets-Management
Committete Secrets sind der häufigste Git-Sicherheitsvorfall. Sobald gepusht, gehen Sie davon aus, dass das Secret kompromittiert ist — rotieren Sie es sofort, selbst nach dem Entfernen aus dem Verlauf, da Klons und Forks es behalten. Prävention ist am besten: .gitignore Secrets, verwenden Sie Umgebungsvariablen oder einen Secret Manager (Vault, AWS Secrets Manager) und installieren Sie git-secrets oder einen pre-commit-Hook, der nach API-Keys und Passwörtern vor jedem Commit scannt.
# never commit secrets — use .gitignore
echo ".env" >> .gitignore
echo "*.pem" >> .gitignore
echo "secrets/" >> .gitignore
# if you accidentally committed a secret:
# 1. rotate/revoke the secret immediately
# 2. remove from history
git filter-repo --path .env --invert-paths
git push --force-with-lease
# use environment files or secret managers
echo "API_KEY=$API_KEY" > .env.local # gitignored
# load via dotenv in your app
# use git-secrets to scan pre-commit
git secrets --install
git secrets --register-awsPerformance-Tipps
Große Repositories können langsam sein. fsmonitor und untrackedcache machen git status viel schneller, indem sie den Dateisystem-Zustand cachen. Shallow- und Partial-Clones reduzieren den anfänglichen Download. Führen Sie git gc regelmäßig aus, um Objekte zu komprimieren. --no-verify überspringt pre-commit- und commit-msg-Hooks — nützlich für Notfälle, sollte aber nicht zur Gewohnheit werden, da es die Qualitätsprüfungen Ihres Teams umgeht.
# speed up status on large repos
git config --global core.fsmonitor true
git config --global core.untrackedcache true
# shallow clone for CI
git clone --depth 1 https://github.com/user/repo.git
# partial clone for huge monorepos
git clone --filter=blob:none https://github.com/user/monorepo.git
# periodic garbage collection
git gc --prune=now
# disable slow hooks temporarily
git commit --no-verifyHäufige Fallstricke
Vermeiden Sie diese klassischen Fehler: niemals Force-Push zu geteilten Branches (--force-with-lease ist die sichere Option); niemals Commits rebasen, auf denen andere möglicherweise Arbeit basieren hat; niemals auf einem detached HEAD committen, ohne zuerst einen Branch zu erstellen. Verwenden Sie Git LFS für große Binärdateien — sie blähen sonst den Verlauf dauerhaft auf. Konfigurieren Sie Zeilenenden (autocrlf) pro OS, um lästige Whitespace-only-Diffs in plattformübergreifenden Teams zu vermeiden.
# PITFALL: force-pushing to shared branches
git push --force origin main # DON'T — use --force-with-lease
# PITFALL: rebasing pushed commits
# rebase only your local, unpushed branches
# PITFALL: committing on detached HEAD
git checkout v1.0.0
# changes here are not on a branch — create one:
git checkout -b fix/v1.0.1
# PITFALL: large binary files bloating history
# use Git LFS for binaries
git lfs install
git lfs track "*.psd"
git add .gitattributes
# PITFALL: CRLF/LF line endings across OS
git config --global core.autocrlf input # on Linux/Mac
git config --global core.autocrlf true # on WindowsGit Flow Workflow
Git Flow Branch-Modell
Git Flow ist ein striktes Branching-Modell für Release-basierte Projekte. main hält immer Produktionscode; develop hält Integrationsarbeit. Features branchen von develop und mergen zurück. Releases branchen von develop, stabilisieren sich und mergen dann zu sowohl main (mit einem Tag) als auch develop. Hotfixes branchen von main und mergen zu sowohl main als auch develop. Dieses Modell eignet sich für Projekte mit geplanten Releases (Desktop-Apps, On-Premise-Software). Für Continuous Deployment ist GitHub Flow (main + Feature-Branches) einfacher. Das git-flow-CLI-Tool automatisiert den Branch-Tanz.
# Git Flow uses long-lived branches:
# main → production-ready code
# develop → latest delivered development changes
# feature/* → new features (branched from develop)
# release/* → release preparation (branched from develop)
# hotfix/* → urgent production fixes (branched from main)
# Initialize git-flow (interactive setup)
git flow init
# Start a new feature
git flow feature start my-feature
# Creates feature/my-feature from develop
# Finish a feature (merges to develop, deletes branch)
git flow feature finish my-feature
# Publish a feature to remote
git flow feature publish my-feature
# Start a release
git flow release start 1.2.0
# Creates release/1.2.0 from develop
# Finish a release (merges to main AND develop, tags)
git flow release finish 1.2.0GitHub Flow (einfacher)
GitHub Flow ist der einfachste Workflow: main ist immer deploybar, Feature-Branches sind kurzlebig und alles mergt über Pull Requests. Es gibt keinen develop-Branch oder Release-Branches — main wird kontinuierlich deployed. Dies funktioniert gut für Web-Apps mit Continuous Deployment. Die wichtigste Regel: niemals direkt zu main committen; immer einen PR zur Überprüfung verwenden. Halten Sie Feature-Branches klein und kurzlebig (Tage, nicht Wochen). Löschen Sie Branches nach dem Mergen, um das Repo sauber zu halten. Dieses Modell priorisiert Geschwindigkeit und Einfachheit gegenüber Git Flows strukturiertem Release-Management.
# GitHub Flow: only main + feature branches
# 1. Create branch from main
git checkout main
git pull origin main
git checkout -b feature/add-login
# 2. Commit changes
git add .
git commit -m "feat: add login page"
# 3. Push to remote
git push -u origin feature/add-login
# 4. Open Pull Request on GitHub
# 5. Review, discuss, get approval
# 6. Merge to main (via GitHub UI or CLI)
git checkout main
git pull origin main
git branch -d feature/add-login # delete local branch
# 7. Deploy from main (continuous deployment)Trunk-Based Development
Trunk-Based Development ist die extremste Variante: Entwickler committen direkt zu main (oder sehr kurzlebige Branches, die innerhalb von 24 Stunden gemergt werden). Dies ermöglicht echte Continuous Integration — alle integrieren ständig. Unvollständige Features verwenden Feature Flags (deployed aber versteckt) anstatt langlebiger Branches. Dies erfordert starke CI/CD, umfassende Tests und Feature-Flag-Infrastruktur. Verwendet von Google, Facebook und Netflix. Vorteile: keine Merge-Hölle, schnelles Feedback, kleine Änderungen. Herausforderungen: erfordert Disziplin, Testabdeckung und Feature-Flag-Management. Am besten für erfahrene Teams mit robuster CI/CD.
# Trunk-Based: everyone commits to main (trunk)
# Short-lived feature branches optional
# Direct commit to main (small teams)
git checkout main
git pull
# make changes
git add . && git commit -m "fix: typo in header"
git push
# With short-lived branches (larger teams)
git checkout -b quick-fix
git commit -m "fix: validation bug"
git push
# PR merged within 24 hours
# Feature flags enable incomplete code on main
# Code is deployed but hidden behind a flag
if (featureFlag.isEnabled("new-checkout")) {
showNewCheckout();
} else {
showOldCheckout();
}Fork & Pull Workflow
Der Fork & Pull-Workflow ist Standard für Open Source. Beitragende forken das Repo (erstellen ihre eigene Kopie), pushen Branches zu ihrem Fork und öffnen PRs zum Original-(upstream)-Repo. Das upstream-Remote ermöglicht es Ihnen, Ihren Fork mit dem Original zu synchronisieren. Erstellen Sie immer Feature-Branches von einem aktualisierten main. Dieser Workflow ermöglicht es jedem, ohne Schreibrechte beizutragen. Maintainer reviewen PRs und mergen. Um Ihren Fork synchron zu halten, fetchen Sie upstream und mergen/rebasen regelmäßig. Einige Projekte verwenden ein 'Clone, Branch, PR'-Modell für interne Beitragende mit direktem Push-Zugriff auf Feature-Branches.
# For open-source projects (contributors don't have push access)
# 1. Fork the repo on GitHub (UI button)
# 2. Clone YOUR fork
git clone https://github.com/YOUR-USERNAME/project.git
cd project
# 3. Add upstream (original repo)
git remote add upstream https://github.com/ORIGINAL/project.git
# 4. Keep your fork updated
git fetch upstream
git checkout main
git merge upstream/main # or: git rebase upstream/main
git push origin main
# 5. Create feature branch
git checkout -b feature/my-contribution
# 6. Push to YOUR fork
git push origin feature/my-contribution
# 7. Open Pull Request from your fork to upstreamBranch-Namenskonventionen
Konsistente Branch-Namen verbessern die Klarheit und ermöglichen Automatisierung. Häufige Präfixe: feature, bugfix, hotfix, release, chore, docs, refactor, experiment. Das Einbeziehen von Ticket-Nummern (PROJ-123) verknüpft Branches mit Issues und ermöglicht Auto-Linking. Schrägstriche erstellen visuelle Hierarchie in Git-GUIs. Einige Teams erzwingen Naming via Git-Hooks oder CI-Checks. Die Konvention sollte in CONTRIBUTING.md dokumentiert sein. Halten Sie Namen beschreibend, aber prägnant. Vermeiden Sie persönliche Namen (johns-branch) — beschreiben Sie die Arbeit, nicht den Autor. Konsistentes Naming macht Branch-Cleanup und Verlaufsnavigation viel einfacher.
# Common naming patterns:
feature/add-user-authentication
feature/PROJ-123-user-profile
bugfix/fix-login-redirect
bugfix/PROJ-456-crash-on-startup
hotfix/security-patch-xss
release/v2.0.0
chore/update-dependencies
docs/api-documentation
refactor/extract-auth-module
experiment/new-algorithm
# Using ticket numbers (Jira, Linear, etc.)
git checkout -b feature/PROJ-123-oauth-login
# Auto-linking in commit messages
git commit -m "PROJ-123: implement OAuth login"
# GitHub auto-links PROJ-123 to the Jira ticket
# Branch naming with slashes creates hierarchy
# in Git GUI tools (GitHub, GitKraken, SourceTree)Rebase Deep Dive
Interaktives Rebase
Interaktives Rebase (-i) ist das mächtigste Werkzeug zur Verlaufsbearbeitung. Es ermöglicht Ihnen, Commits vor dem Pushen umzuschreiben, neu zu ordnen, zu kombinieren, aufzuteilen oder zu löschen. squash kombiniert einen Commit mit seinem Eltern-Commit (Messages mergen); fixup macht dasselbe, verwirft aber die Commit-Message (bereinigt 'WIP'-Commits). edit pausiert das Rebase, damit Sie den Commit amendieren können (Dateien hinzufügen, Inhalt ändern). reword lässt Sie nur die Message ändern. drop entfernt einen Commit. Rebasen Sie immer vor dem Pushen, um den Verlauf sauber zu halten. Rebasen Sie niemals Commits, die andere bereits gepullt haben — es schreibt den geteilten Verlauf um.
# Rebase last 5 commits interactively
git rebase -i HEAD~5
# Opens editor with:
# pick a1b2c3d First commit
# pick e4f5g6h Second commit
# pick i7j8k9l Third commit
# pick m0n1o2p Fourth commit
# pick q3r4s5t Fifth commit
# Commands:
# pick = use commit as-is
# reword = use commit, edit message
# edit = pause to amend the commit
# squash = combine with previous commit
# fixup = like squash, discard this message
# drop = remove commit entirely
# exec = run a shell command
# reorder = move lines to reorder commitsCommits squashen
Squashen kombiniert mehrere Commits zu einem und erstellt sauberen Verlauf. Dies ist ideal zum Mergen eines Feature-Branches: Squashen Sie 20 'WIP'-Commits zu einem sinnvollen 'feat: add login'-Commit. Das Flag --fixup erstellt einen speziellen Commit, den --autosquash automatisch platziert und mit seinem Ziel squash — großartig, um Review-Feedback zu beheben, ohne den Verlauf zu überladen. git reset --soft main gefolgt von einem einzelnen Commit squash alles auf einmal (einfacher als interaktives Rebase für totales Squashen). Viele Teams konfigurieren PR-Merges zum Auto-Squashen (GitHub 'Squash and merge'-Option).
# Squash the last 3 commits into one
git rebase -i HEAD~3
# In editor, change:
# pick a1b2c3d First
# squash e4f5g6h Second (or 'fixup' to discard message)
# squash i7j8k9l Third
# Git prompts for combined commit message
# Squash everything since branching from main
git rebase -i main
# Auto-squash fixup commits
git commit --fixup a1b2c3d # creates fixup! commit
git rebase -i --autosquash main
# Git automatically reorders and squashes fixup commits
# Squash all commits into one on a branch
git reset --soft main
git commit -m "feat: complete feature X"Rebase vs. Merge
Merge bewahrt den vollständigen Branch-Verlauf (mit Merge-Commits, die zeigen, wo Features divergierten und gemergt wurden). Rebase spielt Commits auf das Ziel ab und erstellt einen linearen Verlauf ohne Merge-Commits. Merge ist sicherer (keine Verlaufsumschreibung) und zeigt Feature-Kontext. Rebase ist sauberer, schreibt aber den Commit-Verlauf um. Häufige Strategie: Rebasen Sie Ihren Feature-Branch auf das neueste main vor dem Mergen, dann mergen (Fast-Forward oder mit --no-ff für einen Merge-Commit). Dies gibt saubere Commits UND einen Merge-Commit, der das Feature markiert. Für öffentliche/geteilte Branches bevorzugen Sie Merge, um Verlaufskonflikte zu vermeiden.
# MERGE: preserves complete history with merge commits
git checkout main
git merge feature
# Creates a merge commit, history looks like a graph:
# * merge commit
# |\
# | * feature commit 2
# | * feature commit 1
# * main commit
# REBASE: linear history, no merge commits
git checkout feature
git rebase main
git checkout main
git merge feature # fast-forward, no merge commit
# History is linear:
# * feature commit 2
# * feature commit 1
# * main commit
# When to use each:
# Merge: preserve context of feature branch, public repos
# Rebase: clean linear history, before pushing feature branchRebase-Konflikte lösen
Rebase-Konflikte treten beim Abspielen von Commits auf eine geänderte Basis auf. Lösen Sie jeden Konflikt, git add Sie die gelösten Dateien und git rebase --continue. Das Rebase verarbeitet einen Commit gleichzeitig, sodass Sie mehrere Konflikte treffen können. --skip verwirft einen Commit (verwenden, wenn er nach dem Rebase leer wird). --abort bricht alles ab und kehrt zum Pre-Rebase-Zustand zurück — immer ein sicherer Ausweg. Für komplexe Konflikte startet git mergetool ein visuelles Merge-Tool (VS Code, Beyond Compare usw.). Der Hauptunterschied zu Merge-Konflikten: Rebase kann erfordern, denselben Konflikt mehrmals zu lösen (einmal pro abgespieltem Commit).
# During rebase, conflicts pause the process
git rebase main
# CONFLICT in file.txt
# 1. Resolve conflicts manually in the file
# (look for <<<<<<< ======= >>>>>>> markers)
# 2. Stage resolved files
git add file.txt
# 3. Continue the rebase
git rebase --continue
# Skip a commit (if it's empty after rebase)
git rebase --skip
# Abort the entire rebase (return to original state)
git rebase --abort
# Use a merge tool for conflicts
git mergetool
# After resolving, the rebase continues
# with the next commit automaticallyRebase --onto (fortgeschritten)
git rebase --onto ist eine fortgeschrittene Form für präzises Commit-Transplanting. Die Syntax: rebase --onto NEW-BASE OLD-BASE BRANCH — es nimmt Commits zwischen OLD-BASE und BRANCH und spielt sie auf NEW-BASE ab. Dies ist nützlich, um den Basispunkt eines Branches zu ändern (z.B. Ihr Feature basierte auf einem anderen Feature, das gemergt wurde; Rebase auf main zum Bereinigen). Es wird auch verwendet, um spezifische Commits aus dem Verlauf zu entfernen (um sie herum abspielen). Dies ist eine Power-User-Funktion — verstehen Sie zuerst reguläres Rebase. Haben Sie immer ein Backup (Reflog) vor fortgeschrittener Verlaufsumschreibung.
# Scenario: feature branch was based on old-branch,
# but you want to rebase onto main instead
# git rebase --onto new-base old-base branch
git rebase --onto main old-branch feature
# This takes commits from old-branch..feature
# and replays them onto main
# Use case: remove commits from the middle
# Remove commit C from branch (replay A,B,D onto base)
# base -> A -> B -> C -> D
# git rebase --onto base C D
# Result: base -> A -> B -> D'
# Use case: move a branch to a different parent
git rebase --onto main feature/sub-feature feature/main-feature
# Moves main-feature's unique commits from sub-feature to mainCherry-Pick & Bisect
git cherry-pick
cherry-pick wendet einen spezifischen Commit von einem Branch auf einen anderen an. Anwendungsfälle: einen Bugfix auf einen Release-Branch anwenden, einen vergessenen Commit kopieren oder selektiv Features portieren. Der Commit erhält einen neuen Hash (anderer Parent). Cherry-Pick kann Konflikte verursachen, wenn der Ziel-Branch divergiert hat. --no-commit stagt Änderungen, ohne zu committen (nützlich, um mehrere Cherry-Picks zu kombinieren). Vermeiden Sie übermäßiges Cherry-Picking — es kann duplizierte Commits erstellen, wenn Branches schließlich mergen. Für systematisches Backporting verwenden Sie Release-Branches mit Merges stattdessen.
# Apply a specific commit to current branch
git cherry-pick a1b2c3d
# Cherry-pick multiple commits
git cherry-pick a1b2c3d e4f5g6h i7j8k9l
# Cherry-pick a range (exclusive start, inclusive end)
git cherry-pick A..E # commits B, C, D, E
# Cherry-pick without committing (stage only)
git cherry-pick --no-commit a1b2c3d
# or: -n
# Cherry-pick and edit commit message
git cherry-pick --edit a1b2c3d
# Cherry-pick from another branch
git cherry-pick feature-branch~2
# If conflicts occur:
git add . && git cherry-pick --continue
git cherry-pick --abort # cancelgit bisect (Binärsuche)
git bisect führt eine binäre Suche durch den Commit-Verlauf durch, um den genauen Commit zu finden, der einen Bug eingeführt hat. Sie markieren den aktuellen Zustand als 'bad' und einen bekannten funktionierenden Commit als 'good'. Git checkt den Mittelpunkt aus; Sie testen und markieren good/bad. Jeder Schritt halbiert den Suchraum — einen Bug in 1000 Commits zu finden, erfordert ~10 Schritte. bisect reset kehrt zu Ihrem ursprünglichen Branch zurück. Dies ist unbezahlbar zum Aufspüren von Regressionen. Kombinieren Sie mit git bisect log, um Bisect-Sessions zu speichern/wiederherzustellen. Der Schuld-Commit offenbart oft sofort die Ursache.
# Find which commit introduced a bug
git bisect start
# Mark current (bad) commit
git bisect bad
# Mark a known-good commit (last working version)
git bisect good v1.0.0
# or: git bisect good a1b2c3d
# Git checks out a middle commit
# Test it, then mark:
git bisect good # if this commit works
git bisect bad # if this commit is broken
# Repeat until Git identifies the culprit:
# "a1b2c3d is the first bad commit"
# When done:
git bisect reset # return to original branch
# Skip a commit (can't test, e.g., doesn't build)
git bisect skipAutomatisiertes Bisect
Automatisiertes Bisect führt ein Testskript für jeden Commit aus und eliminiert manuelles Testen. Das Skript beendet sich mit 0 (good), non-zero (bad) oder 125 (skip — z.B. Build-Fehler). Git markiert automatisch jeden Commit und findet den Schuldigen. Dies ist extrem mächtig mit einer Test-Suite: git bisect run npm test findet den fehlerhaften Commit in Minuten. Sie können die Suche auch auf spezifische Dateien beschränken (git bisect start -- path/to/file), um Dinge zu beschleunigen. Das Skript kann alles sein: ein Test, ein Build-Check oder ein curl-Befehl, der eine API prüft. Speichern Sie das Bisect-Log, um es später zu reproduzieren oder fortzusetzen.
# Auto-bisect with a test script
git bisect start
git bisect bad HEAD
git bisect good v1.0.0
# Git runs this script for each commit
# Exit 0 = good, exit 1 = bad, 125 = skip
git bisect run npm test
# Or a custom script
git bisect run ./scripts/check-bug.sh
# Example check script:
#!/bin/bash
npm run build || exit 125 # skip if build fails
npm test -- --grep "login bug"
# exit 0 if test passes (good), 1 if fails (bad)
# Git automatically finds the bad commit
# without manual testing
# Bisect with a file range (faster)
git bisect start -- src/auth/login.jsgit blame & annotate
git blame zeigt den Autor und Commit für jede Zeile einer Datei — unerlässlich, um zu verstehen, warum Code existiert. -L beschränkt auf einen Zeilenbereich (schneller, fokussierter). -w ignoriert Whitespace-only-Änderungen (zeigt den wahren Inhalts-Autor). -M erkennt innerhalb derselben Datei verschobenen Code; -C erkennt aus anderen Dateien kopierten Code (zeigt den Original-Autor, nicht den Kopierer). blame ist zum Verstehen, nicht zum Beschuldigen — verwenden Sie es, um Kontext für Code zu finden, dann lesen Sie den vollständigen Commit mit git show. GitHub 'Blame'-Button bietet eine visuelle Schnittstelle. Kombinieren Sie mit git log -S, um zu finden, wann spezifischer Text hinzugefügt wurde.
# Show who last modified each line
git blame file.txt
# Blame specific line range
git blame -L 10,20 file.txt
# Show full commit hash (not abbreviated)
git blame -l file.txt
# Show email instead of name
git blame -e file.txt
# Ignore whitespace changes
git blame -w file.txt
# Detect moved lines within file
git blame -M file.txt
# Detect moved lines from other files
git blame -C file.txt
# Blame with commit message
git blame --show-name --show-email file.txt | headgit revert (sicheres Rückgängigmachen)
git revert erstellt einen neuen Commit, der einen vorherigen Commit rückgängig macht — es ist die sichere Methode, um Änderungen auf geteilten Branches rückgängig zu machen (im Gegensatz zu reset, das den Verlauf umschreibt). revert ist ideal für Produktions-Branches, wo Sie den Verlauf nicht umschreiben können. Das Reverten eines Merge-Commits erfordert -m 1 (Mainline-Parent) — dies macht den Merge rückgängig, während der Branch-Verlauf erhalten bleibt. Ein Revert eines Reverts wendet die ursprüngliche Änderung wieder an (häufig, wenn ein Revert ein Fehler war). Für mehrere Commits reverten Sie in umgekehrter Reihenfolge (neueste zuerst), um Konflikte zu minimieren. Verwenden Sie immer revert auf geteilten/öffentlichen Branches; verwenden Sie reset nur auf lokalen Branches.
# Revert a commit (creates a NEW commit that undoes it)
git revert a1b2c3d
# Revert multiple commits
git revert a1b2c3d e4f5g6h
# Revert a range
git revert A..E
# Revert without committing (stage the reversal)
git revert --no-commit a1b2c3d
# Revert a merge commit
git revert -m 1 a1b2c3d
# -m 1 specifies the mainline parent (parent 1 = the branch
# you merged INTO, parent 2 = the branch you merged FROM)
# If revert conflicts:
git add . && git revert --continue
git revert --abortReflog & Wiederherstellung
git reflog Grundlagen
Das Reflog zeichnet jede Änderung an HEAD und Branch-Zeigern auf — sogar Operationen, die Commits 'zerstören' (reset --hard, rebase, Branch-Löschung). Dies ist Ihr Sicherheitsnetz: 'verlorene' Commits sind ~90 Tage (Standard) über das Reflog wiederherstellbar. reflog ist lokal (wird nie gepusht) und zeigt die chronologische Historie der Zeiger-Bewegungen. Zur Wiederherstellung finden Sie den Commit-Hash im Reflog und checkout/reset darauf. Die @{N}-Syntax referenziert Einträge: HEAD@{0} ist aktuell, HEAD@{1} ist vorherige. Wenn Sie jemals denken, Sie hätten Arbeit 'verloren', checken Sie zuerst das Reflog — es ist fast sicher noch da.
# View the reflog (reference log)
git reflog
# Shows ALL reference changes, including:
# - commits, checkouts, resets, rebases, merges
# Example output:
# a1b2c3d HEAD@{0}: reset: moving to HEAD~1
# e4f5g6h HEAD@{1}: commit: add feature
# i7j8k9l HEAD@{2}: checkout: moving from main to feature
# Reflog for a specific branch
git reflog show feature-branch
# Reflog with dates
git reflog --date=iso
# Recover a "lost" commit
git reflog
# Find the commit hash, then:
git checkout a1b2c3d # or: git reset --hard a1b2c3dGelöschte Branches wiederherstellen
Gelöschte Branches und Reset-Commits sind über das Reflog wiederherstellbar. Die Commit-Objekte existieren weiterhin in Gits Objekt-Store bis zur Garbage Collection (Standard: 90 Tage für unerreichbare Objekte). Um einen gelöschten Branch wiederherzustellen, finden Sie seinen Tip-Commit im Reflog und erstellen einen neuen Branch, der darauf zeigt. Für reset --hard-Fehler zeigt das Reflog die vorherige HEAD-Position — reset Sie dorthin zurück. Für schlechte Rebases finden Sie den Reflog-Eintrag vor dem Rebase-Start und reset darauf. Die wichtigste Lektion: In Git ist fast nichts sofort wirklich verloren. Checken Sie immer das Reflog, bevor Sie in Panik geraten.
# Accidentally deleted a branch?
git branch -D feature # force deleted
# Find it in reflog
git reflog
# e4f5g6h HEAD@{2}: commit: work on feature
# Recreate the branch at that commit
git branch feature e4f5g6h
# Or checkout and create
git checkout -b feature e4f5g6h
# Recover after reset --hard
git reset --hard HEAD~3 # oops, went too far
git reflog
# Find the commit before the reset
git reset --hard HEAD@{1} # undo the reset
# Recover after a bad rebase
git reflog
git reset --hard HEAD@{5} # before the rebase startedgit fsck (dangling Objects)
git fsck überprüft die Repository-Integrität und findet dangling Objects — Commits, Blobs und Trees, die von keinem Branch oder Tag referenziert werden. --lost-found schreibt diese nach .git/lost-found/. Dies ist der letzte Ausweg, wenn das Reflog nicht hat, was Sie benötigen (Reflog-Einträge verfallen oder git gc lief). Dangling Commits sind oft das Ergebnis abgebrochener Operationen oder verfallener Reflog-Einträge. Inspizieren Sie mit git show, dann stellen Sie wieder her, indem Sie einen Branch erstellen. fsck --full verifiziert die Integrität aller Objekte (nützlich zum Erkennen von Korruption). Führen Sie fsck regelmäßig auf wichtigen Repos aus, um Probleme früh zu erkennen.
# Find dangling (unreachable) commits
git fsck --lost-found
# Output:
# dangling commit a1b2c3d...
# dangling blob e4f5g6h...
# Inspect a dangling commit
git show a1b2c3d
# Recover it
git branch recovered a1b2c3d
# Full fsck (check repository integrity)
git fsck --full
# Check for dangling objects only
git fsck --no-reflogs --dangling
# When reflog doesn't have what you need
# (e.g., expired, or gc ran), fsck finds
# ALL dangling objects in the object storegit stash Deep Dive
git stash legt uncommittete Änderungen vorübergehend ab. push -m fügt eine beschreibende Message hinzu (unerlässlich zum Verwalten mehrerer Stashes). -u schließt ungetrackte Dateien ein; -a schließt auch ignorierte Dateien ein. apply wendet ohne Entfernen erneut an; pop wendet an und entfernt. stash branch erstellt einen neuen Branch aus dem Stash (nützlich, wenn der Stash mit dem aktuellen Branch konfligiert). Stashes werden in einem Stack (LIFO) gespeichert — referenzieren Sie mit stash@{N}. show -p zeigt den Diff. Stashes überleben Reboots, sind aber lokal (werden nie gepusht). Bereinigen Sie alte Stashes regelmäßig; sie häufen sich an. Für langfristige Arbeit erstellen Sie einen Branch anstatt zu stagen.
# Stash with message
git stash push -m "work in progress on login"
# Stash specific files
git stash push -m "wip" file1.txt file2.txt
# Stash including untracked files
git stash push -u # or --include-untracked
# Stash including ignored files
git stash push -a # or --all
# List stashes
git stash list
# stash@{0}: On feature: wip on login
# stash@{1}: On main: quick fix
# Apply a specific stash
git stash apply stash@{1}
# Apply and drop (pop)
git stash pop # applies stash@{0} and removes it
# Show stash contents
git stash show -p stash@{0}
# Create branch from stash
git stash branch new-branch stash@{0}
# Drop a stash
git stash drop stash@{1}
git stash clear # drop ALL stashesgit tag-Verwaltung
Tags markieren spezifische Commits als wichtig (Releases, Meilensteine). Annotierte Tags (-a) speichern Metadaten (Tagger, Datum, Message) und werden für Releases empfohlen. Lightweight-Tags sind nur benannte Zeiger (keine Metadaten). Signierte Tags (-s) verwenden GPG zur Verifizierung (wichtig für Security-Releases). Tags werden standardmäßig NICHT gepusht — verwenden Sie --tags, um sie zu pushen. Semantische Versionierung (v1.2.3) ist die Standard-Namenskonvention. Checkout eines Tags für einen detached HEAD-Zustand (zum Inspizieren oder Bauen eines Releases). GitHub-Releases basieren auf Tags — erstellen Sie einen Tag, dann veröffentlichen Sie einen Release mit Notes.
# Create annotated tag (recommended)
git tag -a v1.0.0 -m "Release 1.0.0"
# Create lightweight tag
git tag v1.0.0
# Tag a specific commit
git tag -a v0.9.0 -m "beta" a1b2c3d
# List all tags
git tag
git tag -l "v1.*" # filter by pattern
# Push tags to remote
git push origin v1.0.0 # single tag
git push origin --tags # all tags
# Delete a tag
git tag -d v1.0.0 # local
git push origin --delete v1.0.0 # remote
# Show tag details
git show v1.0.0
# Checkout a tag (detached HEAD)
git checkout v1.0.0
# Signed tags (GPG)
git tag -s v1.0.0 -m "signed release"Worktree & Submodules
git worktree
git worktree erstellt zusätzliche Working Directories aus demselben Repository — kein Klonen nötig. Jedes Worktree checkt gleichzeitig einen anderen Branch aus. Dies ist perfekt für: an einem Hotfix arbeiten, während Ihr Feature-Branch offen bleibt, Tests auf einem Branch ausführen, während Sie auf einem anderen coden, oder langlaufende Builds auf einem Worktree haben. Alle Worktrees teilen sich das .git-Verzeichnis (Objekte, Refs), sodass sie synchron bleiben und Speicherplatz sparen. Sie können denselben Branch nicht in zwei Worktrees auschecken (Git verhindert dies, um Konflikte zu vermeiden). Worktrees sind schneller als Klonen für Multi-Branch-Workflows.
# Create a new working directory linked to the repo
git worktree add ../project-hotfix hotfix-branch
# Work in the new directory
cd ../project-hotfix
# This is a full working tree on hotfix-branch
# Shares the same .git, so no cloning needed
# List worktrees
git worktree list
# /path/to/project main
# /path/to/project-hotfix hotfix-branch
# Remove a worktree
git worktree remove ../project-hotfix
# Prune stale worktree entries
git worktree prune
# Create worktree at new branch
git worktree add -b feature-x ../project-feature maingit submodule Grundlagen
Submodules betten ein Git-Repository in ein anderes ein — nützlich zum Einbinden geteilter Bibliotheken oder Abhängigkeiten. Das Parent-Repo speichert einen Zeiger (Commit-Hash) auf das Submodule, nicht seinen Inhalt. --recurse-submodules ist beim Klonen unerlässlich (sonst sind Submodules leer). Das Aktualisieren von Submodules (--remote) fetcht die neuesten Commits; Sie müssen dann den neuen Hash im Parent-Repo committen. Submodules sind komplex: Branches, Konflikte und Updates erfordern sorgfältige Handhabung. Für einfacheres Abhängigkeits-Management ziehen Sie Git subtrees, Package Manager (npm, pip) oder Monorepo-Strategien in Betracht. Verwenden Sie Submodules, wenn Sie einen spezifischen externen Commit tracken müssen.
# Add a submodule to your repo
git submodule add https://github.com/user/lib.git libs/lib
# Clone a repo with submodules
git clone --recurse-submodules https://github.com/user/project.git
# If you forgot --recurse-submodules:
git submodule update --init --recursive
# Pull latest changes in all submodules
git submodule update --remote
# Pull specific submodule
git submodule update --remote libs/lib
# After updating submodules, commit the new hash
git add libs/lib
git commit -m "update lib submodule"
# Execute command in all submodules
git submodule foreach 'git status'Submodule-Workflows
Innerhalb eines Submodules zu arbeiten ist wie in einem normalen Repo — Sie committen und pushen aus dem Submodule-Verzeichnis. Das Parent-Repo trackt den Commit-Hash, daher müssen Sie nach dem Ändern eines Submodules auch im Parent committen. Beim Wechseln von Branches stimmt der Submodule-Inhalt möglicherweise nicht überein — führen Sie git submodule update --init --recursive zum Synchronisieren aus. Das Löschen von Submodules erfordert drei Schritte: deinit (abmelden), git rm (aus dem Tracking entfernen) und manuelles Löschen von .git/modules. Submodule-Workflows sind fehleranfällig; kommunizieren Sie immer mit Ihrem Team beim Aktualisieren von Submodules, um Hash-Mismatches zu vermeiden.
# Change code inside a submodule
cd libs/lib
# Make changes, commit, and push
git add .
git commit -m "fix: bug in lib"
git push origin HEAD:main
# Back in parent repo, update the pointer
cd ../..
git add libs/lib
git commit -m "chore: update lib submodule"
# Switch branches with submodules
git checkout main
git submodule update --init --recursive
# Delete a submodule
git submodule deinit -f libs/lib
git rm libs/lib
rm -rf .git/modules/libs/lib
git commit -m "remove lib submodule"
# Move a submodule
git mv libs/lib libs/new-libGit Hooks
Git-Hooks führen Skripte an spezifischen Punkten im Git-Lebenszyklus aus. Client-seitige Hooks (pre-commit, pre-push, commit-msg) erzwingen lokale Standards. pre-commit ist ideal für Linting/Formatierung; pre-push für das Ausführen von Tests; commit-msg für das Erzwingen von Conventional Commits. Hooks werden NICHT von Git getrackt (sie leben in .git/hooks/), sodass sie nicht zwischen Klonen synchronisieren. Um Hooks teamweit zu teilen, verwenden Sie ein Tool wie Husky (npm), pre-commit (Python) oder committen Sie die Hooks in ein eingechecktes Verzeichnis und symlinken Sie diese. Server-seitige Hooks (pre-receive, post-receive) laufen auf dem Remote und können Richtlinien für alle Beitragenden erzwingen.
# Hooks live in .git/hooks/ (not tracked by Git)
# Sample hooks are provided with .sample extension
# pre-commit: runs before commit is created
# .git/hooks/pre-commit
#!/bin/bash
npm run lint || exit 1 # block commit if lint fails
# pre-push: runs before pushing
#!/bin/bash
npm test || exit 1 # block push if tests fail
# commit-msg: validate commit message format
#!/bin/bash
# $1 is the path to the commit message file
if ! grep -qE "^(feat|fix|docs|chore):" "$1"; then
echo "Use conventional commit format: type: message"
exit 1
fi
# prepare-commit-msg: auto-populate message
#!/bin/bash
echo "# Branch: $(git branch --show-current)" >> "$1"
# Make hooks executable
chmod +x .git/hooks/pre-commitGit LFS (Large File Storage)
Git LFS ersetzt große Dateien (Binärdateien, Videos, Datensätze) durch Text-Zeiger in Git und speichert den tatsächlichen Inhalt auf einem separaten LFS-Server. Dies hält das Repo leichtgewichtig — ohne LFS blähen Binärdateien das Repo dauerhaft auf (jede Version wird gespeichert). Tracken Sie Dateimuster mit git lfs track, dann committen Sie .gitattributes. Danach funktionieren große Dateien transparent. git lfs migrate import konvertiert vorhandene Dateien retrospektiv zu LFS (schreibt Verlauf um — zuerst mit dem Team koordinieren). LFS erfordert Server-Unterstützung (GitHub, GitLab, Bitbucket unterstützen alle). Hinweis: LFS hat Bandbreiten-/Speicher-Quoten auf gehosteten Plattformen. Für wirklich riesige Dateien ziehen Sie externen Speicher mit URLs in Betracht.
# Initialize Git LFS
git lfs install
# Track large file types
git lfs track "*.psd"
git lfs track "*.zip"
git lfs track "assets/**"
# This creates/updates .gitattributes
# Commit the .gitattributes file
git add .gitattributes
git commit -m "chore: configure LFS tracking"
# Add large files normally
git add design.psd
git commit -m "add design file"
git push
# View LFS tracked files
git lfs ls-files
# Pull LFS content (if not auto-downloaded)
git lfs pull
# Migrate existing files to LFS (rewrites history)
git lfs migrate import --include="*.psd" --everything
# Check LFS status
git lfs statusStash
Speichern & Pop
git stash legt uncommittete Änderungen ab, sodass Sie Branches wechseln oder Updates mit einem sauberen Working Tree pullen können. pop wendet den obersten Stash an und entfernt ihn; apply behält ihn. Der Stash ist ein LIFO-Stack.
# Save uncommitted changes (tracked files only)
git stash
# Save including untracked files
git stash -u
# Pop the most recent stash (removes it)
git stash pop
# Apply without removing (keeps stash in list)
git stash applyBenannte Stashes
Übergeben Sie immer -m, um Stashes zu beschriften — die Standardmessage ist der Branch und Commit, was selten beschreibend ist. stash@{N} referenziert einen spezifischen Stash nach seinem Index.
# Save with a descriptive message
git stash push -m "WIP: refactor auth flow"
# List all stashes with messages
git stash list
# Apply a specific stash by index
git stash apply stash@{1}Stash-Branches
git stash branch erstellt einen neuen Branch vom Commit, an dem der Stash ursprünglich erstellt wurde, und wendet den Stash dort an. Dies ist die sauberste Methode zur Wiederherstellung, wenn ein Stash nicht mehr sauber angewendet werden kann.
# Create a new branch from a stash
git stash branch feature-branch stash@{0}
# Useful when stash conflicts with current branch
# - Creates branch from the commit where stash was made
# - Applies stash on top
# - Drops stash if apply succeedsPartieller Stash
Stagen Sie nur, was Sie benötigen, mit -p (interaktive Hunk-Auswahl) oder durch Auflisten spezifischer Dateien. --keep-index stasht ungestagte Änderungen, lässt aber gestagte Änderungen an Ort und Stelle.
# Interactively choose hunks to stash
git stash push -p
# Stash specific files only
git stash push -m "config tweaks" config.yml .env.local
# Stash with keep-index (staged changes stay)
git stash --keep-indexStash-Verwaltung
git stash show -p zeigt den vollständigen Diff eines Stash. drop entfernt einen einzelnen Stash; clear löscht alle (unumkehrbar). Stashes sind nur lokal; sie werden nie zu Remotes gepusht.
# Show what's in a stash
git stash show -p stash@{0}
# Drop a specific stash
git stash drop stash@{0}
# Clear all stashes (irreversible)
git stash clear
# Show stash list with dates
git stash list --date=relativeRebase
Basis-Rebase
Rebase bewegt Ihre Branch-Commits auf einen anderen Branch und erzeugt einen linearen Verlauf. Im Gegensatz zu Merge schreibt es Commit-Hashes um. Rebasen Sie niemals Commits, die bereits gepusht und geteilt wurden.
# Rebase current branch onto main
git checkout feature
git rebase main
# Abort if conflicts are too messy
git rebase --abort
# Continue after resolving conflicts
git rebase --continueInteraktives Rebase
Interaktives Rebase (-i) ermöglicht es Ihnen, den Verlauf vor dem Teilen umzuschreiben: Commits neu ordnen, verwandte zu einem einzelnen sauberen Commit squashen, Messages umformulieren oder Fehler verwerfen. Tun Sie dies immer an ungepushten Commits.
# Rebase last 5 commits interactively
git rebase -i HEAD~5
# Commands: pick, reword, edit, squash, fixup, drop
# squash = combine with previous, keep message
# fixup = combine with previous, discard message
# reword = change commit message onlySquash & Fixup
--fixup erstellt einen Commit, der als Fix für einen anderen markiert ist. --autosquash während Rebase platziert fixup!- und squash!-Commits automatisch neben ihren Zielen. Dies strafft den 'früh committen, später aufräumen'-Workflow.
# Create a fixup commit targeting an earlier commit
git commit --fixup a1b2c3
# Autosquash during rebase (auto-reorders fixups)
git rebase -i --autosquash HEAD~5Rebase --onto
--onto ist chirurgisches Rebase: Es bewegt einen Bereich von Commits von einer Basis zu einer anderen. Verwenden Sie es, um einen Branch umzuparenten oder die ersten paar Commits eines Branches zu verwerfen.
# Move commits from one base to another
# git rebase --onto <new-base> <old-base> <branch>
git rebase --onto main feature-old feature-new
# Drop the first N commits of a branch
git rebase --onto main HEAD~3Rebase-Konflikte
Während Rebase stoppt Konflikte bei jedem Commit. Lösen Sie, git add, dann --continue zum Fortfahren. --skip verwirft den konfliktbehafteten Commit vollständig. --abort kehrt zum Pre-Rebase-Zustand zurück.
# During rebase, conflicts pause the process
git rebase main
# CONFLICT (content): Merge conflict in file.js
# Resolve in editor, then:
git add file.js
git rebase --continue
# Skip a commit that conflicts (drop it)
git rebase --skip
# Give up entirely
git rebase --abortCherry-Pick
Einen Commit cherry-picken
cherry-pick wendet einen spezifischen Commit aus einem anderen Branch auf Ihren aktuellen Branch an und erstellt einen neuen Commit mit denselben Änderungen. Der neue Commit hat einen anderen Hash, weil der Parent unterschiedlich ist.
# Apply a specific commit to current branch
git cherry-pick a1b2c3d
# Cherry-pick multiple commits
git cherry-pick a1b2c3d e4f5g6h
# Cherry-pick a range (exclusive of start, inclusive of end)
git cherry-pick A..ENo-Commit Cherry-Pick
--no-commit (-n) stagt die Cherry-Pick-Änderungen, ohne einen Commit zu erstellen. Dies ermöglicht es, mehrere Cherry-Picks zu einem Commit zu kombinieren oder die Änderungen vor dem Committen zu modifizieren.
# Apply changes to working tree without committing
git cherry-pick --no-commit a1b2c3d
# Stage the changes yourself
git add -p
git commit -m "Custom message"Cherry-Pick-Konflikte
Konflikte während Cherry-Pick pausieren die Operation. Lösen Sie, git add, und --continue. --skip verwirft den aktuellen Commit. --abort bricht den Cherry-Pick ab und stellt den Branch wieder her.
git cherry-pick a1b2c3d
# error: could not apply a1b2c3d...
# Resolve conflicts, then:
git add resolved-file.js
git cherry-pick --continue
# Skip this commit
git cherry-pick --skip
# Abort the entire cherry-pick
git cherry-pick --abortCherry-Pick von einem anderen Branch
Der klassische Hotfix-Workflow: Beheben Sie einen Bug auf einem Maintenance-Branch, dann cherry-picken Sie denselben Commit auf main (und andere aktive Branches). Dies vermeidet das Mergen unrelateder Feature-Arbeit.
# Find the commit hash on another branch
git log --oneline feature-branch
# Switch to target branch
git checkout main
# Cherry-pick the commit
git cherry-pick <hash>
# Useful for hotfixes: fix on a feature branch,
# then cherry-pick the fix to mainCherry-Pick-Strategie
-X theirs/ours beeinflusst die Konfliktlösung. -x fügt eine Zeile hinzu, die den Original-Commit-Hash aufzeichnet — unerlässlich für Audit-Trails beim Cherry-Picken von Hotfixes über Branches hinweg.
# Use a different merge strategy
git cherry-pick -X theirs a1b2c3d # prefer their changes on conflict
git cherry-pick -X ours a1b2c3d # prefer our changes on conflict
# Preserve original commit author
git cherry-pick -x a1b2c3d # adds "(cherry picked from ...)" to message
# Edit commit message before committing
git cherry-pick -e a1b2c3dBisect
Basis-Bisect
git bisect führt eine binäre Suche durch den Commit-Verlauf durch, um zu finden, welcher Commit einen Bug eingeführt hat. Sie markieren den aktuellen Commit als bad und einen bekannten good-Commit als good. Nach ~log2(N) Schritten nennt Git den schuldigen Commit.
# Start bisecting
git bisect start
# Mark current commit as bad (has the bug)
git bisect bad
# Mark a known-good commit (older)
git bisect good v1.0.0
# Git checks out the midpoint. Test, then mark:
git bisect good # or
git bisect bad
# Exit bisect mode
git bisect resetBisect-Log & Replay
git bisect log zeichnet jede good/bad-Entscheidung auf. Wenn Sie einen Commit falsch markieren (ein häufiger Fehler), resetten und replayen Sie das Log, dann korrigieren Sie den falschen Schritt.
# Record what happens during bisect
git bisect log > bisect.log
# If you make a mistake, replay from the log
git bisect reset
git bisect replay bisect.log
# Visualize the bisect state
git bisect visualizeAutomatisiertes Bisect
git bisect run automatisiert die Suche: Git checkt jeden Kandidaten aus, führt Ihr Skript aus und markiert den Commit basierend auf dem Exit-Code. Dies ist dramatisch schneller als manuelles Testen.
# Auto-bisect: git runs a test script and marks good/bad itself
git bisect start HEAD v1.0.0 -- # bad=HEAD, good=v1.0.0
git bisect run npm test # exit 0=good, 1-124=bad, 125=skip
# Or with a custom script
git bisect run ./scripts/check-bug.shBisect nach Datei
Das Übergeben eines Pfads an git bisect start beschränkt die Suche auf Commits, die diese Datei modifiziert haben. Dies überspringt hunderte irrelevante Commits und zielt auf die Datei, in der der Bug wahrscheinlich lebt.
# Limit bisect to changes in a specific file
git bisect start -- path/to/file.js
# Combine with bad/good markers
git bisect bad HEAD
git bisect good v1.0.0
# Git only considers commits that touched that fileBisect Reset
Führen Sie immer git bisect reset aus, wenn Sie fertig sind — es kehrt Sie zu Ihrem ursprünglichen Branch zurück und bereinigt den Bisect-Zustand. Ohne Reset bleibt Ihr Working Tree auf dem zuletzt getesteten Commit.
# Exit bisect mode and return to original branch
git bisect reset
# Reset to a specific branch/commit instead
git bisect reset <branch>
# View current bisect state
git bisect statusSubmodules
Ein Submodule hinzufügen
Submodules betten ein Git-Repository in ein anderes ein — nützlich zum Vendoren geteilter Bibliotheken. git submodule add registriert das Submodule in .gitmodules. Neue Klons benötigen --recurse-submodules.
# Add a submodule at a specific path
git submodule add https://github.com/user/lib.git libs/lib
# This creates:
# - libs/lib/ (the submodule checkout)
# - .gitmodules (tracks submodule URLs and paths)
# Commit the new submodule
git commit -m "Add lib submodule"
# Clone a repo with submodules included
git clone --recurse-submodules https://github.com/user/repo.gitSubmodules aktualisieren
Ein Submodule ist auf einen spezifischen Commit gepinnt. git submodule update --remote fetcht den neuesten Commit auf dem getrackten Branch und aktualisiert den Zeiger. Sie müssen diese Zeiger-Änderung im Parent-Repo committen.
# Pull latest changes in all submodules
git submodule update --remote
# Update a specific submodule
git submodule update --remote libs/lib
# Then commit the updated pointer
git add libs/lib
git commit -m "Bump lib submodule"
# Initialize submodules after cloning
git submodule update --init --recursiveSubmodule Foreach
foreach führt einen Shell-Befehl in jedem Submodule-Verzeichnis aus — nützlich für Bulk-Operationen wie Status prüfen, Updates pullen oder Bauen. --recursive steigt in verschachtelte Submodules ab.
# Run a command in every submodule
git submodule foreach 'git status'
# With recursion into nested submodules
git submodule foreach --recursive 'git checkout main'
# Use --quiet to suppress the "Entering..." messages
git submodule foreach --quiet 'git pull'Deinit & Remove
Das Entfernen eines Submodules ist ein mehrstufiger Prozess: deinit meldet es ab, rm -rf .git/modules/... löscht die Submodule-Git-Daten, und git rm entfernt den Working Tree. Das Vergessen der .git/modules-Bereinigung hinterlässt verwaiste Daten.
# Deinit a submodule (unregisters, keeps files)
git submodule deinit libs/lib
# Fully remove a submodule
git submodule deinit -f libs/lib
rm -rf .git/modules/libs/lib
git rm -f libs/lib
git commit -m "Remove lib submodule"Submodule-Branches
Standardmäßig befinden sich Submodules im detached HEAD. Das Setzen von submodule.<name>.branch lässt --remote diesen Branch tracken. Um Änderungen innerhalb eines Submodules vorzunehmen, cd hinein, checkout einen Branch, committen und pushen.
# Configure a submodule to track a branch
git config -f .gitmodules submodule.libs/lib.branch main
# Now --remote updates from that branch
git submodule update --remote
# Work inside a submodule like a normal repo
cd libs/lib
git checkout feature-branch
git push
cd ../..
git add libs/lib
git commit -m "Update lib to feature-branch"Hooks
Häufige Hooks
Git-Hooks sind Skripte in .git/hooks/, die automatisch an spezifischen Punkten ausgeführt werden. Client-seitige Hooks laufen auf Ihrer Maschine und können Aktionen blockieren. Server-seitige Hooks laufen auf dem Remote und erzwingen Richtlinien. Hooks werden standardmäßig nicht versioniert — verwenden Sie Husky, um sie zu teilen.
# Client-side (run on your machine):
# pre-commit - runs before commit is created
# prepare-commit-msg - can edit commit message
# commit-msg - validates commit message
# pre-push - runs before pushing
# post-merge - runs after git merge
# Server-side (run on the remote):
# pre-receive - runs before refs are updated
# update - runs once per ref
# post-receive - runs after refs are updatedpre-commit Hook
pre-commit läuft, bevor der Commit erstellt wird; ein non-zero Exit bricht den Commit ab. Häufige Verwendungen: gestagte Dateien linten, fokussierte Tests ausführen, Code formatieren. Halten Sie es schnell (<5 Sekunden), sonst werden Entwickler es mit --no-verify umgehen.
#!/bin/sh
# .git/hooks/pre-commit
# Run linter on staged files
npm run lint-staged
if [ $? -ne 0 ]; then
echo "Linting failed. Fix errors and try again."
exit 1
fi
# Run tests
npm test -- --findRelatedTests
if [ $? -ne 0 ]; then
echo "Tests failed."
exit 1
fi
exit 0commit-msg Hook
commit-msg erhält den Pfad zur temporären Commit-Message-Datei als $1. Es kann die Message validieren oder umschreiben. Ein non-zero Exit lehnt den Commit ab. Dies ist die Standardmethode, um Conventional Commits zu erzwingen.
#!/bin/sh
# .git/hooks/commit-msg
# Enforce Conventional Commits format
pattern='^(feat|fix|docs|style|refactor|perf|test|chore|ci|build|revert)(\(.*\))?: .{1,72}$'
if ! grep -qE "$pattern" "$1"; then
echo "Invalid commit message format."
echo "Use: <type>(<scope>): <description>"
exit 1
fiHusky-Setup
Husky installiert Git-Hooks aus einem versionierten .husky/-Verzeichnis, sodass jedes Teammitglied nach npm install dieselben Hooks erhält. lint-staged führt Befehle nur auf gestagten Dateien aus und hält pre-commit schnell.
# Install Husky
npm install --save-dev husky
npx husky init
# Add a pre-commit hook
echo 'npm run lint-staged' > .husky/pre-commit
# Add a commit-msg hook
echo 'npx --no-install commitlint --edit $1' > .husky/commit-msg
# package.json
{
"scripts": { "prepare": "husky" },
"lint-staged": {
"*.{js,ts}": ["eslint --fix", "prettier --write"]
}
}pre-push Hook
pre-push läuft, bevor Refs gepusht werden; non-zero Exit bricht ab. Es liest vorgeschlagene Pushes von stdin. Häufige Verwendungen: Pushes zu geschützten Branches blockieren, die vollständige Test-Suite ausführen.
#!/bin/sh
# .husky/pre-push
# Reads stdin: <local ref> <local sha> <remote ref> <remote sha>
while read local_ref local_sha remote_ref remote_sha; do
if [ "$remote_ref" = "refs/heads/main" ]; then
echo "Direct push to main is not allowed."
exit 1
fi
done
npm test
if [ $? -ne 0 ]; then
echo "Tests failed. Push aborted."
exit 1
fiWorktrees
Ein Worktree hinzufügen
Ein Worktree ist ein separates Working Directory, das mit demselben Repository verknüpft ist. Sie können mehrere Branches gleichzeitig in verschiedenen Verzeichnissen ausgecheckt haben — kein Stagen zum Kontextwechsel.
# Create a worktree at a path, on a new branch
git worktree add ../project-feature feature-branch
# Worktree on an existing branch
git worktree add ../project-hotfix hotfix-branch
# Worktree at a specific commit (detached HEAD)
git worktree add --detach ../project-inspect v1.0.0
# List all worktrees
git worktree listWorktree-Workflow
Worktrees glänzen beim Kontextwechsel: Ein dringender Bug trifft ein, während Sie tief in einem Feature stecken. Anstatt zu stagen und Ihren IDE-Zustand zu verlieren, erstellen Sie ein Worktree auf main, beheben Sie den Bug dort und kehren Sie zurück.
# Scenario: working on feature, urgent bug comes in
git worktree add ../project-hotfix main
cd ../project-hotfix
git checkout -b fix-urgent
# ... fix the bug, commit, push ...
cd ../project-feature
# Your feature work is untouched
# Clean up when done
git worktree remove ../project-hotfixEntfernen & Prune
remove löscht ein Worktree-Verzeichnis und seine Admin-Metadaten. Der Branch, auf dem es war, bleibt. Wenn das Worktree uncommittete Änderungen hat, verweigert remove, es sei denn, Sie übergeben --force.
# Remove a worktree (must be clean or use --force)
git worktree remove ../project-feature
# Force remove even with uncommitted changes
git worktree remove --force ../project-feature
# Prune worktree admin files for deleted directories
git worktree prune
# Show what would be pruned
git worktree prune --dry-run -vWorktree-Vorteile
Worktrees lösen mehrere Schmerzpunkte: kein Stagen für Kontextwechsel, parallele Builds/Tests, isolierte node_modules pro Branch und Side-by-Side-Branch-Vergleich. Die geteilte Objekt-Datenbank bedeutet minimalen Speicher-Overhead.
# 1. No stashing needed for context switches
# 2. Run long builds/tests in one worktree while
# continuing work in another
# 3. Each worktree has its own node_modules
# 4. Compare two branches side-by-side in two
# editor windows
# 5. Shared object database = minimal disk overhead
# Typical layout:
# ~/projects/
# main-repo/ (main branch)
# main-repo-feature/ (feature worktree)
# main-repo-hotfix/ (hotfix worktree)Gesperrte Worktrees
Sperren Sie ein Worktree, wenn es Arbeit enthält, die nicht gestört werden sollte (langlaufende Builds, angehängter Debugger). Gesperrte Worktrees überleben prune. move verlagert ein Worktree; repair repariert die Admin-Dateien.
# Lock a worktree (prevents it from being pruned)
git worktree lock ../project-feature --reason "Running long build"
# Unlock when done
git worktree unlock ../project-feature
# Move a worktree to a new path
git worktree move ../project-feature ../new-location/project-feature
# Repair after moving manually
git worktree repair ../new-location/project-featureReflog
Reflog ansehen
Das Reflog zeichnet jede Änderung an HEAD und Branch-Tipps auf — Commits, Checkouts, Resets, Rebases. Es ist ein lokales Sicherheitsnetz: Selbst nach einer destruktiven Operation sind die Commits noch im Reflog.
# Show reflog for HEAD
git reflog
# a1b2c3d HEAD@{0}: commit: Fix bug
# e4f5g6h HEAD@{1}: checkout: moving to feature
# 789abc0 HEAD@{2}: reset: moving to HEAD~1
# Show reflog for a specific branch
git reflog show feature
# Show reflog with dates
git reflog --date=isoVerlorene Commits wiederherstellen
Nach einem hard Reset oder Rebase sind 'verlorene' Commits weiterhin über das Reflog erreichbar. Finden Sie den Hash in git reflog, dann reset --hard oder cherry-pick zur Wiederherstellung. Deshalb ist Git sicher — fast nichts ist wirklich weg.
# Find the commit you lost (e.g., after a hard reset)
git reflog
# a1b2c3d HEAD@{0}: reset: moving to HEAD~1
# e4f5g6h HEAD@{1}: commit: Important work <-- this one
# Reset back to the lost commit
git reset --hard e4f5g6h
# Or cherry-pick it onto your current branch
git cherry-pick e4f5g6hReflog & Reset
ORIG_HEAD ist eine Convenience-Ref, die nach destruktiven Operationen (reset, merge, rebase) auf den vorherigen HEAD zeigt. git reset --hard ORIG_HEAD macht die letzte solche Operation in einem Befehl rückgängig.
# Undo a git reset --hard
git reflog
git reset --hard HEAD@{1}
# Undo a rebase
git reflog
git reset --hard HEAD@{5}
# Undo a merge
git reset --hard ORIG_HEAD
# ORIG_HEAD is set by merge, rebase, reset, and cherry-pickVerfallen & Bereinigen
Reflog-Einträge häufen sich und verbrauchen Speicherplatz. expire entfernt alte Einträge; --expire-unreachable zielt nur auf Einträge, die von keiner Ref erreichbar sind. Nach dem Verfallen führen Sie git gc --prune=now aus, um unerreichbare Objekte zu löschen.
# Expire reflog entries older than 30 days
git reflog expire --expire=30.days
# Expire entries unreachable from current branches
git reflog expire --expire-unreachable=30.days
# Delete a specific reflog entry
git reflog delete HEAD@{2}
# Dry run (see what would be expired)
git reflog expire --dry-run --expire=now --allReflog für Branches
Jeder Branch führt sein eigenes Reflog. Wenn Sie einen Branch mit git branch -D löschen, sind die Commits noch im Reflog — finden Sie den Hash und erstellen Sie den Branch mit git branch <Name> <Hash> neu.
# Each branch has its own reflog
git reflog show main
# a1b2c3d main@{0}: commit: Update docs
# e4f5g6h main@{1}: pull origin main: Fast-forward
# Recover a deleted branch
git reflog # find the hash the branch pointed to
git branch recovered-branch e4f5g6h
# Compare current state with a past reflog entry
git diff HEAD@{1} HEADLFS
Installieren & Tracken
Git LFS speichert große Dateien (Bilder, Videos, Binärdateien) außerhalb des Git-Repositories und ersetzt sie in Commits durch Zeigerdateien. git lfs track registriert Muster in .gitattributes. Committen Sie immer .gitattributes, bevor Sie große Dateien hinzufügen.
# Install Git LFS (once per user)
git lfs install
# Track large file types
git lfs track "*.psd"
git lfs track "*.zip"
git lfs track "assets/*"
# View tracking rules
cat .gitattributes
# Commit the .gitattributes file
git add .gitattributes
git commit -m "Configure LFS tracking"LFS-Dateien hinzufügen & committen
Sobald ein Dateimuster getrackt ist, stagt git add die Datei automatisch über LFS. Der Commit speichert eine kleine Zeigerdatei (~130 Bytes) anstelle der Binärdatei. Der tatsächliche Inhalt wird beim Pushen auf den LFS-Server hochgeladen.
# After configuring tracking, add files normally
git add design.psd
git commit -m "Add design file"
# Verify LFS is handling the file
git lfs ls-files
# a1b2c3d4 * design.psd
# The commit contains a pointer, not the actual file
git show HEAD -- design.psd
# version https://git-lfs.github.com/spec/v1
# oid sha256:...
# size 12345678Klonen & Pullen
Das Klonen eines Repos mit LFS lädt zuerst Zeigerdateien, dann den tatsächlichen Inhalt. Wenn der LFS-Download fehlschlägt, versucht git lfs pull erneut. git lfs fetch lädt Objekte herunter, ohne sie in den Working Tree zu schreiben.
# Clone a repo with LFS files (downloads them automatically)
git clone https://github.com/user/repo.git
# If LFS files are missing, fetch them
git lfs pull
# Fetch LFS objects without checking them out
git lfs fetch
# Checkout LFS files for specific paths
git lfs checkout assets/Zu LFS migrieren
git lfs migrate import konvertiert retrospektiv große Dateien im Verlauf zu LFS-Zeigern. Dies schreibt alle Commit-Hashes um — jeder Mitarbeiter muss neu klonen. Führen Sie --dry-run zuerst aus, um die Auswirkungen zu sehen.
# Convert existing large files to LFS (rewrites history!)
git lfs migrate import --include="*.psd" --include-ref=refs/heads/main
# Migrate all branches
git lfs migrate import --include="*.psd" --everything
# Check what would be migrated (dry run)
git lfs migrate import --include="*.psd" --include-ref=refs/heads/main --dry-runLFS-Verwaltung
git lfs status zeigt ausstehende LFS-Änderungen. git lfs env zeigt die Konfiguration. git lfs fsck verifiziert, dass alle LFS-Objekte, die von Zeigerdateien referenziert werden, vorhanden und unbeschädigt sind.
# View LFS status
git lfs status
# List all LFS files in the repo
git lfs ls-files
# Check LFS configuration
git lfs env
# Untrack a file type (does not remove existing LFS objects)
git lfs untrack "*.zip"
# Verify LFS objects are present and valid
git lfs fsckCI/CD-Integration
GitHub Actions Grundlagen
GitHub Actions führt Workflows bei Push/PR aus. actions/checkout fetcht das Repo; fetch-depth: 0 holt den vollständigen Verlauf. npm ci installiert aus der Lockfile (schneller, strikter als install). Cachen Sie Abhängigkeiten mit dem Cache-Key.
# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm test
- run: npm run buildBedingte Workflows
Filtern Sie Workflows nach Branch oder Event mit on: push: branches. Verwenden Sie Job-Level if:-Bedingungen, um Jobs basierend auf Kontext zu überspringen. needs: erstellt Abhängigkeiten zwischen Jobs — deploy läuft nur, wenn test bestanden wird.
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm test
deploy:
needs: test
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- run: ./deploy.shGit-Hooks in CI
CI-Pipelines spiegeln oft lokale Hooks wider: zuerst linten (schnelles Fehlschlagen), dann testen. needs: lint stellt sicher, dass Tests nur laufen, wenn Linting bestanden wird, und spart CI-Minuten. Das Aufteilen von Jobs ermöglicht parallele Runner für Geschwindigkeit.
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: '20' }
- run: npm ci
- run: npm run lint
- run: npm run typecheck
test:
needs: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm test -- --coverageSecrets & Umgebung
Speichern Sie Secrets (API-Keys, Tokens) in Repo-Einstellungen und referenzieren Sie sie über ${{ secrets.NAME }}. Sie werden nie in Logs ausgegeben. Umgebungen können manuelle Genehmigung vor dem Deployment erfordern und fügen ein Gate hinzu.
jobs:
deploy:
runs-on: ubuntu-latest
environment: production # requires manual approval
steps:
- uses: actions/checkout@v4
- name: Deploy
env:
API_KEY: ${{ secrets.API_KEY }}
DB_URL: ${{ secrets.DATABASE_URL }}
run: ./scripts/deploy.sh "$API_KEY" "$DB_URL"Matrix-Builds
Matrix-Builds führen denselben Job über mehrere OS/Sprach-Kombinationen parallel aus. Dies fängt plattformspezifische Bugs früh. Verwenden Sie fail-fast: false, um alle Kombinationen auszuführen, selbst wenn eine fehlschlägt. Halten Sie Matrizes vernünftig, um CI-Minuten zu kontrollieren.
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
node-version: ['18', '20', '22']
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm testVerwandte Git-Snippets
Copy-paste ready code for common tasks.
Was this helpful?