diff --git a/git/README.md b/git/README.md index d7df09b..590044c 100644 --- a/git/README.md +++ b/git/README.md @@ -4,146 +4,1150 @@ include_toc: true --- # Git -## delete branch +## Grundlagen -Lokal Branch löschen z.B. wenn er auf Origin in master gemergt wurde. +### Repository initialisieren -``` -// delete branch locally -git branch -d localBranchName +Ein neues Git-Repository erstellen: -// delete branch remotely -git push origin --delete remoteBranchName +```bash +git init ``` -## master updaten auf Stand von origin/master +Oder ein bestehendes Repository klonen: -``` -git checkout master -git pull -git reset --hard origin/master -git pull +```bash +git clone + +# Beispiel mit HTTPS +git clone https://github.com/user/repository.git + +# Beispiel mit SSH +git clone git@github.com:user/repository.git + +# Mit spezifischem Verzeichnisnamen +git clone ``` -## Lokal ausgecheckter Feature-Branch in master mergen +### Git Konfiguration -Vorgehensweise: Lokal in den master-Branch mergen und dann nach origin/master pushen. +Grundlegende Konfiguration nach der Installation: -Der übliche Weg sieht etwa so aus (ohne Pull-Request-Workflow): +```bash +# Benutzername global setzen +git config --global user.name "Dein Name" - - Auf master wechseln (lokal): `git checkout master` - - Aktuellste Änderungen von origin/master holen und mit lokalem master synchronisieren: `git pull origin master` - - Deinen Feature-Branch in den lokalen master mergen (angenommen, Dein Branch heißt feature/mybranch): `git merge feature/mybranch` - - Falls Merge-Konflikte auftreten, diese im Code beheben, Dateien committen, sodass der Merge abgeschlossen werden kann. - - Änderungen auf den Remote-Master pushen: `git push origin master` +# E-Mail global setzen +git config --global user.email "deine.email@example.com" -Nun ist der Code aus `feature/mybranch` in `origin/master` eingeflossen. +# Standard-Editor festlegen +git config --global core.editor "code --wait" # für VS Code -## Remote Branch als neuen local branch +# Aktuelle Konfiguration anzeigen +git config --list +# Nur lokale Konfiguration (für aktuelles Repo) +git config user.name "Anderer Name" + +# Spezifischen Wert abfragen +git config user.email ``` -git fetch origin -# Anzeigen aller Branches + +### Remote Repositories verwalten + +```bash +# Remote-Repositories anzeigen +git remote -v + +# Neues Remote-Repository hinzufügen +git remote add +git remote add origin https://github.com/user/repo.git + +# Remote-URL ändern +git remote set-url origin + +# Remote-Repository entfernen +git remote remove + +# Remote-Repository umbenennen +git remote rename +``` + +## Dateien hinzufügen und committen + +### Staging Area + +```bash +# Einzelne Datei zur Staging Area hinzufügen +git add dateiname.txt + +# Alle geänderten Dateien hinzufügen +git add . + +# Alle Dateien eines bestimmten Typs hinzufügen +git add *.js + +# Interaktives Staging (wähle aus, was gestaged werden soll) +git add -p + +# Dateien aus der Staging Area entfernen (unstage) +git reset HEAD dateiname.txt +# oder mit neuerer Git-Version +git restore --staged dateiname.txt +``` + +### Commits erstellen + +```bash +# Commit mit Message erstellen +git commit -m "Beschreibung der Änderungen" + +# Alle geänderten, bereits getrackten Dateien committen (überspringt git add) +git commit -a -m "Commit-Message" + +# Letzten Commit ändern (Message oder Dateien ergänzen) +git commit --amend -m "Neue Commit-Message" + +# Leeren Commit erstellen (nützlich für CI/CD Trigger) +git commit --allow-empty -m "Trigger rebuild" +``` + +### Status und Unterschiede anzeigen + +```bash +# Status des Working Directory anzeigen +git status + +# Kurze Statusanzeige +git status -s + +# Unterschiede im Working Directory anzeigen (noch nicht gestaged) +git diff + +# Unterschiede in der Staging Area anzeigen +git diff --staged +# oder +git diff --cached + +# Unterschiede zwischen zwei Commits +git diff + +# Nur Dateinamen der geänderten Dateien anzeigen +git diff --name-only + +# Unterschiede einer bestimmten Datei anzeigen +git diff dateiname.txt +``` + +## Branches + +### Branch-Grundlagen + +```bash +# Alle lokalen Branches anzeigen +git branch + +# Alle Branches (lokal und remote) anzeigen +git branch -a + +# Nur Remote-Branches anzeigen +git branch -r + +# Neuen Branch erstellen +git branch + +# Neuen Branch erstellen und direkt dorthin wechseln +git checkout -b +# oder mit neuerer Syntax +git switch -c + +# Zu einem Branch wechseln +git checkout +# oder +git switch + +# Branch umbenennen +git branch -m +# Aktuellen Branch umbenennen +git branch -m +``` + +### Branch löschen + +Lokal Branch löschen, z.B. wenn er auf Remote in master/main gemergt wurde: + +```bash +# Lokal löschen (nur wenn bereits gemergt) +git branch -d + +# Lokal löschen (erzwingen, auch wenn nicht gemergt) +git branch -D + +# Remote löschen +git push origin --delete +# Alternative Syntax +git push origin : +``` + +**Beispiel:** + +```bash +# Feature-Branch nach Merge löschen +git checkout main +git branch -d feature/neue-funktion +git push origin --delete feature/neue-funktion +``` + +### Remote Branch als neuen lokalen Branch auschecken + +```bash +# Remote-Änderungen holen (ohne zu mergen) +git fetch origin + +# Alle Branches anzeigen +git branch -a + +# Remote-Branch als lokalen Branch auschecken +git checkout -b origin/ + +# Wenn lokaler und remote Name gleich sind (ab Git 2.23) +git checkout --track origin/ +# oder einfach +git checkout # Git erstellt automatisch tracking branch +``` + +**Beispiel:** + +```bash +git fetch origin git branch -a -# zuerst local dann origin-name angeben: git checkout -b INITIATIVE-242_Ru origin/INITIATIVE-242_Ru ``` -## Branch löschen +### Branch mit anderem Branch aktualisieren -### Lokal löschen +Eigenen Feature-Branch mit den neuesten Änderungen aus main/master aktualisieren: -``` -git branch -d (wenn gemergt) -git branch -D (um zu erzwingen) -``` +#### Mit Rebase (empfohlen für saubere History) -### Remote löschen - - -``` -git push origin --delete - -``` - -## Tag löschen - -### Lokal - -``` -git tag -d tagname -``` - -### Remote - -``` -git push --delete origin tagname -``` - -## 1 oder mehrere Commits zurück - -### 1 Schritt zurück - -``` -git reset --hard HEAD~1 -``` - -### Mehrere Schritte zurück - -``` -git reset --hard -``` - -! nicht vergessen, anschliessend für remote anpassen: - -``` -git push -f -``` - -## Overwrite local history with remote - -``` -git fetch --all -git reset --hard / -``` - -## Eigenen Branch mit dem Master-Branch aktualisieren - -``` -git checkout master +```bash +# Zuerst main/master aktualisieren +git checkout main git pull -git checkout xyz -git rebase -i master + +# Zum Feature-Branch wechseln +git checkout feature/mein-branch + +# Rebase durchführen +git rebase main + +# Bei Konflikten: Konflikte in den Dateien lösen, dann: +git add . +git rebase --continue + +# Falls zu komplex: Rebase abbrechen +git rebase --abort + +# Nach erfolgreichem Rebase: Force-Push (mit Sicherheitsnetz) +git push --force-with-lease ``` -... hier die Konflikte lösen ... +#### Interaktives Rebase für mehr Kontrolle -``` +```bash +git checkout main +git pull +git checkout feature/mein-branch +git rebase -i main + +# Im Editor: Commits anpassen (pick, squash, edit, drop, etc.) +# Nach dem Speichern: Konflikte lösen falls nötig git add . git rebase --continue git push --force-with-lease ``` -## Neuer Branch aus falschem Branch +#### Mit Merge (behält alle Commits) -### Ausgangslage - -Neuer Branch (b) wurde fälschlicherweise aus einem anderen Branch (a) (anstatt dem Master) erstellt. Die Files aus (a) sind nun doppelt vorhanden, nämlich auch in (b). Bei einem Pull-Request für (b) sind dann die files auch von (a) drin. - -### Problemlösung +```bash +git checkout feature/mein-branch +git merge main +# Konflikte lösen falls nötig, dann: +git add . +git commit # Merge-Commit erstellen +git push ``` -git checkout master + +### Neuer Branch aus falschem Branch erstellt + +#### Ausgangslage + +Ein neuer Branch (feature-b) wurde fälschlicherweise aus einem anderen Branch (feature-a) anstatt aus main/master erstellt. Die Commits aus feature-a erscheinen nun auch in feature-b. + +#### Problemlösung + +```bash +# Main aktualisieren +git checkout main git pull -git checkout (b) + +# Zum problematischen Branch wechseln +git checkout feature-b git pull -git rebase -i master + +# Interaktives Rebase auf main +git rebase -i main + +# Im Editor: Bei den Commits aus feature-a, die nicht in feature-b gehören: +# Ändere "pick" zu "drop" (oder lösche die Zeile komplett) +# Speichern und schließen + +# Prüfen ob alles korrekt ist +git log --oneline + +# Force-Push mit Sicherheitsnetz +git push --force-with-lease ``` -bei den commits aus (b), also die, die nicht in den neuen branch gehören, ein d vorne dran (anstatt bestehendem pick) und speichern +**Alternative: Branch neu erstellen** +```bash +# Neuen Branch vom richtigen Ausgangspunkt erstellen +git checkout main +git pull +git checkout -b feature-b-neu + +# Nur die gewünschten Commits cherry-picken +git cherry-pick +git cherry-pick + +# Alten Branch löschen +git branch -D feature-b +git push origin --delete feature-b + +# Neuen Branch umbenennen und pushen +git branch -m feature-b +git push -u origin feature-b ``` -git log (zum prüfen ob ok) + +## Merging und Integration + +### Feature-Branch in main/master mergen + +Vorgehensweise ohne Pull-Request-Workflow: + +```bash +# 1. Auf main/master wechseln (lokal) +git checkout main + +# 2. Aktuellste Änderungen holen und synchronisieren +git pull origin main + +# 3. Feature-Branch in lokalen main mergen +git merge feature/mein-branch + +# 4. Bei Merge-Konflikten: Konflikte in den Dateien beheben +# Konfliktmarkierungen (<<<<<<<, =======, >>>>>>>) im Code auflösen +# Dann Dateien stagen: +git add +# Merge abschließen: +git commit + +# 5. Änderungen auf Remote pushen +git push origin main +``` + +**Alternative mit Fast-Forward vermeiden:** + +```bash +# Merge-Commit erzwingen (auch wenn Fast-Forward möglich wäre) +git merge --no-ff feature/mein-branch +``` + +### Merge abbrechen + +```bash +# Falls während eines Merges etwas schiefgeht +git merge --abort +``` + +## Cherry-Pick + +Einzelne Commits aus einem Branch in einen anderen übernehmen: + +```bash +# Einzelnen Commit cherry-picken +git cherry-pick + +# Mehrere Commits cherry-picken +git cherry-pick + +# Bereich von Commits cherry-picken (exklusiv start, inklusiv end) +git cherry-pick .. + +# Cherry-Pick ohne automatischen Commit +git cherry-pick -n + +# Bei Konflikten: Konflikte lösen, dann +git add . +git cherry-pick --continue + +# Cherry-Pick abbrechen +git cherry-pick --abort +``` + +**Beispiel:** + +```bash +# Commit aus feature-a in feature-b übernehmen +git checkout feature-b +git cherry-pick abc123 +``` + +## Stash - Änderungen temporär speichern + +```bash +# Aktuelle Änderungen in den Stash speichern +git stash +# oder mit Beschreibung +git stash save "WIP: Feature XY" + +# Stash mit untracked Dateien +git stash -u +# oder mit allen Dateien (auch ignored) +git stash -a + +# Alle Stashes anzeigen +git stash list + +# Stash anwenden (behält Stash) +git stash apply +# Spezifischen Stash anwenden +git stash apply stash@{2} + +# Stash anwenden und entfernen +git stash pop +# Spezifischen Stash poppen +git stash pop stash@{2} + +# Stash-Inhalt anzeigen +git stash show +git stash show -p # mit diff + +# Stash löschen +git stash drop stash@{0} + +# Alle Stashes löschen +git stash clear + +# Branch aus Stash erstellen +git stash branch +``` + +**Typisches Szenario:** + +```bash +# Arbeit unterbrechen für dringenden Bugfix +git stash +git checkout main +git checkout -b hotfix/bug +# Bugfix durchführen... +git checkout feature/meine-arbeit +git stash pop +``` + +## History und Logs + +### Commit-History anzeigen + +```bash +# Standard Log +git log + +# Kompakte einzeilige Darstellung +git log --oneline + +# Mit Grafik der Branches +git log --graph --oneline --all + +# Letzten N Commits anzeigen +git log -n 5 +git log -5 + +# Logs mit Änderungen +git log -p + +# Logs eines bestimmten Autors +git log --author="Name" + +# Logs in einem Zeitraum +git log --since="2024-01-01" --until="2024-12-31" +git log --since="2 weeks ago" + +# Logs für eine bestimmte Datei +git log -- pfad/zur/datei.txt + +# Commits finden, die einen bestimmten String ändern +git log -S "suchtext" + +# Schöne formatierte Ausgabe +git log --pretty=format:"%h - %an, %ar : %s" +``` + +### Commit-Details anzeigen + +```bash +# Details eines bestimmten Commits +git show + +# Dateien in einem Commit +git show --name-only + +# Statistiken eines Commits +git show --stat +``` + +### Reflog - History der HEAD-Bewegungen + +```bash +# Alle HEAD-Bewegungen anzeigen (auch bei reset, rebase, etc.) +git reflog + +# Nützlich um "verlorene" Commits wiederzufinden +git reflog show + +# Zu einem früheren Zustand zurückkehren +git reset --hard HEAD@{2} +``` + +## Commits rückgängig machen + +### Reset - History zurücksetzen + +```bash +# Einen Commit zurück (Änderungen bleiben im Working Directory) +git reset --soft HEAD~1 + +# Einen Commit zurück (Änderungen bleiben unstaged) +git reset HEAD~1 +# oder +git reset --mixed HEAD~1 + +# Einen Commit zurück (ACHTUNG: Änderungen werden gelöscht!) +git reset --hard HEAD~1 + +# Mehrere Commits zurück +git reset --hard HEAD~3 + +# Zu einem bestimmten Commit zurück +git reset --hard + +# Nach einem Reset: Remote überschreiben (Vorsicht!) +git push --force +# Sicherer: Mit force-with-lease (schützt vor Überschreiben anderer Änderungen) +git push --force-with-lease +``` + +### Revert - Commit rückgängig machen (sicher für Shared Branches) + +```bash +# Einen Commit rückgängig machen (erstellt neuen Commit) +git revert + +# Mehrere Commits rückgängig machen +git revert + +# Letzten Commit rückgängig machen +git revert HEAD + +# Revert ohne automatischen Commit +git revert -n +``` + +**Unterschied Reset vs. Revert:** +- `reset`: Ändert die History (problematisch bei Shared Branches) +- `revert`: Erstellt neuen Commit (sicher für Shared Branches) + +### Einzelne Datei auf älteren Stand zurücksetzen + +```bash +# Datei aus einem bestimmten Commit wiederherstellen +git checkout -- pfad/zur/datei.txt + +# Datei auf Stand von HEAD (letzter Commit) zurücksetzen +git checkout HEAD -- datei.txt +# oder mit neuerer Syntax +git restore datei.txt + +# Datei auf Stand von Remote zurücksetzen +git checkout origin/main -- datei.txt +``` + +## Lokale History mit Remote überschreiben + +```bash +# Alle Remote-Änderungen holen +git fetch --all + +# Lokalen Branch komplett mit Remote überschreiben +git reset --hard origin/ + +# Beispiel für main +git fetch --all +git reset --hard origin/main +``` + +**Wichtig:** Alle lokalen Änderungen gehen verloren! + +## Main/Master auf Stand von origin aktualisieren + +```bash +# Standard-Methode +git checkout main +git pull + +# Falls lokale Änderungen verworfen werden sollen +git checkout main +git fetch origin +git reset --hard origin/main + +# Alternative: Zuerst fetch, dann pull +git checkout main +git fetch origin +git pull origin main +``` + +## Tags + +### Tags erstellen + +```bash +# Lightweight Tag erstellen +git tag v1.0.0 + +# Annotated Tag erstellen (empfohlen) +git tag -a v1.0.0 -m "Version 1.0.0 Release" + +# Tag für einen bestimmten Commit +git tag -a v1.0.0 -m "Release" + +# Tags auf Remote pushen +git push origin v1.0.0 + +# Alle Tags auf Remote pushen +git push origin --tags +``` + +### Tags anzeigen + +```bash +# Alle Tags anzeigen +git tag + +# Tags mit Muster suchen +git tag -l "v1.0.*" + +# Tag-Details anzeigen +git show v1.0.0 +``` + +### Tags löschen + +```bash +# Lokal löschen +git tag -d + +# Remote löschen +git push --delete origin +# Alternative Syntax +git push origin :refs/tags/ +``` + +**Beispiel:** + +```bash +git tag -d v1.0.0 +git push --delete origin v1.0.0 +``` + +## .gitignore + +Dateien und Verzeichnisse von der Versionskontrolle ausschließen: + +```bash +# .gitignore Datei im Root-Verzeichnis erstellen +touch .gitignore +``` + +**Beispiel .gitignore:** + +```gitignore +# Kompilierte Dateien +*.class +*.o +*.pyc +__pycache__/ + +# Build-Verzeichnisse +/build/ +/dist/ +/target/ + +# Abhängigkeiten +node_modules/ +vendor/ + +# IDE-spezifische Dateien +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# Betriebssystem-Dateien +.DS_Store +Thumbs.db + +# Umgebungsvariablen und Secrets +.env +.env.local +secrets.yml + +# Logs +*.log +logs/ + +# Temporäre Dateien +tmp/ +temp/ +*.tmp + +# Spezifische Datei ignorieren +config/database.yml + +# Alle Dateien eines Typs in einem Verzeichnis +docs/**/*.pdf + +# Negation: Datei NICHT ignorieren +!wichtig.log +``` + +### Bereits getrackte Dateien ignorieren + +```bash +# Datei aus Git entfernen, aber lokal behalten +git rm --cached dateiname + +# Verzeichnis aus Git entfernen, aber lokal behalten +git rm -r --cached verzeichnis/ + +# Dann .gitignore aktualisieren und committen +``` + +## Synchronisation mit Remote + +### Pull und Fetch + +```bash +# Änderungen holen und mergen +git pull + +# Von spezifischem Remote und Branch +git pull origin main + +# Fetch: Nur Änderungen holen (ohne zu mergen) +git fetch +git fetch origin + +# Mit Rebase statt Merge +git pull --rebase + +# Alle Remotes fetchen +git fetch --all + +# Remote-Branches prunen (gelöschte entfernen) +git fetch --prune +``` + +### Push + +```bash +# Zum konfigurierten Remote pushen +git push + +# Zu spezifischem Remote und Branch +git push origin main + +# Neuen Branch auf Remote erstellen und tracken +git push -u origin neuer-branch +# oder +git push --set-upstream origin neuer-branch + +# Force Push (Vorsicht!) +git push --force + +# Sicherer Force Push git push --force-with-lease +# Alle Branches pushen +git push --all + +# Tags mit pushen +git push --tags +``` + +## Arbeiten mit Patches + +```bash +# Patch aus Commits erstellen +git format-patch -1 HEAD +git format-patch HEAD~3..HEAD + +# Patch anwenden +git apply patch-datei.patch + +# Patch mit Commit-Informationen anwenden +git am < patch-datei.patch + +# Prüfen ob Patch anwendbar ist +git apply --check patch-datei.patch +``` + +## Submodules + +```bash +# Submodule hinzufügen +git submodule add pfad/zum/submodule + +# Repository mit Submodules klonen +git clone --recurse-submodules + +# Submodules in bestehendem Repo initialisieren +git submodule init +git submodule update + +# Alle Submodules aktualisieren +git submodule update --remote + +# Submodule entfernen +git submodule deinit pfad/zum/submodule +git rm pfad/zum/submodule +rm -rf .git/modules/pfad/zum/submodule +``` + +## Nützliche Aliase + +Git-Aliase in der Konfiguration einrichten: + +```bash +# Kurzformen für häufige Befehle +git config --global alias.co checkout +git config --global alias.br branch +git config --global alias.ci commit +git config --global alias.st status + +# Log mit Graph +git config --global alias.lg "log --graph --oneline --all --decorate" + +# Undo letzter Commit (behält Änderungen) +git config --global alias.undo "reset HEAD~1" + +# Kurzform für Status +git config --global alias.s "status -s" + +# Branch mit letztem Commit anzeigen +git config --global alias.branches "branch -v" +``` + +## Troubleshooting + +### Merge-Konflikte lösen + +```bash +# Status der Konflikte anzeigen +git status + +# Konflikte in den Dateien manuell lösen (<<<<<<, ======, >>>>>>) +# Dann: +git add +git commit + +# Merge abbrechen und zurück zum Ursprung +git merge --abort + +# Mergetool verwenden +git mergetool +``` + +### Versehentlich gelöschte Dateien wiederherstellen + +```bash +# Datei aus letztem Commit wiederherstellen +git restore datei.txt +# oder +git checkout HEAD -- datei.txt + +# Gelöschte Dateien finden +git log --diff-filter=D --summary | grep delete + +# Datei aus History wiederherstellen +git checkout ^ -- datei.txt +``` + +### Commit an falschen Branch + +```bash +# Szenario: Commit versehentlich an main statt an Feature-Branch + +# 1. Neuen Branch vom aktuellen Stand erstellen +git branch feature/neuer-branch + +# 2. Main zurücksetzen +git reset --hard HEAD~1 + +# 3. Zum neuen Branch wechseln +git checkout feature/neuer-branch +``` + +### Große Dateien aus History entfernen + +```bash +# Git filter-branch (alte Methode, nicht empfohlen) +git filter-branch --tree-filter 'rm -f grosse-datei.zip' HEAD + +# BFG Repo-Cleaner (empfohlen, schneller) +# Zuerst BFG installieren, dann: +bfg --delete-files grosse-datei.zip + +# Git filter-repo (moderner Ersatz für filter-branch) +git filter-repo --path grosse-datei.zip --invert-paths +``` + +### Detached HEAD State + +```bash +# Zu einem Branch zurückkehren +git checkout main + +# Änderungen aus Detached HEAD in neuem Branch speichern +git checkout -b neuer-branch +``` + +### Versehentlich überschriebene Änderungen wiederherstellen + +```bash +# Reflog verwenden um verlorene Commits zu finden +git reflog + +# Zu einem früheren Zustand zurückkehren +git reset --hard HEAD@{5} +``` + +## Best Practices + +### Commit-Messages + +Gute Commit-Messages folgen diesem Format: + +``` +: + + + +