--- 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 # 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 ``` ### 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 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 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 ``` ## 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: ``` :