Das Wichtigste in Kürze
- Git speichert Snapshots deines Projekts; Änderungen laufen vom Arbeitsverzeichnis über die Staging Area in einen Commit.
- Branches sind günstig: Arbeite in einem eigenen Branch und führe ihn per merge oder rebase zurück.
- git reset unterscheidet sich je nach Modus darin, ob nur HEAD, auch der Index oder zusätzlich das Arbeitsverzeichnis zurückgesetzt wird.
- Rebase schreibt Commits neu: Wende es nicht auf Historie an, die schon andere von dir geholt haben.
Die Konzepte hinter den Befehlen
Git ist ein verteiltes Versionsverwaltungssystem. Nach der Darstellung in Pro Git speichert Git seine Daten nicht als Liste von Änderungen an Dateien, sondern als Folge von Snapshots: Bei jedem Commit hält Git fest, wie alle Dateien in diesem Moment aussehen. Unveränderte Dateien werden nicht erneut gespeichert, Git verweist auf die bereits vorhandene Version.
Eine Datei kann dabei drei Zustände haben: modified (geändert, noch nicht vorgemerkt), staged (für den nächsten Commit vorgemerkt) und committed (sicher in der lokalen Datenbank gespeichert). Daraus ergeben sich die drei Bereiche eines Projekts:
| Bereich | Bedeutung |
|---|---|
| Working Tree (Arbeitsverzeichnis) | Die Dateien, die du auf der Platte siehst und bearbeitest |
| Staging Area (Index) | Merkliste dessen, was in den nächsten Commit kommt |
Git-Verzeichnis (.git) | Datenbank mit der gesamten Historie |
Dazu kommen drei weitere Begriffe. Ein Branch ist eine bewegliche Markierung auf einem Commit, über die du parallel an verschiedenen Strängen arbeitest. HEAD zeigt auf den Commit, den du gerade ausgecheckt hast. Ein Remote ist ein Repository auf einem anderen Rechner oder Server, mit dem du Commits austauschst.
Befehlsübersicht nach Aufgaben
| Aufgabe | Befehl |
|---|---|
| Repository anlegen | git init, git clone <url> |
| Stand ansehen | git status, git diff, git log --oneline |
| Änderungen vormerken | git add <datei> |
| Commit anlegen | git commit -m "Nachricht" |
| Branch anlegen/wechseln | git switch -c <name>, git switch <name> |
| Branches auflisten/löschen | git branch, git branch -d <name> |
| Branch einbinden | git merge <name>, git rebase <ziel> |
| Arbeit zwischenlagern | git stash, git stash pop |
| Änderungen verwerfen | git restore <datei>, git restore --staged <datei> |
| Historie zurücksetzen | git reset --soft/--mixed/--hard <commit> |
| Mit Remote arbeiten | git remote add, git fetch, git pull, git push |
Repository anlegen, vormerken, committen
Die folgenden Beispiele laufen in einem frischen Verzeichnis. git init -b main legt ein Repository mit dem Branch main an. Danach hast du eine neue Datei, die Git noch nicht kennt (??):
git init -b main projekt
cd projekt
echo "# Projekt" > README.md
git status --short?? README.mdgit add merkt die Datei vor, git commit speichert den Snapshot:
git add README.md
git status --short
git commit -m "Erster Commit: README"A README.md
[main (root-commit) 374df69] Erster Commit: README
1 file changed, 1 insertion(+)
create mode 100644 README.mdDas A in der linken Spalte bedeutet „staged, neu hinzugefügt“. Ändere die Datei jetzt, zeigt git diff den Unterschied zwischen Arbeitsverzeichnis und Staging Area:
echo "Zeile 2" >> README.md
git diffdiff --git a/README.md b/README.md
index 5585de1..5ae98b0 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,2 @@
# Projekt
+Zeile 2Mit git commit -am stagest und committest du bereits getrackte Dateien in einem Schritt, git log --oneline zeigt die Historie kompakt:
git commit -am "README erweitert"
git log --oneline0dd594e README erweitert
374df69 Erster Commit: READMEPraxis-Tipp: Schreibe Commit-Nachrichten so, dass man die Änderung ohne Diff versteht („README erweitert“), und committe zusammengehörige Änderungen gemeinsam. Das macht
git logspäter nützlich.
Branches: Arbeiten ohne Risiko für main
Mit git switch -c legst du einen Branch an und wechselst gleich hinein. Ältere Anleitungen verwenden dafür git checkout -b; switch ist die speziellere Variante für diesen Zweck.
git switch -c feature/hallo
echo "print('hallo')" > hallo.py
git add hallo.py
git commit -m "hallo.py hinzugefuegt"
git switch main
git merge feature/halloSwitched to a new branch 'feature/hallo'
[feature/hallo 6b7f447] hallo.py hinzugefuegt
1 file changed, 1 insertion(+)
create mode 100644 hallo.py
Switched to branch 'main'
Updating 0dd594e..6b7f447
Fast-forward
hallo.py | 1 +
1 file changed, 1 insertion(+)
create mode 100644 hallo.pyWeil auf main seit dem Abzweigen nichts passiert ist, genügt ein Fast-Forward: Git setzt main einfach auf den neueren Commit. Danach kannst du den fertigen Branch aufräumen:
git branch
git branch -d feature/hallo feature/hallo
* main
Deleted branch feature/hallo (was 6b7f447).Der Stern markiert den aktuellen Branch. -d löscht nur, wenn der Branch bereits eingebunden ist; das schützt vor Verlust.
Merge-Konflikt entstehen sehen und lösen
Ein Konflikt entsteht, wenn zwei Branches dieselbe Stelle unterschiedlich ändern. Wir erzeugen ihn absichtlich: Branch a und Branch b legen beide eine Datei titel.txt mit unterschiedlichem Inhalt an.
git switch -c a
echo "Titel: A" > titel.txt && git add . && git commit -m "Titel A"
git switch main
git switch -c b
echo "Titel: B" > titel.txt && git add . && git commit -m "Titel B"
git switch a
git merge bAuto-merging titel.txt
CONFLICT (add/add): Merge conflict in titel.txt
Automatic merge failed; fix conflicts and then commit the result.git status --short zeigt AA titel.txt (beide Seiten haben die Datei hinzugefügt). In der Datei steht jetzt:
<<<<<<< HEAD
Titel: A
=======
Titel: B
>>>>>>> bZwischen <<<<<<< und ======= steht deine Version (HEAD), darunter die des einzubindenden Branches. Du bearbeitest die Datei so, dass genau der gewünschte Inhalt übrig bleibt, und entfernst alle Markierungen. Hier entscheiden wir uns für Titel: AB. Danach schließt du den Merge ab:
echo "Titel: AB" > titel.txt
git add titel.txt
git commit -m "Merge b, Konflikt geloest"
git log --oneline --graph --all* ac559bf Merge b, Konflikt geloest
|\
| * a3e2b2a Titel B
* | a23405d Titel A
|/
* 6b7f447 hallo.py hinzugefuegt
* 0dd594e README erweitert
* 374df69 Erster Commit: READMEDer Graph zeigt den Merge-Commit mit zwei Eltern. Möchtest du den Merge lieber abbrechen, geht das vor dem Commit mit git merge --abort.
Merge oder Rebase?
Beide Befehle bringen die Arbeit eines Branches in einen anderen, aber auf unterschiedliche Weise. Merge verbindet beide Historien mit einem Merge-Commit und lässt alle bestehenden Commits unverändert. Rebase nimmt die Commits deines Branches und spielt sie neu auf der Spitze des Zielbranches ab. Das Ergebnis ist eine lineare Historie, aber die Commits sind neu (andere Hashes).
Ein Beispiel: main hat seit dem Abzweigen von r1 einen weiteren Commit bekommen.
git switch r1
git rebase main
git log --oneline --graph -5Rebasing (1/1)
Successfully rebased and updated refs/heads/r1.
* d1fd453 r1
* 62609e6 m weiter
* 89048f3 x a
* 6b7f447 hallo.py hinzugefuegt
* 0dd594e README erweitertDer Commit r1 liegt jetzt direkt hinter m weiter, ohne Merge-Commit.
| Merge | Rebase | |
|---|---|---|
| Historie | bleibt erhalten, mit Merge-Commit | linear, Commits neu geschrieben |
| Bestehende Commits | unverändert | bekommen neue Hashes |
| Sicher auf geteilten Branches | ja | nein |
Wichtig: Rebase schreibt Commits neu. Wende es nicht auf Commits an, die du bereits an andere weitergegeben hast (gepusht und von Kolleginnen oder Kollegen geholt). Sonst divergieren die Historien, und alle Beteiligten müssen aufräumen. Auf lokalen, noch nicht geteilten Branches ist Rebase unproblematisch.
Stash: Arbeit zwischenlagern
Du hast Änderungen, die noch nicht commit-reif sind, musst aber kurz den Branch wechseln? git stash legt den Stand beiseite und stellt das Arbeitsverzeichnis wieder her:
echo "unfertig" >> README.md
git stash
git stash list
git stash popSaved working directory and index state WIP on main: 6b7f447 hallo.py hinzugefuegt
stash@{0}: WIP on main: 6b7f447 hallo.py hinzugefuegt
On branch main
Changes not staged for commit:
modified: README.md
Dropped refs/stash@{0} (4c458ba3f15c5d6cbdfd5d46ca6969a06632e67e)stash pop holt die Änderungen zurück und entfernt den Eintrag aus der Stash-Liste.
Änderungen verwerfen und Commits zurücksetzen
Zwei Befehle mit unterschiedlichen Wirkungen, die oft verwechselt werden:
git restore arbeitet auf Dateiebene. Mit --staged nimmst du eine Datei aus der Staging Area, ohne die Änderung zu verlieren. Ohne --staged wirft es die Änderung im Arbeitsverzeichnis weg, und zwar endgültig, weil sie nie committet wurde.
echo "a" > x.txt && git add x.txt && git commit -m "x a"
echo "b" > x.txt && git add x.txt
git restore --staged x.txt
git status --short
git restore x.txt M x.txtNach dem ersten restore steht die Änderung als unstaged ( M) im Arbeitsverzeichnis; nach dem zweiten ist sie weg.
git reset bewegt dagegen den aktuellen Branch auf einen anderen Commit. Die Git-Dokumentation unterscheidet drei Modi, die jeweils HEAD verschieben und sich darin unterscheiden, was sonst passiert:
| Modus | HEAD | Index (Staging Area) | Arbeitsverzeichnis |
|---|---|---|---|
--soft | verschoben | unverändert | unverändert |
--mixed (Standard) | verschoben | auf den Zielcommit zurückgesetzt | unverändert |
--hard | verschoben | zurückgesetzt | auf den Zielcommit zurückgesetzt |
Das lässt sich nachvollziehen. Ausgangspunkt ist ein Commit „x b“, der x.txt von a auf b ändert:
git reset --soft HEAD~1
git status --shortM x.txtDer Commit ist weg, die Änderung steht aber noch fertig vorgemerkt in der Staging Area (M links). Nach einem neuen Commit und git reset --mixed HEAD~1:
Unstaged changes after reset:
M x.txtJetzt ist die Änderung nicht mehr vorgemerkt ( M), aber noch im Arbeitsverzeichnis. Mit git reset --hard HEAD~1 verschwindet sie ganz:
git reset --hard HEAD~1
cat x.txtHEAD is now at 89048f3 x a
a--hard verwirft laut Dokumentation auch uncommittete Änderungen an getrackten Dateien. Verlierst du dabei einen Commit, hilft git reflog, der die letzten Positionen von HEAD auflistet und dir die Hashes verschwundener Commits zeigt, solange Git sie noch nicht aufgeräumt hat:
89048f3 HEAD@{0}: reset: moving to HEAD~1
9f380bb HEAD@{1}: commit: x b dritterDie Dokumentation warnt zudem davor, Commits zurückzusetzen, die du schon an andere weitergegeben hast.
Mit einem Remote arbeiten
Ein Remote ist ein Repository, mit dem du Commits austauschst. Zum Üben reicht ein lokales Bare-Repository; bei GitHub oder GitLab stünde an dieser Stelle die Adresse des Projekts.
git init -q --bare -b main remote.git
cd projekt
git remote add origin ../remote.git
git push -u origin mainTo ../remote.git
* [new branch] main -> main
branch 'main' set up to track 'origin/main'.-u verknüpft deinen lokalen main mit origin/main, sodass späteres git push und git pull ohne weitere Angaben funktionieren. Hat jemand anderes (hier: ein zweiter Klon) etwas gepusht, unterscheidest du zwei Wege:
git fetchlädt neue Commits aus dem Remote, ändert aber deinen Branch nicht.git pullholt und integriert in einem Schritt.
git fetch
git status -sb
git pullFrom ../remote
62609e6..8ce1d6f main -> origin/main
## main...origin/main [behind 1]
Updating 62609e6..8ce1d6f
Fast-forward
y.txt | 1 +
1 file changed, 1 insertion(+)
create mode 100644 y.txtDer Status [behind 1] sagt, dass dein Branch einen Commit hinter dem Remote liegt. Wer vor dem Integrieren sehen will, was kommt, nutzt erst fetch und danach git log oder git diff gegen origin/main.
Wie geht es weiter?
Dein konkreter nächster Schritt: Lege ein Wegwerf-Repository an und spiele den Konfliktfall aus diesem Artikel selbst durch, mit eigenen Dateinamen. Wenn du einmal einen Konflikt bewusst gelöst hast, verliert er viel von seinem Schrecken. Danach lohnt sich der Blick in das Buch Pro Git auf git-scm.com, das Branching, Remotes und Fehlerbehebung ausführlich behandelt.
Passende Übungsprojekte findest du im Python-Einstieg, dessen Skripte du von Anfang an in ein Repository legen kannst. Falls du noch überlegst, welche Sprache du als Nächstes angehst, hilft die Entscheidungshilfe zur ersten Programmiersprache. Weitere Themen im Ressort findest du unter Programmierung.
Häufige Fragen
Was ist der Unterschied zwischen Git und GitHub?
Git ist die Versionsverwaltung auf deinem Rechner. Plattformen wie GitHub oder GitLab hosten Remote-Repositorys und bieten zusätzliche Funktionen wie Pull Requests.
Wie mache ich einen Commit rückgängig, den ich schon gepusht habe?
Verwende git revert, das einen neuen Commit erzeugt, der die Änderung aufhebt. Historie auf einem geteilten Branch umzuschreiben (reset, rebase) betrifft alle, die ihn schon geholt haben.
Quellen
- Pro Git: What is Git? git-scm.com (Scott Chacon, Ben Straub) · abgerufen am 28. Oktober 2026
- git-reset Dokumentation git-scm.com · abgerufen am 28. Oktober 2026