1272 lines
26 KiB
Markdown
1272 lines
26 KiB
Markdown
---
|
|
gitea: none
|
|
include_toc: true
|
|
---
|
|
# Git
|
|
|
|
## Grundlagen
|
|
|
|
### Das Drei-Stufen-Konzept
|
|
|
|
Git arbeitet mit drei Bereichen:
|
|
|
|
- __Working Directory__ (Arbeitsverzeichnis) - hier bearbeitest du deine Dateien
|
|
- __Staging Area__ - hier sammelst du Änderungen, die du committen möchtest
|
|
- __Repository__ - hier werden die Commits gespeichert
|
|
|
|
### Git Konfiguration
|
|
|
|
Grundlegende Konfiguration nach der Installation:
|
|
|
|
```bash
|
|
# Benutzername global setzen
|
|
git config --global user.name "Dein Name"
|
|
|
|
# E-Mail global setzen
|
|
git config --global user.email "deine.email@example.com"
|
|
|
|
# Standard-Editor festlegen
|
|
git config --global core.editor "code --wait" # für VS Code
|
|
|
|
# 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
|
|
```
|
|
|
|
### Repository initialisieren
|
|
|
|
Ein neues Git-Repository erstellen:
|
|
|
|
```bash
|
|
git init
|
|
```
|
|
|
|
Oder ein bestehendes Repository klonen:
|
|
|
|
```bash
|
|
git clone <repository-url>
|
|
|
|
# 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 <repository-url> <verzeichnisname>
|
|
```
|
|
|
|
### Remote Repositories verwalten
|
|
|
|
```bash
|
|
# Remote-Repositories anzeigen
|
|
git remote -v
|
|
|
|
# Neues Remote-Repository hinzufügen
|
|
git remote add <name> <url>
|
|
git remote add origin https://github.com/user/repo.git
|
|
|
|
# Remote-URL ändern
|
|
git remote set-url origin <neue-url>
|
|
|
|
# Remote-Repository entfernen
|
|
git remote remove <name>
|
|
|
|
# Remote-Repository umbenennen
|
|
git remote rename <alter-name> <neuer-name>
|
|
```
|
|
|
|
## 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 <commit1> <commit2>
|
|
|
|
# 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 <branch-name>
|
|
|
|
# Neuen Branch erstellen und direkt dorthin wechseln
|
|
git checkout -b <branch-name>
|
|
# oder mit neuerer Syntax
|
|
git switch -c <branch-name>
|
|
|
|
# Zu einem Branch wechseln
|
|
git checkout <branch-name>
|
|
# oder
|
|
git switch <branch-name>
|
|
|
|
# Branch umbenennen
|
|
git branch -m <alter-name> <neuer-name>
|
|
# Aktuellen Branch umbenennen
|
|
git branch -m <neuer-name>
|
|
```
|
|
|
|
### 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 <branch-name>
|
|
|
|
# Lokal löschen (erzwingen, auch wenn nicht gemergt)
|
|
git branch -D <branch-name>
|
|
|
|
# Remote löschen
|
|
git push origin --delete <branch-name>
|
|
# Alternative Syntax
|
|
git push origin :<branch-name>
|
|
```
|
|
|
|
**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 <lokaler-name> origin/<remote-branch>
|
|
|
|
# Wenn lokaler und remote Name gleich sind (ab Git 2.23)
|
|
git checkout --track origin/<branch-name>
|
|
# oder einfach
|
|
git checkout <branch-name> # Git erstellt automatisch tracking branch
|
|
```
|
|
|
|
**Beispiel:**
|
|
|
|
```bash
|
|
git fetch origin
|
|
git branch -a
|
|
git checkout -b INITIATIVE-242_Ru origin/INITIATIVE-242_Ru
|
|
```
|
|
|
|
### Branch mit anderem Branch aktualisieren
|
|
|
|
Eigenen Feature-Branch mit den neuesten Änderungen aus main/master aktualisieren:
|
|
|
|
#### Mit Rebase (empfohlen für saubere History)
|
|
|
|
```bash
|
|
# Zuerst main/master aktualisieren
|
|
git checkout main
|
|
git pull
|
|
|
|
# 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
|
|
```
|
|
|
|
#### 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
|
|
```
|
|
|
|
#### Mit Merge (behält alle Commits)
|
|
|
|
```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
|
|
```
|
|
|
|
### 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
|
|
|
|
# Zum problematischen Branch wechseln
|
|
git checkout feature-b
|
|
git pull
|
|
|
|
# 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
|
|
```
|
|
|
|
**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 <commit-hash-1>
|
|
git cherry-pick <commit-hash-2>
|
|
|
|
# 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
|
|
```
|
|
|
|
## 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 <konflikt-dateien>
|
|
# 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 <commit-hash>
|
|
|
|
# Mehrere Commits cherry-picken
|
|
git cherry-pick <commit-hash-1> <commit-hash-2>
|
|
|
|
# Bereich von Commits cherry-picken (exklusiv start, inklusiv end)
|
|
git cherry-pick <start-commit>..<end-commit>
|
|
|
|
# Cherry-Pick ohne automatischen Commit
|
|
git cherry-pick -n <commit-hash>
|
|
|
|
# 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 <branch-name>
|
|
```
|
|
|
|
**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 <commit-hash>
|
|
|
|
# Dateien in einem Commit
|
|
git show --name-only <commit-hash>
|
|
|
|
# Statistiken eines Commits
|
|
git show --stat <commit-hash>
|
|
```
|
|
|
|
### 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 <commit-hash>
|
|
|
|
# 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 <commit-hash>
|
|
|
|
# Mehrere Commits rückgängig machen
|
|
git revert <commit-hash-1> <commit-hash-2>
|
|
|
|
# Letzten Commit rückgängig machen
|
|
git revert HEAD
|
|
|
|
# Revert ohne automatischen Commit
|
|
git revert -n <commit-hash>
|
|
```
|
|
|
|
**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 <commit-hash> -- 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
|
|
```
|
|
|
|
## Branch mit Remote synchronisieren
|
|
|
|
### Standard-Synchronisation (normaler Workflow)
|
|
|
|
Wenn du einfach die neuesten Änderungen vom Remote-Branch holen möchtest:
|
|
|
|
```bash
|
|
# Main/Master aktualisieren (Standard-Methode)
|
|
git checkout main
|
|
git pull
|
|
|
|
# Expliziter: Von spezifischem Remote pullen
|
|
git checkout main
|
|
git pull origin main
|
|
|
|
# Sicherer: Erst fetchen, dann Status prüfen, dann pullen
|
|
git checkout main
|
|
git fetch origin
|
|
git status # Prüfen ob lokale Änderungen existieren
|
|
git pull origin main
|
|
```
|
|
|
|
**Wann verwenden:** Reguläre Synchronisation, wenn keine lokalen Änderungen vorhanden sind oder diese per Merge integriert werden sollen.
|
|
|
|
### Lokale Änderungen komplett verwerfen (Notfall)
|
|
|
|
Wenn lokale Änderungen komplett verworfen und durch den Remote-Stand ersetzt werden sollen:
|
|
|
|
```bash
|
|
# ACHTUNG: Alle lokalen Änderungen gehen verloren!
|
|
git fetch --all
|
|
git reset --hard origin/<branch-name>
|
|
|
|
# Beispiel für main Branch
|
|
git checkout main
|
|
git fetch origin
|
|
git reset --hard origin/main
|
|
```
|
|
|
|
**Wann verwenden:**
|
|
- Lokale Commits sind fehlerhaft und sollen verworfen werden
|
|
- Merge-Konflikte sind zu komplex und ein Neustart ist einfacher
|
|
- Experimentelle Änderungen sollen rückgängig gemacht werden
|
|
- Feature-Branch soll auf exakt denselben Stand wie Remote
|
|
|
|
**Wichtig:**
|
|
- ⚠️ Alle lokalen, nicht gepushten Commits gehen verloren!
|
|
- ⚠️ Alle uncommitteten Änderungen gehen verloren!
|
|
- 💡 Tipp: Vorher Backup mit `git stash` oder `git branch backup-$(date +%Y%m%d)` erstellen
|
|
|
|
## 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 <commit-hash> -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 <tag-name>
|
|
|
|
# Remote löschen
|
|
git push --delete origin <tag-name>
|
|
# Alternative Syntax
|
|
git push origin :refs/tags/<tag-name>
|
|
```
|
|
|
|
**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
|
|
|
|
#### Zusammenspiel von Fetch, Pull, Merge und Rebase
|
|
|
|
**Grundprinzip:**
|
|
|
|
```
|
|
git pull = git fetch + git merge
|
|
git pull --rebase = git fetch + git rebase
|
|
```
|
|
|
|
**Was passiert im Detail:**
|
|
|
|
1. **`git fetch`** - Holt Änderungen vom Remote, **ohne** sie zu integrieren
|
|
- Lädt neue Commits vom Remote-Repository herunter
|
|
- Aktualisiert Remote-Tracking-Branches (z.B. `origin/main`)
|
|
- Ändert **nichts** am lokalen Branch oder Working Directory
|
|
- Sicher - kann nichts kaputt machen
|
|
|
|
2. **`git pull`** - Holt Änderungen **und** merged sie automatisch
|
|
- Führt intern `git fetch` aus
|
|
- Merged dann automatisch `origin/main` in lokalen `main`
|
|
- Erstellt Merge-Commit bei divergierenden Histories
|
|
- Kann zu Merge-Konflikten führen
|
|
|
|
3. **`git pull --rebase`** - Holt Änderungen **und** rebaset darauf
|
|
- Führt intern `git fetch` aus
|
|
- Setzt lokale Commits **auf top** der neuen Remote-Commits
|
|
- Keine Merge-Commits → saubere, lineare History
|
|
- Empfohlen für Feature-Branches
|
|
|
|
**Visueller Vergleich:**
|
|
|
|
```
|
|
# Ausgangssituation: Lokale und Remote-Commits divergieren
|
|
C (origin/main)
|
|
/
|
|
A - B
|
|
\
|
|
D (main, lokal)
|
|
|
|
# Nach git pull (merge):
|
|
C (origin/main)
|
|
/ \
|
|
A - B E (main, Merge-Commit)
|
|
\ /
|
|
D
|
|
|
|
# Nach git pull --rebase:
|
|
A - B - C (origin/main) - D' (main, rebasiert)
|
|
```
|
|
|
|
#### Befehle im Detail
|
|
|
|
```bash
|
|
# Fetch: Nur Änderungen holen (ohne zu integrieren)
|
|
git fetch
|
|
git fetch origin
|
|
|
|
# Jetzt lokal prüfen was sich geändert hat:
|
|
git log origin/main # Remote-Commits anschauen
|
|
git diff main origin/main # Unterschiede vergleichen
|
|
|
|
# Dann entscheiden: Merge oder Rebase?
|
|
git merge origin/main # Merge-Variante
|
|
# oder
|
|
git rebase origin/main # Rebase-Variante
|
|
|
|
# Pull: Änderungen holen und mergen (automatisch)
|
|
git pull
|
|
|
|
# Von spezifischem Remote und Branch
|
|
git pull origin main
|
|
|
|
# Mit Rebase statt Merge (empfohlen für saubere History)
|
|
git pull --rebase
|
|
git pull --rebase origin main
|
|
|
|
# Alle Remotes fetchen
|
|
git fetch --all
|
|
|
|
# Remote-Branches prunen (gelöschte entfernen)
|
|
git fetch --prune
|
|
|
|
# Fetch und prune in einem
|
|
git fetch --all --prune
|
|
```
|
|
|
|
#### Wann was verwenden?
|
|
|
|
| Szenario | Empfohlener Befehl | Begründung |
|
|
|----------|-------------------|------------|
|
|
| Erstmal schauen was sich geändert hat | `git fetch` | Kein Risiko, nur Download |
|
|
| Main/Master aktualisieren | `git pull` | Standard, Merge ist OK |
|
|
| Feature-Branch aktualisieren | `git pull --rebase` | Saubere lineare History |
|
|
| Unsicher bei Konflikten | `git fetch` + manuell merge/rebase | Mehr Kontrolle |
|
|
| Shared Branch (mehrere Entwickler) | `git pull` | Merge preserviert alle Histories |
|
|
| Privater Branch | `git pull --rebase` | History-Cleanup möglich |
|
|
|
|
**Best Practice - Der sichere Weg:**
|
|
|
|
```bash
|
|
# 1. Erstmal nur fetchen (kein Risiko)
|
|
git fetch origin
|
|
|
|
# 2. Prüfen was sich geändert hat
|
|
git log HEAD..origin/main --oneline
|
|
|
|
# 3. Unterschiede anschauen
|
|
git diff HEAD origin/main
|
|
|
|
# 4. Dann bewusst entscheiden
|
|
git merge origin/main
|
|
# oder
|
|
git rebase origin/main
|
|
```
|
|
|
|
### 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 <repository-url> pfad/zum/submodule
|
|
|
|
# Repository mit Submodules klonen
|
|
git clone --recurse-submodules <repository-url>
|
|
|
|
# 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 <gelöste-dateien>
|
|
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 <commit-hash>^ -- 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:
|
|
|
|
```
|
|
<Typ>: <Kurzbeschreibung (max 50 Zeichen)>
|
|
|
|
<Detaillierte Beschreibung (optional, 72 Zeichen pro Zeile)>
|
|
|
|
<Footer (optional): Issue-Referenzen, Breaking Changes, etc.>
|
|
```
|
|
|
|
**Typen:**
|
|
- `feat`: Neues Feature
|
|
- `fix`: Bugfix
|
|
- `docs`: Dokumentation
|
|
- `style`: Formatierung, kein Code-Change
|
|
- `refactor`: Code-Refactoring
|
|
- `test`: Tests hinzufügen oder anpassen
|
|
- `chore`: Build-Prozess, Dependencies, etc.
|
|
|
|
**Beispiele:**
|
|
|
|
```
|
|
feat: Benutzer-Login mit OAuth implementieren
|
|
|
|
fix: Null-Pointer Exception beim Speichern
|
|
|
|
docs: README mit Installationsanleitung aktualisiert
|
|
|
|
refactor: Datenbankzugriff in separate Klasse ausgelagert
|
|
```
|
|
|
|
### Workflow-Empfehlungen
|
|
|
|
1. **Häufig committen**: Kleine, logische Commits sind besser als große
|
|
2. **Branch-Strategie**: Feature-Branches für neue Entwicklungen
|
|
3. **Pull Requests**: Code-Review vor dem Merge
|
|
4. **Main/Master schützen**: Direkte Commits vermeiden
|
|
5. **Rebase vor Merge**: Saubere, lineare History
|
|
6. **Tests vor Push**: Lokale Tests durchführen
|
|
7. **Force-Push vermeiden**: Besonders bei Shared Branches
|
|
8. **Regelmäßig pullen**: Konflikte früh erkennen
|
|
|
|
### Branch-Naming-Konventionen
|
|
|
|
```
|
|
feature/kurze-beschreibung
|
|
bugfix/issue-nummer-beschreibung
|
|
hotfix/kritischer-bug
|
|
release/version-nummer
|
|
```
|
|
|
|
**Beispiele:**
|
|
```
|
|
feature/user-authentication
|
|
bugfix/login-validation
|
|
hotfix/security-patch
|
|
release/v1.2.0
|
|
```
|
|
|
|
## Fortgeschrittene Befehle
|
|
|
|
### Bisect - Buggy Commit finden
|
|
|
|
```bash
|
|
# Bisect starten
|
|
git bisect start
|
|
|
|
# Aktuellen Commit als "bad" markieren
|
|
git bisect bad
|
|
|
|
# Bekannten guten Commit markieren
|
|
git bisect good <commit-hash>
|
|
|
|
# Git checked automatisch Commits aus
|
|
# Nach jedem Test:
|
|
git bisect good # wenn OK
|
|
git bisect bad # wenn Bug vorhanden
|
|
|
|
# Bisect beenden
|
|
git bisect reset
|
|
```
|
|
|
|
### Worktree - Mehrere Branches gleichzeitig
|
|
|
|
```bash
|
|
# Neuen Worktree erstellen
|
|
git worktree add ../projekt-feature feature/neue-funktion
|
|
|
|
# Alle Worktrees anzeigen
|
|
git worktree list
|
|
|
|
# Worktree entfernen
|
|
git worktree remove ../projekt-feature
|
|
|
|
# Aufräumen
|
|
git worktree prune
|
|
```
|
|
|
|
### Blame - Änderungen pro Zeile anzeigen
|
|
|
|
```bash
|
|
# Zeigt wer welche Zeile wann geändert hat
|
|
git blame dateiname.txt
|
|
|
|
# Mit Zeilennummern
|
|
git blame -L 10,20 dateiname.txt
|
|
|
|
# Ignore Whitespace-Änderungen
|
|
git blame -w dateiname.txt
|
|
```
|
|
|
|
### Clean - Untracked Files entfernen
|
|
|
|
```bash
|
|
# Anzeigen was gelöscht würde (Dry-Run)
|
|
git clean -n
|
|
|
|
# Untracked Files löschen
|
|
git clean -f
|
|
|
|
# Auch Verzeichnisse löschen
|
|
git clean -fd
|
|
|
|
# Auch ignored Files löschen
|
|
git clean -fdx
|
|
```
|
|
|
|
## Git Hooks
|
|
|
|
Hooks sind Skripte die bei bestimmten Git-Events ausgeführt werden:
|
|
|
|
```bash
|
|
# Hooks befinden sich in:
|
|
.git/hooks/
|
|
|
|
# Beispiel: pre-commit Hook
|
|
# Datei: .git/hooks/pre-commit
|
|
#!/bin/bash
|
|
npm run lint
|
|
npm test
|
|
|
|
# Ausführbar machen
|
|
chmod +x .git/hooks/pre-commit
|
|
```
|
|
|
|
**Wichtige Hooks:**
|
|
- `pre-commit`: Vor jedem Commit
|
|
- `pre-push`: Vor jedem Push
|
|
- `post-merge`: Nach jedem Merge
|
|
- `post-checkout`: Nach Branch-Wechsel
|
|
|
|
## Nützliche Tipps
|
|
|
|
### Farbige Ausgabe aktivieren
|
|
|
|
```bash
|
|
git config --global color.ui auto
|
|
```
|
|
|
|
### Automatisches Stash bei Rebase
|
|
|
|
```bash
|
|
git config --global rebase.autoStash true
|
|
```
|
|
|
|
### Default Branch Name
|
|
|
|
```bash
|
|
git config --global init.defaultBranch main
|
|
```
|
|
|
|
### Pull Strategie festlegen
|
|
|
|
```bash
|
|
# Rebase als Standard beim Pull
|
|
git config --global pull.rebase true
|
|
|
|
# Fast-Forward only
|
|
git config --global pull.ff only
|
|
```
|
|
|
|
### Editor für Commit-Messages
|
|
|
|
```bash
|
|
git config --global core.editor "nano"
|
|
# oder für VS Code
|
|
git config --global core.editor "code --wait"
|
|
```
|
|
|
|
### Globales .gitignore
|
|
|
|
```bash
|
|
# Erstellen
|
|
touch ~/.gitignore_global
|
|
|
|
# Konfigurieren
|
|
git config --global core.excludesfile ~/.gitignore_global
|
|
|
|
# Beispiel-Inhalt: IDE und OS-spezifische Dateien
|
|
echo ".DS_Store" >> ~/.gitignore_global
|
|
echo ".vscode/" >> ~/.gitignore_global
|
|
echo "*.swp" >> ~/.gitignore_global
|
|
```
|